Panda3D
 All Classes Functions Variables Enumerations
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 "mutexHolder.h"
17 #include "config_util.h"
18 #include "config_pipeline.h"
19 
20 #ifdef COW_THREADED
21 ////////////////////////////////////////////////////////////////////
22 // Function: CopyOnWritePointer::get_read_pointer
23 // Access: Public
24 // Description: Returns a pointer locked for read. Until this
25 // pointer dereferences, calls to get_write_pointer()
26 // will force a copy.
27 //
28 // This flavor of the method is written for the threaded
29 // case.
30 ////////////////////////////////////////////////////////////////////
32 get_read_pointer() const {
33  if (_cow_object == (CopyOnWriteObject *)NULL) {
34  return NULL;
35  }
36 
37  Thread *current_thread = Thread::get_current_thread();
38 
39  MutexHolder holder(_cow_object->_lock_mutex);
40  while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write) {
41  if (_cow_object->_locking_thread == current_thread) {
42  return _cow_object;
43  }
44  if (util_cat.is_debug()) {
45  util_cat.debug()
46  << *current_thread << " waiting on " << _cow_object->get_type()
47  << " " << _cow_object << ", held by " << *_cow_object->_locking_thread
48  << "\n";
49  }
50  _cow_object->_lock_cvar.wait();
51  }
52 
53  _cow_object->_lock_status = CopyOnWriteObject::LS_locked_read;
54  _cow_object->_locking_thread = current_thread;
55  return _cow_object;
56 }
57 #endif // COW_THREADED
58 
59 #ifdef COW_THREADED
60 ////////////////////////////////////////////////////////////////////
61 // Function: CopyOnWritePointer::get_write_pointer
62 // Access: Public
63 // Description: Returns a pointer locked for write. If another
64 // thread or threads already hold the pointer locked for
65 // read, then this will force a copy.
66 //
67 // Until this pointer dereferences, calls to
68 // get_read_pointer() or get_write_pointer() will block.
69 //
70 // This flavor of the method is written for the threaded
71 // case.
72 ////////////////////////////////////////////////////////////////////
74 get_write_pointer() {
75  if (_cow_object == (CopyOnWriteObject *)NULL) {
76  return NULL;
77  }
78 
79  Thread *current_thread = Thread::get_current_thread();
80 
81  MutexHolder holder(_cow_object->_lock_mutex);
82  while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write &&
83  _cow_object->_locking_thread != current_thread) {
84  if (util_cat.is_debug()) {
85  util_cat.debug()
86  << *current_thread << " waiting on " << _cow_object->get_type()
87  << " " << _cow_object << ", held by " << *_cow_object->_locking_thread
88  << "\n";
89  }
90  _cow_object->_lock_cvar.wait();
91  }
92 
93  if (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_read) {
94  nassertr(_cow_object->get_ref_count() > _cow_object->get_cache_ref_count(), NULL);
95 
96  if (util_cat.is_debug()) {
97  util_cat.debug()
98  << "Making copy of " << _cow_object->get_type()
99  << " because it is locked in read mode.\n";
100  }
101  PT(CopyOnWriteObject) new_object = _cow_object->make_cow_copy();
102  cache_unref_delete(_cow_object);
103  _cow_object = new_object;
104  _cow_object->cache_ref();
105 
106  } else if (_cow_object->get_cache_ref_count() > 1) {
107  // No one else has it specifically read-locked, but there are
108  // other CopyOnWritePointers holding the same object, so we should
109  // make our own writable copy anyway.
110  if (util_cat.is_debug()) {
111  util_cat.debug()
112  << "Making copy of " << _cow_object->get_type()
113  << " because it is shared by " << _cow_object->get_ref_count()
114  << " pointers.\n";
115  }
116 
117  PT(CopyOnWriteObject) new_object = _cow_object->make_cow_copy();
118  cache_unref_delete(_cow_object);
119  _cow_object = new_object;
120  _cow_object->cache_ref();
121 
122  } else {
123  // No other thread has the pointer locked, and we're the only
124  // CopyOnWritePointer with this object. We can safely write to it
125  // without making a copy.
126 
127  // We can't assert that there are no outstanding ordinary
128  // references to it, though, since the creator of the object might
129  // have saved himself a reference.
130  }
131  _cow_object->_lock_status = CopyOnWriteObject::LS_locked_write;
132  _cow_object->_locking_thread = current_thread;
133 
134  return _cow_object;
135 }
136 #endif // COW_THREADED
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:29
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
This safely stores the primary, owned pointer to a CopyOnWriteObject.
A thread; that is, a lightweight process.
Definition: thread.h:51