Panda3D
Loading...
Searching...
No Matches
conditionVarFullDebug.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 conditionVarFullDebug.cxx
10 * @author drose
11 * @date 2006-08-28
12 */
13
15#include "thread.h"
16#include "config_pipeline.h"
17
18#ifdef DEBUG_THREADS
19
20using std::ostream;
21using std::ostringstream;
22
23/**
24 * You must pass in a Mutex to the condition variable constructor. This mutex
25 * may be shared by other condition variables, if desired. It is the caller's
26 * responsibility to ensure the Mutex object does not destruct during the
27 * lifetime of the condition variable.
28 */
29ConditionVarFullDebug::
30ConditionVarFullDebug(MutexDebug &mutex) :
31 _mutex(mutex),
32 _impl(*mutex.get_global_lock())
33{
34 nassertv(!_mutex._allow_recursion);
35}
36
37/**
38 *
39 */
40ConditionVarFullDebug::
41~ConditionVarFullDebug() {
42}
43
44/**
45 * Waits on the condition. The caller must already be holding the lock
46 * associated with the condition variable before calling this function.
47 *
48 * wait() will release the lock, then go to sleep until some other thread
49 * calls notify() on this condition variable. At that time at least one
50 * thread waiting on the same ConditionVarFullDebug will grab the lock again,
51 * and then return from wait().
52 *
53 * It is possible that wait() will return even if no one has called notify().
54 * It is the responsibility of the calling process to verify the condition on
55 * return from wait, and possibly loop back to wait again if necessary.
56 *
57 * Note the semantics of a condition variable: the mutex must be held before
58 * wait() is called, and it will still be held when wait() returns. However,
59 * it will be temporarily released during the wait() call itself.
60 */
61void ConditionVarFullDebug::
62wait() {
63 _mutex._global_lock->lock();
64
65 Thread *current_thread = Thread::get_current_thread();
66
67 if (!_mutex.do_debug_is_locked()) {
68 ostringstream ostr;
69 ostr << *current_thread << " attempted to wait on "
70 << *this << " without holding " << _mutex;
71 nassert_raise(ostr.str());
72 _mutex._global_lock->unlock();
73 return;
74 }
75
76 if (thread_cat->is_spam()) {
77 thread_cat.spam()
78 << *current_thread << " waiting on " << *this << "\n";
79 }
80
81 nassertd(current_thread->_waiting_on_cvar == nullptr &&
82 current_thread->_waiting_on_cvar_full == nullptr) {
83 }
84 current_thread->_waiting_on_cvar_full = this;
85
86 _mutex.do_unlock();
87 _impl.wait(); // temporarily releases _global_lock
88 _mutex.do_lock(current_thread);
89
90 nassertd(current_thread->_waiting_on_cvar_full == this) {
91 }
92 current_thread->_waiting_on_cvar_full = nullptr;
93
94 if (thread_cat.is_spam()) {
95 thread_cat.spam()
96 << *current_thread << " awake on " << *this << "\n";
97 }
98
99 _mutex._global_lock->unlock();
100}
101
102/**
103 * Waits on the condition, with a timeout. The function will return when the
104 * condition variable is notified, or the timeout occurs. There is no way to
105 * directly tell which happened, and it is possible that neither in fact
106 * happened (spurious wakeups are possible).
107 *
108 * See wait() with no parameters for more.
109 */
110void ConditionVarFullDebug::
111wait(double timeout) {
112 _mutex._global_lock->lock();
113
114 Thread *current_thread = Thread::get_current_thread();
115
116 if (!_mutex.do_debug_is_locked()) {
117 ostringstream ostr;
118 ostr << *current_thread << " attempted to wait on "
119 << *this << " without holding " << _mutex;
120 nassert_raise(ostr.str());
121 _mutex._global_lock->unlock();
122 return;
123 }
124
125 if (thread_cat.is_spam()) {
126 thread_cat.spam()
127 << *current_thread << " waiting on " << *this
128 << ", with timeout " << timeout << "\n";
129 }
130
131 nassertd(current_thread->_waiting_on_cvar == nullptr &&
132 current_thread->_waiting_on_cvar_full == nullptr) {
133 }
134 current_thread->_waiting_on_cvar_full = this;
135
136 _mutex.do_unlock();
137 _impl.wait(timeout); // temporarily releases _global_lock
138 _mutex.do_lock(current_thread);
139
140 nassertd(current_thread->_waiting_on_cvar_full == this) {
141 }
142 current_thread->_waiting_on_cvar_full = nullptr;
143
144 if (thread_cat.is_spam()) {
145 thread_cat.spam()
146 << *current_thread << " awake on " << *this << "\n";
147 }
148
149 _mutex._global_lock->unlock();
150}
151
152/**
153 * Informs one of the other threads who are currently blocked on wait() that
154 * the relevant condition has changed. If multiple threads are currently
155 * waiting, at least one of them will be woken up, although there is no way to
156 * predict which one. It is possible that more than one thread will be woken
157 * up.
158 *
159 * The caller must be holding the mutex associated with the condition variable
160 * before making this call, which will not release the mutex.
161 *
162 * If no threads are waiting, this is a no-op: the notify event is lost.
163 */
164void ConditionVarFullDebug::
165notify() {
166 _mutex._global_lock->lock();
167
168 Thread *current_thread = Thread::get_current_thread();
169
170 if (!_mutex.do_debug_is_locked()) {
171 ostringstream ostr;
172 ostr << *current_thread << " attempted to notify "
173 << *this << " without holding " << _mutex;
174 nassert_raise(ostr.str());
175 _mutex._global_lock->unlock();
176 return;
177 }
178
179 if (thread_cat->is_spam()) {
180 thread_cat.spam()
181 << *current_thread << " notifying " << *this << "\n";
182 }
183
184 _impl.notify();
185 _mutex._global_lock->unlock();
186}
187
188/**
189 * Informs all of the other threads who are currently blocked on wait() that
190 * the relevant condition has changed.
191 *
192 * The caller must be holding the mutex associated with the condition variable
193 * before making this call, which will not release the mutex.
194 *
195 * If no threads are waiting, this is a no-op: the notify event is lost.
196 */
197void ConditionVarFullDebug::
198notify_all() {
199 _mutex._global_lock->lock();
200
201 Thread *current_thread = Thread::get_current_thread();
202
203 if (!_mutex.do_debug_is_locked()) {
204 ostringstream ostr;
205 ostr << *current_thread << " attempted to notify "
206 << *this << " without holding " << _mutex;
207 nassert_raise(ostr.str());
208 _mutex._global_lock->unlock();
209 return;
210 }
211
212 if (thread_cat->is_spam()) {
213 thread_cat.spam()
214 << *current_thread << " notifying all " << *this << "\n";
215 }
216
217 _impl.notify_all();
218 _mutex._global_lock->unlock();
219}
220
221/**
222 * This method is declared virtual in ConditionVarFullDebug, but non-virtual
223 * in ConditionVarFullDirect.
224 */
225void ConditionVarFullDebug::
226output(ostream &out) const {
227 out << "ConditionVarFull " << (void *)this << " on " << _mutex;
228}
229
230#endif // DEBUG_THREADS
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.