Panda3D
Loading...
Searching...
No Matches
copyOnWritePointer.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file copyOnWritePointer.cxx
10 * @author drose
11 * @date 2007-04-09
12 */
13
14#include "copyOnWritePointer.h"
15#include "config_putil.h"
16#include "config_pipeline.h"
17
18#ifdef COW_THREADED
19/**
20 * Returns a pointer locked for read. Until this pointer dereferences, calls
21 * to get_write_pointer() will force a copy.
22 *
23 * This flavor of the method is written for the threaded case.
24 */
26get_read_pointer(Thread *current_thread) const {
27 if (_cow_object == nullptr) {
28 return nullptr;
29 }
30
31 MutexHolder holder(_cow_object->_lock_mutex);
32 while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write) {
33 if (_cow_object->_locking_thread == current_thread) {
34 return _cow_object;
35 }
36 if (util_cat.is_debug()) {
37 util_cat.debug()
38 << *current_thread << " waiting on " << _cow_object->get_type()
39 << " " << _cow_object << ", held by " << *_cow_object->_locking_thread
40 << "\n";
41 }
42 _cow_object->_lock_cvar.wait();
43 }
44
45 _cow_object->_lock_status = CopyOnWriteObject::LS_locked_read;
46 _cow_object->_locking_thread = current_thread;
47 return _cow_object;
48}
49#endif // COW_THREADED
50
51#ifdef COW_THREADED
52/**
53 * Returns a pointer locked for write. If another thread or threads already
54 * hold the pointer locked for read, then this will force a copy.
55 *
56 * Until this pointer dereferences, calls to get_read_pointer() or
57 * get_write_pointer() will block.
58 *
59 * This flavor of the method is written for the threaded case.
60 */
63 if (_cow_object == nullptr) {
64 return nullptr;
65 }
66
67 Thread *current_thread = Thread::get_current_thread();
68
69 _cow_object->_lock_mutex.lock();
70 while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write &&
71 _cow_object->_locking_thread != current_thread) {
72 if (util_cat.is_debug()) {
73 util_cat.debug()
74 << *current_thread << " waiting on " << _cow_object->get_type()
75 << " " << _cow_object << ", held by " << *_cow_object->_locking_thread
76 << "\n";
77 }
78 _cow_object->_lock_cvar.wait();
79 }
80
81 if (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_read) {
82 nassertr(_cow_object->get_ref_count() > _cow_object->get_cache_ref_count(), nullptr);
83
84 if (util_cat.is_debug()) {
85 util_cat.debug()
86 << "Making copy of " << _cow_object->get_type()
87 << " because it is locked in read mode.\n";
88 }
89
90 PT(CopyOnWriteObject) new_object = _cow_object->make_cow_copy();
91 _cow_object->CachedTypedWritableReferenceCount::cache_unref();
92 _cow_object->_lock_mutex.unlock();
93
94 MutexHolder holder(new_object->_lock_mutex);
95 _cow_object = new_object;
96 _cow_object->CachedTypedWritableReferenceCount::cache_ref();
97 _cow_object->_lock_status = CopyOnWriteObject::LS_locked_write;
98 _cow_object->_locking_thread = current_thread;
99
100 return new_object;
101
102 } else if (_cow_object->get_cache_ref_count() > 1) {
103 // No one else has it specifically read-locked, but there are other
104 // CopyOnWritePointers holding the same object, so we should make our own
105 // writable copy anyway.
106 if (util_cat.is_debug()) {
107 util_cat.debug()
108 << "Making copy of " << _cow_object->get_type()
109 << " because it is shared by " << _cow_object->get_ref_count()
110 << " pointers.\n";
111 }
112
113 PT(CopyOnWriteObject) new_object = _cow_object->make_cow_copy();
114 _cow_object->CachedTypedWritableReferenceCount::cache_unref();
115 _cow_object->_lock_mutex.unlock();
116
117 MutexHolder holder(new_object->_lock_mutex);
118 _cow_object = new_object;
119 _cow_object->CachedTypedWritableReferenceCount::cache_ref();
120 _cow_object->_lock_status = CopyOnWriteObject::LS_locked_write;
121 _cow_object->_locking_thread = current_thread;
122
123 return new_object;
124
125 } else {
126 // No other thread has the pointer locked, and we're the only
127 // CopyOnWritePointer with this object. We can safely write to it without
128 // making a copy.
129
130 // We can't assert that there are no outstanding ordinary references to
131 // it, though, since the creator of the object might have saved himself a
132 // reference.
133 _cow_object->_lock_status = CopyOnWriteObject::LS_locked_write;
134 _cow_object->_locking_thread = current_thread;
135 _cow_object->_lock_mutex.unlock();
136 }
137
138 return _cow_object;
139}
140#endif // COW_THREADED
get_cache_ref_count
Returns the current reference count.
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
const CopyOnWriteObject * get_read_pointer(Thread *current_thread) const
Returns a pointer locked for read.
CopyOnWriteObject * get_write_pointer()
Returns a pointer locked for write.
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition mutexHolder.h:25
get_ref_count
Returns the current reference count.
A thread; that is, a lightweight process.
Definition thread.h:46
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition thread.h:109
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.