From fb5191e812ff157fa7a033c233c2f9322f37ad6b Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 11 Feb 2019 15:29:35 +0100 Subject: [PATCH] pipeline: unify ConditionVarFull and ConditionVar See #550. Now that we use the Vista API for condition variables, the only place where the distinction is still relevant is Windows XP, and it's just not worth it for that one corner case. --- dtool/src/dtoolbase/mutexWin32Impl.h | 1 - panda/src/event/asyncFuture.h | 1 - panda/src/pipeline/conditionVar.h | 10 +- panda/src/pipeline/conditionVarDebug.cxx | 41 ++- panda/src/pipeline/conditionVarDebug.h | 1 + panda/src/pipeline/conditionVarDirect.I | 15 +- panda/src/pipeline/conditionVarDirect.h | 1 + panda/src/pipeline/conditionVarFull.I | 40 --- panda/src/pipeline/conditionVarFull.cxx | 14 -- panda/src/pipeline/conditionVarFull.h | 42 +--- panda/src/pipeline/conditionVarFullDebug.I | 20 -- panda/src/pipeline/conditionVarFullDebug.cxx | 234 ------------------ panda/src/pipeline/conditionVarFullDebug.h | 64 ----- panda/src/pipeline/conditionVarFullDirect.I | 103 -------- panda/src/pipeline/conditionVarFullDirect.cxx | 27 -- panda/src/pipeline/conditionVarFullDirect.h | 64 ----- .../src/pipeline/conditionVarFullWin32Impl.I | 66 ----- .../pipeline/conditionVarFullWin32Impl.cxx | 20 -- .../src/pipeline/conditionVarFullWin32Impl.h | 65 ----- panda/src/pipeline/conditionVarImpl.h | 8 +- panda/src/pipeline/conditionVarWin32Impl.I | 35 +-- panda/src/pipeline/conditionVarWin32Impl.h | 26 +- panda/src/pipeline/mutexDebug.h | 1 - panda/src/pipeline/mutexDirect.h | 1 - panda/src/pipeline/p3pipeline_composite1.cxx | 3 - panda/src/pipeline/thread.cxx | 7 +- panda/src/pipeline/thread.h | 3 - 27 files changed, 91 insertions(+), 822 deletions(-) delete mode 100644 panda/src/pipeline/conditionVarFull.I delete mode 100644 panda/src/pipeline/conditionVarFull.cxx delete mode 100644 panda/src/pipeline/conditionVarFullDebug.I delete mode 100644 panda/src/pipeline/conditionVarFullDebug.cxx delete mode 100644 panda/src/pipeline/conditionVarFullDebug.h delete mode 100644 panda/src/pipeline/conditionVarFullDirect.I delete mode 100644 panda/src/pipeline/conditionVarFullDirect.cxx delete mode 100644 panda/src/pipeline/conditionVarFullDirect.h delete mode 100644 panda/src/pipeline/conditionVarFullWin32Impl.I delete mode 100644 panda/src/pipeline/conditionVarFullWin32Impl.cxx delete mode 100644 panda/src/pipeline/conditionVarFullWin32Impl.h diff --git a/dtool/src/dtoolbase/mutexWin32Impl.h b/dtool/src/dtoolbase/mutexWin32Impl.h index 9b34973b1d..47f31a2e8f 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.h +++ b/dtool/src/dtoolbase/mutexWin32Impl.h @@ -74,7 +74,6 @@ private: volatile PVOID _lock[2] = {nullptr, nullptr}; friend class ConditionVarWin32Impl; - friend class ConditionVarFullWin32Impl; }; /** diff --git a/panda/src/event/asyncFuture.h b/panda/src/event/asyncFuture.h index c12bccb7d0..27fa1db29c 100644 --- a/panda/src/event/asyncFuture.h +++ b/panda/src/event/asyncFuture.h @@ -22,7 +22,6 @@ class AsyncTaskManager; class AsyncTask; -class ConditionVarFull; /** * This class represents a thread-safe handle to a promised future result of diff --git a/panda/src/pipeline/conditionVar.h b/panda/src/pipeline/conditionVar.h index fe90e22063..47ad3c973d 100644 --- a/panda/src/pipeline/conditionVar.h +++ b/panda/src/pipeline/conditionVar.h @@ -24,11 +24,6 @@ * condition variable can be used to "wake up" a thread when some arbitrary * condition has changed. * - * The ConditionVar class does not support the full semantics of POSIX - * condition variables. In particular, it does not support the broadcast or - * notify_all function. See ConditionVarFull for a more complete (but - * possibly more expensive) API. - * * A condition variable is associated with a single mutex, and several * condition variables may share the same mutex. * @@ -51,10 +46,7 @@ PUBLISHED: // These methods are inherited from the base class. //INLINE void wait(); //INLINE void notify(); - - // The notify_all() method is specifically *not* provided by ConditionVar. - // Use ConditionVarFull if you need to call this method. - void notify_all() = delete; + //INLINE void notify_all(); INLINE Mutex &get_mutex() const; }; diff --git a/panda/src/pipeline/conditionVarDebug.cxx b/panda/src/pipeline/conditionVarDebug.cxx index 30a12695ad..c38bdc6d52 100644 --- a/panda/src/pipeline/conditionVarDebug.cxx +++ b/panda/src/pipeline/conditionVarDebug.cxx @@ -78,8 +78,7 @@ wait() { << *current_thread << " waiting on " << *this << "\n"; } - nassertd(current_thread->_waiting_on_cvar == nullptr && - current_thread->_waiting_on_cvar_full == nullptr) { + nassertd(current_thread->_waiting_on_cvar == nullptr) { } current_thread->_waiting_on_cvar = this; @@ -128,8 +127,7 @@ wait(double timeout) { << ", with timeout " << timeout << "\n"; } - nassertd(current_thread->_waiting_on_cvar == nullptr && - current_thread->_waiting_on_cvar_full == nullptr) { + nassertd(current_thread->_waiting_on_cvar == nullptr) { } current_thread->_waiting_on_cvar = this; @@ -156,9 +154,6 @@ wait(double timeout) { * predict which one. It is possible that more than one thread will be woken * up. * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * * If no threads are waiting, this is a no-op: the notify event is lost. */ void ConditionVarDebug:: @@ -187,6 +182,38 @@ notify() { _mutex._global_lock->unlock(); } +/** + * Informs all of the other threads who are currently blocked on wait() that + * the relevant condition has changed. + * + * If no threads are waiting, this is a no-op: the notify event is lost. + */ +void ConditionVarDebug:: +notify_all() { + _mutex._global_lock->lock(); + + /* + if (!_mutex.do_debug_is_locked()) { + Thread *current_thread = Thread::get_current_thread(); + ostringstream ostr; + ostr << *current_thread << " attempted to notify " + << *this << " without holding " << _mutex; + nassert_raise(ostr.str()); + _mutex._global_lock->unlock(); + return; + } + */ + + if (thread_cat->is_spam()) { + Thread *current_thread = Thread::get_current_thread(); + thread_cat.spam() + << *current_thread << " notifying all " << *this << "\n"; + } + + _impl.notify_all(); + _mutex._global_lock->unlock(); +} + /** * This method is declared virtual in ConditionVarDebug, but non-virtual in * ConditionVarDirect. diff --git a/panda/src/pipeline/conditionVarDebug.h b/panda/src/pipeline/conditionVarDebug.h index 85da3fde2e..d7aa8e7ecb 100644 --- a/panda/src/pipeline/conditionVarDebug.h +++ b/panda/src/pipeline/conditionVarDebug.h @@ -43,6 +43,7 @@ PUBLISHED: BLOCKING void wait(); BLOCKING void wait(double timeout); void notify(); + void notify_all(); virtual void output(std::ostream &out) const; private: diff --git a/panda/src/pipeline/conditionVarDirect.I b/panda/src/pipeline/conditionVarDirect.I index bf8e42aea5..3a5074fd65 100644 --- a/panda/src/pipeline/conditionVarDirect.I +++ b/panda/src/pipeline/conditionVarDirect.I @@ -76,9 +76,6 @@ wait(double timeout) { * predict which one. It is possible that more than one thread will be woken * up. * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * * If no threads are waiting, this is a no-op: the notify event is lost. */ INLINE void ConditionVarDirect:: @@ -86,3 +83,15 @@ notify() { TAU_PROFILE("ConditionVarDirect::notify()", " ", TAU_USER); _impl.notify(); } + +/** + * Informs all of the other threads who are currently blocked on wait() that + * the relevant condition has changed. + * + * If no threads are waiting, this is a no-op: the notify event is lost. + */ +INLINE void ConditionVarDirect:: +notify_all() { + TAU_PROFILE("ConditionVarDirect::notify()", " ", TAU_USER); + _impl.notify_all(); +} diff --git a/panda/src/pipeline/conditionVarDirect.h b/panda/src/pipeline/conditionVarDirect.h index 2a8c9197cb..17ecca68d9 100644 --- a/panda/src/pipeline/conditionVarDirect.h +++ b/panda/src/pipeline/conditionVarDirect.h @@ -43,6 +43,7 @@ PUBLISHED: BLOCKING INLINE void wait(); BLOCKING INLINE void wait(double timeout); INLINE void notify(); + INLINE void notify_all(); void output(std::ostream &out) const; private: diff --git a/panda/src/pipeline/conditionVarFull.I b/panda/src/pipeline/conditionVarFull.I deleted file mode 100644 index b796e7aed2..0000000000 --- a/panda/src/pipeline/conditionVarFull.I +++ /dev/null @@ -1,40 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFull.I - * @author drose - * @date 2006-08-28 - */ - -/** - * You must pass in a Mutex to the condition variable constructor. This mutex - * may be shared by other condition variables, if desired. It is the caller's - * responsibility to ensure the Mutex object does not destruct during the - * lifetime of the condition variable. - */ -INLINE ConditionVarFull:: -ConditionVarFull(Mutex &mutex) : -#ifdef DEBUG_THREADS - ConditionVarFullDebug(mutex) -#else - ConditionVarFullDirect(mutex) -#endif // DEBUG_THREADS -{ -} - -/** - * Returns the mutex associated with this condition variable. - */ -INLINE Mutex &ConditionVarFull:: -get_mutex() const { -#ifdef DEBUG_THREADS - return (Mutex &)ConditionVarFullDebug::get_mutex(); -#else - return (Mutex &)ConditionVarFullDirect::get_mutex(); -#endif // DEBUG_THREADS -} diff --git a/panda/src/pipeline/conditionVarFull.cxx b/panda/src/pipeline/conditionVarFull.cxx deleted file mode 100644 index b5a32d477c..0000000000 --- a/panda/src/pipeline/conditionVarFull.cxx +++ /dev/null @@ -1,14 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFull.cxx - * @author drose - * @date 2006-08-28 - */ - -#include "conditionVarFull.h" diff --git a/panda/src/pipeline/conditionVarFull.h b/panda/src/pipeline/conditionVarFull.h index 37a9af1e11..f7effac224 100644 --- a/panda/src/pipeline/conditionVarFull.h +++ b/panda/src/pipeline/conditionVarFull.h @@ -14,46 +14,8 @@ #ifndef CONDITIONVARFULL_H #define CONDITIONVARFULL_H -#include "pandabase.h" -#include "conditionVarFullDebug.h" -#include "conditionVarFullDirect.h" +#include "conditionVar.h" -/** - * This class implements a condition variable; see ConditionVar for a brief - * introduction to this class. The ConditionVarFull class provides a more - * complete implementation than ConditionVar; in particular, it provides the - * notify_all() method, which is guaranteed to wake up all threads currently - * waiting on the condition (whereas notify() is guaranteed to wake up at - * least one thread, but may or may not wake up all of them). - * - * This class exists because on certain platforms (e.g. Win32), implementing - * notify_all() requires more overhead, so you should use ConditionVar for - * cases when you do not require the notify_all() semantics. - * - * There are still some minor semantics that POSIX condition variables provide - * which this implementation does not. For instance, it is required (not - * optional) that the caller of notify() or notify_all() is holding the - * condition variable's mutex before the call. - * - * This class inherits its implementation either from ConditionVarFullDebug or - * ConditionVarFullDirect, depending on the definition of DEBUG_THREADS. - */ -#ifdef DEBUG_THREADS -class EXPCL_PANDA_PIPELINE ConditionVarFull : public ConditionVarFullDebug -#else -class EXPCL_PANDA_PIPELINE ConditionVarFull : public ConditionVarFullDirect -#endif // DEBUG_THREADS -{ -PUBLISHED: - INLINE explicit ConditionVarFull(Mutex &mutex); - ConditionVarFull(const ConditionVarFull ©) = delete; - ~ConditionVarFull() = default; - - ConditionVarFull &operator = (const ConditionVarFull ©) = delete; - - INLINE Mutex &get_mutex() const; -}; - -#include "conditionVarFull.I" +typedef ConditionVar ConditionVarFull; #endif diff --git a/panda/src/pipeline/conditionVarFullDebug.I b/panda/src/pipeline/conditionVarFullDebug.I deleted file mode 100644 index 5a09f03a3d..0000000000 --- a/panda/src/pipeline/conditionVarFullDebug.I +++ /dev/null @@ -1,20 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDebug.I - * @author drose - * @date 2006-08-28 - */ - -/** - * Returns the mutex associated with this condition variable. - */ -INLINE MutexDebug &ConditionVarFullDebug:: -get_mutex() const { - return _mutex; -} diff --git a/panda/src/pipeline/conditionVarFullDebug.cxx b/panda/src/pipeline/conditionVarFullDebug.cxx deleted file mode 100644 index 6b8b7feaa7..0000000000 --- a/panda/src/pipeline/conditionVarFullDebug.cxx +++ /dev/null @@ -1,234 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDebug.cxx - * @author drose - * @date 2006-08-28 - */ - -#include "conditionVarFullDebug.h" -#include "thread.h" -#include "config_pipeline.h" - -#ifdef DEBUG_THREADS - -using std::ostream; -using std::ostringstream; - -/** - * You must pass in a Mutex to the condition variable constructor. This mutex - * may be shared by other condition variables, if desired. It is the caller's - * responsibility to ensure the Mutex object does not destruct during the - * lifetime of the condition variable. - */ -ConditionVarFullDebug:: -ConditionVarFullDebug(MutexDebug &mutex) : - _mutex(mutex), - _impl(*mutex.get_global_lock()) -{ - nassertv(!_mutex._allow_recursion); -} - -/** - * - */ -ConditionVarFullDebug:: -~ConditionVarFullDebug() { -} - -/** - * Waits on the condition. The caller must already be holding the lock - * associated with the condition variable before calling this function. - * - * wait() will release the lock, then go to sleep until some other thread - * calls notify() on this condition variable. At that time at least one - * thread waiting on the same ConditionVarFullDebug will grab the lock again, - * and then return from wait(). - * - * It is possible that wait() will return even if no one has called notify(). - * It is the responsibility of the calling process to verify the condition on - * return from wait, and possibly loop back to wait again if necessary. - * - * Note the semantics of a condition variable: the mutex must be held before - * wait() is called, and it will still be held when wait() returns. However, - * it will be temporarily released during the wait() call itself. - */ -void ConditionVarFullDebug:: -wait() { - _mutex._global_lock->lock(); - - Thread *current_thread = Thread::get_current_thread(); - - if (!_mutex.do_debug_is_locked()) { - ostringstream ostr; - ostr << *current_thread << " attempted to wait on " - << *this << " without holding " << _mutex; - nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); - return; - } - - if (thread_cat->is_spam()) { - thread_cat.spam() - << *current_thread << " waiting on " << *this << "\n"; - } - - nassertd(current_thread->_waiting_on_cvar == nullptr && - current_thread->_waiting_on_cvar_full == nullptr) { - } - current_thread->_waiting_on_cvar_full = this; - - _mutex.do_unlock(); - _impl.wait(); // temporarily releases _global_lock - _mutex.do_lock(current_thread); - - nassertd(current_thread->_waiting_on_cvar_full == this) { - } - current_thread->_waiting_on_cvar_full = nullptr; - - if (thread_cat.is_spam()) { - thread_cat.spam() - << *current_thread << " awake on " << *this << "\n"; - } - - _mutex._global_lock->unlock(); -} - -/** - * Waits on the condition, with a timeout. The function will return when the - * condition variable is notified, or the timeout occurs. There is no way to - * directly tell which happened, and it is possible that neither in fact - * happened (spurious wakeups are possible). - * - * See wait() with no parameters for more. - */ -void ConditionVarFullDebug:: -wait(double timeout) { - _mutex._global_lock->lock(); - - Thread *current_thread = Thread::get_current_thread(); - - if (!_mutex.do_debug_is_locked()) { - ostringstream ostr; - ostr << *current_thread << " attempted to wait on " - << *this << " without holding " << _mutex; - nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); - return; - } - - if (thread_cat.is_spam()) { - thread_cat.spam() - << *current_thread << " waiting on " << *this - << ", with timeout " << timeout << "\n"; - } - - nassertd(current_thread->_waiting_on_cvar == nullptr && - current_thread->_waiting_on_cvar_full == nullptr) { - } - current_thread->_waiting_on_cvar_full = this; - - _mutex.do_unlock(); - _impl.wait(timeout); // temporarily releases _global_lock - _mutex.do_lock(current_thread); - - nassertd(current_thread->_waiting_on_cvar_full == this) { - } - current_thread->_waiting_on_cvar_full = nullptr; - - if (thread_cat.is_spam()) { - thread_cat.spam() - << *current_thread << " awake on " << *this << "\n"; - } - - _mutex._global_lock->unlock(); -} - -/** - * Informs one of the other threads who are currently blocked on wait() that - * the relevant condition has changed. If multiple threads are currently - * waiting, at least one of them will be woken up, although there is no way to - * predict which one. It is possible that more than one thread will be woken - * up. - * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * - * If no threads are waiting, this is a no-op: the notify event is lost. - */ -void ConditionVarFullDebug:: -notify() { - _mutex._global_lock->lock(); - - /* - if (!_mutex.do_debug_is_locked()) { - Thread *current_thread = Thread::get_current_thread(); - ostringstream ostr; - ostr << *current_thread << " attempted to notify " - << *this << " without holding " << _mutex; - nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); - return; - } - */ - - if (thread_cat->is_spam()) { - Thread *current_thread = Thread::get_current_thread(); - thread_cat.spam() - << *current_thread << " notifying " << *this << "\n"; - } - - _impl.notify(); - _mutex._global_lock->unlock(); -} - -/** - * Informs all of the other threads who are currently blocked on wait() that - * the relevant condition has changed. - * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * - * If no threads are waiting, this is a no-op: the notify event is lost. - */ -void ConditionVarFullDebug:: -notify_all() { - _mutex._global_lock->lock(); - - /* - if (!_mutex.do_debug_is_locked()) { - Thread *current_thread = Thread::get_current_thread(); - ostringstream ostr; - ostr << *current_thread << " attempted to notify " - << *this << " without holding " << _mutex; - nassert_raise(ostr.str()); - _mutex._global_lock->unlock(); - return; - } - */ - - if (thread_cat->is_spam()) { - Thread *current_thread = Thread::get_current_thread(); - thread_cat.spam() - << *current_thread << " notifying all " << *this << "\n"; - } - - _impl.notify_all(); - _mutex._global_lock->unlock(); -} - -/** - * This method is declared virtual in ConditionVarFullDebug, but non-virtual - * in ConditionVarFullDirect. - */ -void ConditionVarFullDebug:: -output(ostream &out) const { - out << "ConditionVarFull " << (void *)this << " on " << _mutex; -} - -#endif // DEBUG_THREADS diff --git a/panda/src/pipeline/conditionVarFullDebug.h b/panda/src/pipeline/conditionVarFullDebug.h deleted file mode 100644 index cefb27cad7..0000000000 --- a/panda/src/pipeline/conditionVarFullDebug.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDebug.h - * @author drose - * @date 2006-08-28 - */ - -#ifndef CONDITIONVARFULLDEBUG_H -#define CONDITIONVARFULLDEBUG_H - -#include "pandabase.h" -#include "pmutex.h" -#include "conditionVarImpl.h" - -#ifdef DEBUG_THREADS - -/** - * A condition variable, usually used to communicate information about - * changing state to a thread that is waiting for something to happen. A - * condition variable can be used to "wake up" a thread when some arbitrary - * condition has changed. - * - * A condition variable is associated with a single mutex, and several - * condition variables may share the same mutex. - */ -class EXPCL_PANDA_PIPELINE ConditionVarFullDebug { -public: - explicit ConditionVarFullDebug(MutexDebug &mutex); - ConditionVarFullDebug(const ConditionVarFullDebug ©) = delete; - virtual ~ConditionVarFullDebug(); - - ConditionVarFullDebug &operator = (const ConditionVarFullDebug ©) = delete; - -PUBLISHED: - INLINE MutexDebug &get_mutex() const; - - BLOCKING void wait(); - BLOCKING void wait(double timeout); - void notify(); - void notify_all(); - virtual void output(std::ostream &out) const; - -private: - MutexDebug &_mutex; - ConditionVarFullImpl _impl; -}; - -INLINE std::ostream & -operator << (std::ostream &out, const ConditionVarFullDebug &cv) { - cv.output(out); - return out; -} - -#include "conditionVarFullDebug.I" - -#endif // DEBUG_THREADS - -#endif diff --git a/panda/src/pipeline/conditionVarFullDirect.I b/panda/src/pipeline/conditionVarFullDirect.I deleted file mode 100644 index 207cb01538..0000000000 --- a/panda/src/pipeline/conditionVarFullDirect.I +++ /dev/null @@ -1,103 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDirect.I - * @author drose - * @date 2006-08-28 - */ - -/** - * You must pass in a Mutex to the condition variable constructor. This mutex - * may be shared by other condition variables, if desired. It is the caller's - * responsibility to ensure the Mutex object does not destruct during the - * lifetime of the condition variable. - */ -INLINE ConditionVarFullDirect:: -ConditionVarFullDirect(MutexDirect &mutex) : - _mutex(mutex), - _impl(mutex._impl) -{ -} - -/** - * Returns the mutex associated with this condition variable. - */ -INLINE MutexDirect &ConditionVarFullDirect:: -get_mutex() const { - return _mutex; -} - -/** - * Waits on the condition. The caller must already be holding the lock - * associated with the condition variable before calling this function. - * - * wait() will release the lock, then go to sleep until some other thread - * calls notify() on this condition variable. At that time at least one - * thread waiting on the same ConditionVarFullDirect will grab the lock again, - * and then return from wait(). - * - * It is possible that wait() will return even if no one has called notify(). - * It is the responsibility of the calling process to verify the condition on - * return from wait, and possibly loop back to wait again if necessary. - * - * Note the semantics of a condition variable: the mutex must be held before - * wait() is called, and it will still be held when wait() returns. However, - * it will be temporarily released during the wait() call itself. - */ -INLINE void ConditionVarFullDirect:: -wait() { - TAU_PROFILE("ConditionVarFullDirect::wait()", " ", TAU_USER); - _impl.wait(); -} - -/** - * Waits on the condition, with a timeout. The function will return when the - * condition variable is notified, or the timeout occurs. There is no way to - * directly tell which happened, and it is possible that neither in fact - * happened (spurious wakeups are possible). - * - * See wait() with no parameters for more. - */ -void ConditionVarFullDirect:: -wait(double timeout) { - TAU_PROFILE("ConditionVarFullDirect::wait(double)", " ", TAU_USER); - _impl.wait(timeout); -} - -/** - * Informs one of the other threads who are currently blocked on wait() that - * the relevant condition has changed. If multiple threads are currently - * waiting, at least one of them will be woken up, although there is no way to - * predict which one. It is possible that more than one thread will be woken - * up. - * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * - * If no threads are waiting, this is a no-op: the notify is lost. - */ -INLINE void ConditionVarFullDirect:: -notify() { - TAU_PROFILE("ConditionVarFullDirect::notify()", " ", TAU_USER); - _impl.notify(); -} - -/** - * Informs all of the other threads who are currently blocked on wait() that - * the relevant condition has changed. - * - * The caller must be holding the mutex associated with the condition variable - * before making this call, which will not release the mutex. - * - * If no threads are waiting, this is a no-op: the notify event is lost. - */ -INLINE void ConditionVarFullDirect:: -notify_all() { - TAU_PROFILE("ConditionVarFullDirect::notify()", " ", TAU_USER); - _impl.notify_all(); -} diff --git a/panda/src/pipeline/conditionVarFullDirect.cxx b/panda/src/pipeline/conditionVarFullDirect.cxx deleted file mode 100644 index 04f9c647ed..0000000000 --- a/panda/src/pipeline/conditionVarFullDirect.cxx +++ /dev/null @@ -1,27 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDirect.cxx - * @author drose - * @date 2006-08-28 - */ - -#include "conditionVarFullDirect.h" - -#ifndef DEBUG_THREADS - -/** - * This method is declared virtual in ConditionVarFullDebug, but non-virtual - * in ConditionVarFullDirect. - */ -void ConditionVarFullDirect:: -output(std::ostream &out) const { - out << "ConditionVarFull " << (void *)this << " on " << _mutex; -} - -#endif // !DEBUG_THREADS diff --git a/panda/src/pipeline/conditionVarFullDirect.h b/panda/src/pipeline/conditionVarFullDirect.h deleted file mode 100644 index 729185501b..0000000000 --- a/panda/src/pipeline/conditionVarFullDirect.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullDirect.h - * @author drose - * @date 2006-08-28 - */ - -#ifndef CONDITIONVARFULLDIRECT_H -#define CONDITIONVARFULLDIRECT_H - -#include "pandabase.h" -#include "mutexDirect.h" -#include "conditionVarImpl.h" - -#ifndef DEBUG_THREADS - -/** - * A condition variable, usually used to communicate information about - * changing state to a thread that is waiting for something to happen. A - * condition variable can be used to "wake up" a thread when some arbitrary - * condition has changed. - * - * A condition variable is associated with a single mutex, and several - * condition variables may share the same mutex. - */ -class EXPCL_PANDA_PIPELINE ConditionVarFullDirect { -public: - INLINE explicit ConditionVarFullDirect(MutexDirect &mutex); - ConditionVarFullDirect(const ConditionVarFullDirect ©) = delete; - ~ConditionVarFullDirect() = default; - - ConditionVarFullDirect &operator = (const ConditionVarFullDirect ©) = delete; - -PUBLISHED: - INLINE MutexDirect &get_mutex() const; - - BLOCKING INLINE void wait(); - BLOCKING INLINE void wait(double timeout); - INLINE void notify(); - INLINE void notify_all(); - void output(std::ostream &out) const; - -private: - MutexDirect &_mutex; - ConditionVarFullImpl _impl; -}; - -INLINE std::ostream & -operator << (std::ostream &out, const ConditionVarFullDirect &cv) { - cv.output(out); - return out; -} - -#include "conditionVarFullDirect.I" - -#endif // !DEBUG_THREADS - -#endif diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.I b/panda/src/pipeline/conditionVarFullWin32Impl.I deleted file mode 100644 index 62e8d04e06..0000000000 --- a/panda/src/pipeline/conditionVarFullWin32Impl.I +++ /dev/null @@ -1,66 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullWin32Impl.I - * @author drose - * @date 2006-08-28 - */ - -/** - * - */ -INLINE ConditionVarFullWin32Impl:: -ConditionVarFullWin32Impl(MutexWin32Impl &mutex) : _mutex(mutex) { -} - -/** - * - */ -INLINE ConditionVarFullWin32Impl:: -~ConditionVarFullWin32Impl() { - // These fields are only set in the Windows XP implementation, when these - // both contain events. - if (_cvar[1] != nullptr) { - CloseHandle(_cvar[1]); - } - if (_cvar[2] != nullptr) { - CloseHandle(_cvar[2]); - } -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -wait() { - MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, INFINITE, 0); -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -wait(double timeout) { - MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, (DWORD)(timeout * 1000.0), 0); -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -notify() { - MutexWin32Impl::_funcs._cvar_notify_one(_cvar); -} - -/** - * - */ -INLINE void ConditionVarFullWin32Impl:: -notify_all() { - MutexWin32Impl::_funcs._cvar_notify_all(_cvar); -} diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.cxx b/panda/src/pipeline/conditionVarFullWin32Impl.cxx deleted file mode 100644 index 6d664735d6..0000000000 --- a/panda/src/pipeline/conditionVarFullWin32Impl.cxx +++ /dev/null @@ -1,20 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullWin32Impl.cxx - * @author drose - * @date 2006-08-28 - */ - -#include "selectThreadImpl.h" - -#if defined(WIN32_VC) || defined(WIN64_VC) - -#include "conditionVarFullWin32Impl.h" - -#endif // WIN32_VC diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.h b/panda/src/pipeline/conditionVarFullWin32Impl.h deleted file mode 100644 index 5c621412e7..0000000000 --- a/panda/src/pipeline/conditionVarFullWin32Impl.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file conditionVarFullWin32Impl.h - * @author drose - * @date 2006-08-28 - */ - -#ifndef CONDITIONVARFULLWIN32IMPL_H -#define CONDITIONVARFULLWIN32IMPL_H - -#include "pandabase.h" -#include "selectThreadImpl.h" - -#if defined(WIN32_VC) - -#include "mutexWin32Impl.h" -#include "pnotify.h" -#include "atomicAdjust.h" - -class MutexWin32Impl; - -/** - * Uses Windows native calls to implement a conditionVarFull. - * - * We follow the "SetEvent" implementation suggested by - * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html . This allows us to - * implement both notify() and notify_all(), but it has more overhead than the - * simpler implementation of ConditionVarWin32Impl. - * - * As described by the above reference, this implementation suffers from a few - * weaknesses; in particular, it does not necessarily wake up all threads - * fairly; and it may sometimes incorrectly wake up a thread that was not - * waiting at the time notify() was called. But we figure it's good enough - * for our purposes. - */ -class EXPCL_PANDA_PIPELINE ConditionVarFullWin32Impl { -public: - INLINE ConditionVarFullWin32Impl(MutexWin32Impl &mutex); - INLINE ~ConditionVarFullWin32Impl(); - - INLINE void wait(); - INLINE void wait(double timeout); - INLINE void notify(); - INLINE void notify_all(); - -private: - MutexWin32Impl &_mutex; - - // On Windows XP, the first field contains a Signal (auto-reset) event, - // the second field a broadcast (manual reset) event, third a waiter count. - // On Windows Vista and above, the first contains a PCONDITION_VARIABLE. - volatile PVOID _cvar[3] = {nullptr, nullptr, nullptr}; -}; - -#include "conditionVarFullWin32Impl.I" - -#endif // WIN32_VC - -#endif diff --git a/panda/src/pipeline/conditionVarImpl.h b/panda/src/pipeline/conditionVarImpl.h index 7837622ba6..774ab72753 100644 --- a/panda/src/pipeline/conditionVarImpl.h +++ b/panda/src/pipeline/conditionVarImpl.h @@ -21,35 +21,31 @@ #include "conditionVarDummyImpl.h" typedef ConditionVarDummyImpl ConditionVarImpl; -typedef ConditionVarDummyImpl ConditionVarFullImpl; #elif defined(THREAD_SIMPLE_IMPL) #include "conditionVarSimpleImpl.h" typedef ConditionVarSimpleImpl ConditionVarImpl; -typedef ConditionVarSimpleImpl ConditionVarFullImpl; #elif defined(MUTEX_SPINLOCK) #include "conditionVarSpinlockImpl.h" typedef ConditionVarSpinlockImpl ConditionVarImpl; -typedef ConditionVarSpinlockImpl ConditionVarFullImpl; #elif defined(THREAD_WIN32_IMPL) #include "conditionVarWin32Impl.h" -#include "conditionVarFullWin32Impl.h" typedef ConditionVarWin32Impl ConditionVarImpl; -typedef ConditionVarFullWin32Impl ConditionVarFullImpl; #elif defined(THREAD_POSIX_IMPL) #include "conditionVarPosixImpl.h" typedef ConditionVarPosixImpl ConditionVarImpl; -typedef ConditionVarPosixImpl ConditionVarFullImpl; #endif +typedef ConditionVarImpl ConditionVarFullImpl; + #if defined(WIN32_VC) #include "conditionVarWin32Impl.h" typedef ConditionVarWin32Impl TrueConditionVarImpl; diff --git a/panda/src/pipeline/conditionVarWin32Impl.I b/panda/src/pipeline/conditionVarWin32Impl.I index 82ba9dea39..7f2b24a079 100644 --- a/panda/src/pipeline/conditionVarWin32Impl.I +++ b/panda/src/pipeline/conditionVarWin32Impl.I @@ -16,8 +16,6 @@ */ INLINE ConditionVarWin32Impl:: ConditionVarWin32Impl(MutexWin32Impl &mutex) : _mutex(mutex) { - // Create an auto-reset event. - _event_signal = CreateEvent(nullptr, false, false, nullptr); } /** @@ -25,7 +23,14 @@ ConditionVarWin32Impl(MutexWin32Impl &mutex) : _mutex(mutex) { */ INLINE ConditionVarWin32Impl:: ~ConditionVarWin32Impl() { - CloseHandle(_event_signal); + // These fields are only set in the Windows XP implementation, when these + // both contain events. + if (_cvar[1] != nullptr) { + CloseHandle(_cvar[1]); + } + if (_cvar[2] != nullptr) { + CloseHandle(_cvar[2]); + } } /** @@ -33,12 +38,7 @@ INLINE ConditionVarWin32Impl:: */ INLINE void ConditionVarWin32Impl:: wait() { - _mutex.unlock(); - - DWORD result = WaitForSingleObject(_event_signal, INFINITE); - nassertv(result == WAIT_OBJECT_0); - - _mutex.lock(); + MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, INFINITE, 0); } /** @@ -46,12 +46,7 @@ wait() { */ INLINE void ConditionVarWin32Impl:: wait(double timeout) { - _mutex.unlock(); - - DWORD result = WaitForSingleObject(_event_signal, (DWORD)(timeout * 1000.0)); - nassertv(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT); - - _mutex.lock(); + MutexWin32Impl::_funcs._cvar_wait(_cvar, _mutex._lock, (DWORD)(timeout * 1000.0), 0); } /** @@ -59,5 +54,13 @@ wait(double timeout) { */ INLINE void ConditionVarWin32Impl:: notify() { - SetEvent(_event_signal); + MutexWin32Impl::_funcs._cvar_notify_one(_cvar); +} + +/** + * + */ +INLINE void ConditionVarWin32Impl:: +notify_all() { + MutexWin32Impl::_funcs._cvar_notify_all(_cvar); } diff --git a/panda/src/pipeline/conditionVarWin32Impl.h b/panda/src/pipeline/conditionVarWin32Impl.h index a0c4d882c7..213cacdf9e 100644 --- a/panda/src/pipeline/conditionVarWin32Impl.h +++ b/panda/src/pipeline/conditionVarWin32Impl.h @@ -25,14 +25,19 @@ class MutexWin32Impl; /** - * Uses Windows native calls to implement a conditionVar. + * Uses Windows native calls to implement a ConditionVar. * - * The Windows native synchronization primitives don't actually implement a - * full POSIX-style condition variable, but the Event primitive does a fair - * job if we disallow notify_all() (POSIX broadcast). See - * ConditionVarFullWin32Impl for a full implementation that includes - * notify_all(). This class is much simpler than that full implementation, so - * we can avoid the overhead required to support broadcast. + * On Windows Vista and above, we use the system's native condition variables. + * + * On Windows XP, we follow the "SetEvent" implementation suggested by + * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html . This allows us to + * implement both notify() and notify_all(). + * + * As described by the above reference, this implementation suffers from a few + * weaknesses; in particular, it does not necessarily wake up all threads + * fairly; and it may sometimes incorrectly wake up a thread that was not + * waiting at the time notify() was called. But we figure it's good enough + * for our purposes. */ class EXPCL_PANDA_PIPELINE ConditionVarWin32Impl { public: @@ -42,10 +47,15 @@ public: INLINE void wait(); INLINE void wait(double timeout); INLINE void notify(); + INLINE void notify_all(); private: MutexWin32Impl &_mutex; - HANDLE _event_signal; + + // On Windows XP, the first field contains a Signal (auto-reset) event, + // the second field a broadcast (manual reset) event, third a waiter count. + // On Windows Vista and above, the first contains a PCONDITION_VARIABLE. + volatile PVOID _cvar[3] = {nullptr, nullptr, nullptr}; }; #include "conditionVarWin32Impl.I" diff --git a/panda/src/pipeline/mutexDebug.h b/panda/src/pipeline/mutexDebug.h index 094f2eafc6..298fd9f7ca 100644 --- a/panda/src/pipeline/mutexDebug.h +++ b/panda/src/pipeline/mutexDebug.h @@ -83,7 +83,6 @@ private: static MutexTrueImpl *_global_lock; friend class ConditionVarDebug; - friend class ConditionVarFullDebug; }; INLINE std::ostream & diff --git a/panda/src/pipeline/mutexDirect.h b/panda/src/pipeline/mutexDirect.h index 068f5fc5c4..9e578abd52 100644 --- a/panda/src/pipeline/mutexDirect.h +++ b/panda/src/pipeline/mutexDirect.h @@ -57,7 +57,6 @@ private: mutable MutexTrueImpl _impl; friend class ConditionVarDirect; - friend class ConditionVarFullDirect; }; INLINE std::ostream & diff --git a/panda/src/pipeline/p3pipeline_composite1.cxx b/panda/src/pipeline/p3pipeline_composite1.cxx index 487c5ca0ad..5a9e929283 100644 --- a/panda/src/pipeline/p3pipeline_composite1.cxx +++ b/panda/src/pipeline/p3pipeline_composite1.cxx @@ -2,9 +2,6 @@ #include "conditionVarDebug.cxx" #include "conditionVarDirect.cxx" #include "conditionVarDummyImpl.cxx" -#include "conditionVarFull.cxx" -#include "conditionVarFullDebug.cxx" -#include "conditionVarFullDirect.cxx" #include "conditionVarPosixImpl.cxx" #include "conditionVarWin32Impl.cxx" #include "conditionVarSimpleImpl.cxx" diff --git a/panda/src/pipeline/thread.cxx b/panda/src/pipeline/thread.cxx index 80c32fa7f5..81152a8095 100644 --- a/panda/src/pipeline/thread.cxx +++ b/panda/src/pipeline/thread.cxx @@ -17,7 +17,6 @@ #include "config_pipeline.h" #include "mutexDebug.h" #include "conditionVarDebug.h" -#include "conditionVarFullDebug.h" Thread *Thread::_main_thread; Thread *Thread::_external_thread; @@ -52,7 +51,6 @@ Thread(const std::string &name, const std::string &sync_name) : #ifdef DEBUG_THREADS _blocked_on_mutex = nullptr; _waiting_on_cvar = nullptr; - _waiting_on_cvar_full = nullptr; #endif } @@ -63,8 +61,7 @@ Thread:: ~Thread() { #ifdef DEBUG_THREADS nassertv(_blocked_on_mutex == nullptr && - _waiting_on_cvar == nullptr && - _waiting_on_cvar_full == nullptr); + _waiting_on_cvar == nullptr); #endif } @@ -145,8 +142,6 @@ output_blocker(std::ostream &out) const { _blocked_on_mutex->output_with_holder(out); } else if (_waiting_on_cvar != nullptr) { out << *_waiting_on_cvar; - } else if (_waiting_on_cvar_full != nullptr) { - out << *_waiting_on_cvar_full; } #endif // DEBUG_THREADS } diff --git a/panda/src/pipeline/thread.h b/panda/src/pipeline/thread.h index 69b878725a..159b93c9df 100644 --- a/panda/src/pipeline/thread.h +++ b/panda/src/pipeline/thread.h @@ -31,7 +31,6 @@ class Mutex; class ReMutex; class MutexDebug; class ConditionVarDebug; -class ConditionVarFullDebug; class AsyncTask; /** @@ -156,7 +155,6 @@ private: #ifdef DEBUG_THREADS MutexDebug *_blocked_on_mutex; ConditionVarDebug *_waiting_on_cvar; - ConditionVarFullDebug *_waiting_on_cvar_full; #endif // DEBUG_THREADS private: @@ -184,7 +182,6 @@ private: friend class MutexDebug; friend class ConditionVarDebug; - friend class ConditionVarFullDebug; friend class ThreadDummyImpl; friend class ThreadWin32Impl;