mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 16:20:11 -04:00
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.
This commit is contained in:
parent
ab569916b1
commit
fb5191e812
@ -74,7 +74,6 @@ private:
|
||||
volatile PVOID _lock[2] = {nullptr, nullptr};
|
||||
|
||||
friend class ConditionVarWin32Impl;
|
||||
friend class ConditionVarFullWin32Impl;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
class AsyncTaskManager;
|
||||
class AsyncTask;
|
||||
class ConditionVarFull;
|
||||
|
||||
/**
|
||||
* This class represents a thread-safe handle to a promised future result of
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
@ -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"
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
@ -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();
|
||||
}
|
@ -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
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -83,7 +83,6 @@ private:
|
||||
static MutexTrueImpl *_global_lock;
|
||||
|
||||
friend class ConditionVarDebug;
|
||||
friend class ConditionVarFullDebug;
|
||||
};
|
||||
|
||||
INLINE std::ostream &
|
||||
|
@ -57,7 +57,6 @@ private:
|
||||
mutable MutexTrueImpl _impl;
|
||||
|
||||
friend class ConditionVarDirect;
|
||||
friend class ConditionVarFullDirect;
|
||||
};
|
||||
|
||||
INLINE std::ostream &
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user