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