Panda3D
|
00001 // Filename: conditionVarDebug.cxx 00002 // Created by: drose (13Feb06) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "conditionVarDebug.h" 00016 #include "thread.h" 00017 #include "config_pipeline.h" 00018 00019 #ifdef DEBUG_THREADS 00020 00021 //////////////////////////////////////////////////////////////////// 00022 // Function: ConditionVarDebug::Constructor 00023 // Access: Public 00024 // Description: You must pass in a Mutex to the condition variable 00025 // constructor. This mutex may be shared by other 00026 // condition variables, if desired. It is the caller's 00027 // responsibility to ensure the Mutex object does not 00028 // destruct during the lifetime of the condition 00029 // variable. 00030 //////////////////////////////////////////////////////////////////// 00031 ConditionVarDebug:: 00032 ConditionVarDebug(MutexDebug &mutex) : 00033 _mutex(mutex), 00034 _impl(*mutex.get_global_lock()) 00035 { 00036 nassertv(!_mutex._allow_recursion); 00037 } 00038 00039 //////////////////////////////////////////////////////////////////// 00040 // Function: ConditionVarDebug::Destructor 00041 // Access: Public, Virtual 00042 // Description: 00043 //////////////////////////////////////////////////////////////////// 00044 ConditionVarDebug:: 00045 ~ConditionVarDebug() { 00046 } 00047 00048 //////////////////////////////////////////////////////////////////// 00049 // Function: ConditionVarDebug::wait 00050 // Access: Published 00051 // Description: Waits on the condition. The caller must already be 00052 // holding the lock associated with the condition 00053 // variable before calling this function. 00054 // 00055 // wait() will release the lock, then go to sleep until 00056 // some other thread calls notify() on this condition 00057 // variable. At that time at least one thread waiting 00058 // on the same ConditionVarDebug will grab the lock again, 00059 // and then return from wait(). 00060 // 00061 // It is possible that wait() will return even if no one 00062 // has called notify(). It is the responsibility of the 00063 // calling process to verify the condition on return 00064 // from wait, and possibly loop back to wait again if 00065 // necessary. 00066 // 00067 // Note the semantics of a condition variable: the mutex 00068 // must be held before wait() is called, and it will 00069 // still be held when wait() returns. However, it will 00070 // be temporarily released during the wait() call 00071 // itself. 00072 //////////////////////////////////////////////////////////////////// 00073 void ConditionVarDebug:: 00074 wait() { 00075 _mutex._global_lock->acquire(); 00076 00077 Thread *current_thread = Thread::get_current_thread(); 00078 00079 if (!_mutex.do_debug_is_locked()) { 00080 ostringstream ostr; 00081 ostr << *current_thread << " attempted to wait on " 00082 << *this << " without holding " << _mutex; 00083 nassert_raise(ostr.str()); 00084 _mutex._global_lock->release(); 00085 return; 00086 } 00087 00088 if (thread_cat->is_spam()) { 00089 thread_cat.spam() 00090 << *current_thread << " waiting on " << *this << "\n"; 00091 } 00092 00093 nassertd(current_thread->_waiting_on_cvar == NULL && 00094 current_thread->_waiting_on_cvar_full == NULL) { 00095 } 00096 current_thread->_waiting_on_cvar = this; 00097 00098 _mutex.do_release(); 00099 _impl.wait(); // temporarily releases _global_lock 00100 _mutex.do_acquire(current_thread); 00101 00102 nassertd(current_thread->_waiting_on_cvar == this) { 00103 } 00104 current_thread->_waiting_on_cvar = NULL; 00105 00106 if (thread_cat.is_spam()) { 00107 thread_cat.spam() 00108 << *current_thread << " awake on " << *this << "\n"; 00109 } 00110 00111 _mutex._global_lock->release(); 00112 } 00113 00114 //////////////////////////////////////////////////////////////////// 00115 // Function: ConditionVarDebug::wait 00116 // Access: Published 00117 // Description: Waits on the condition, with a timeout. The function 00118 // will return when the condition variable is notified, 00119 // or the timeout occurs. There is no way to directly 00120 // tell which happened, and it is possible that neither 00121 // in fact happened (spurious wakeups are possible). 00122 // 00123 // See wait() with no parameters for more. 00124 //////////////////////////////////////////////////////////////////// 00125 void ConditionVarDebug:: 00126 wait(double timeout) { 00127 _mutex._global_lock->acquire(); 00128 00129 Thread *current_thread = Thread::get_current_thread(); 00130 00131 if (!_mutex.do_debug_is_locked()) { 00132 ostringstream ostr; 00133 ostr << *current_thread << " attempted to wait on " 00134 << *this << " without holding " << _mutex; 00135 nassert_raise(ostr.str()); 00136 _mutex._global_lock->release(); 00137 return; 00138 } 00139 00140 if (thread_cat.is_spam()) { 00141 thread_cat.spam() 00142 << *current_thread << " waiting on " << *this 00143 << ", with timeout " << timeout << "\n"; 00144 } 00145 00146 nassertd(current_thread->_waiting_on_cvar == NULL && 00147 current_thread->_waiting_on_cvar_full == NULL) { 00148 } 00149 current_thread->_waiting_on_cvar = this; 00150 00151 _mutex.do_release(); 00152 _impl.wait(timeout); // temporarily releases _global_lock 00153 _mutex.do_acquire(current_thread); 00154 00155 nassertd(current_thread->_waiting_on_cvar == this) { 00156 } 00157 current_thread->_waiting_on_cvar = NULL; 00158 00159 if (thread_cat.is_spam()) { 00160 thread_cat.spam() 00161 << *current_thread << " awake on " << *this << "\n"; 00162 } 00163 00164 _mutex._global_lock->release(); 00165 } 00166 00167 //////////////////////////////////////////////////////////////////// 00168 // Function: ConditionVarDebug::notify 00169 // Access: Published 00170 // Description: Informs one of the other threads who are currently 00171 // blocked on wait() that the relevant condition has 00172 // changed. If multiple threads are currently waiting, 00173 // at least one of them will be woken up, although there 00174 // is no way to predict which one. It is possible that 00175 // more than one thread will be woken up. 00176 // 00177 // The caller must be holding the mutex associated with 00178 // the condition variable before making this call, which 00179 // will not release the mutex. 00180 // 00181 // If no threads are waiting, this is a no-op: the 00182 // notify event is lost. 00183 //////////////////////////////////////////////////////////////////// 00184 void ConditionVarDebug:: 00185 notify() { 00186 _mutex._global_lock->acquire(); 00187 00188 Thread *current_thread = Thread::get_current_thread(); 00189 00190 if (!_mutex.do_debug_is_locked()) { 00191 ostringstream ostr; 00192 ostr << *current_thread << " attempted to notify " 00193 << *this << " without holding " << _mutex; 00194 nassert_raise(ostr.str()); 00195 _mutex._global_lock->release(); 00196 return; 00197 } 00198 00199 if (thread_cat->is_spam()) { 00200 thread_cat.spam() 00201 << *current_thread << " notifying " << *this << "\n"; 00202 } 00203 00204 _impl.notify(); 00205 _mutex._global_lock->release(); 00206 } 00207 00208 //////////////////////////////////////////////////////////////////// 00209 // Function: ConditionVarDebug::output 00210 // Access: Published, Virtual 00211 // Description: This method is declared virtual in ConditionVarDebug, 00212 // but non-virtual in ConditionVarDirect. 00213 //////////////////////////////////////////////////////////////////// 00214 void ConditionVarDebug:: 00215 output(ostream &out) const { 00216 out << "ConditionVar " << (void *)this << " on " << _mutex; 00217 } 00218 00219 #endif // DEBUG_THREADS