Panda3D
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  */
26 get_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_ref_count
Returns the current reference count.
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:25
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CopyOnWriteObject * get_write_pointer()
Returns a pointer locked for write.
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A thread; that is, a lightweight process.
Definition: thread.h:46
const CopyOnWriteObject * get_read_pointer(Thread *current_thread) const
Returns a pointer locked for read.