Panda3D
 All Classes Functions Variables Enumerations
conditionVarDebug.cxx
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
 All Classes Functions Variables Enumerations