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:
rdb 2019-02-11 15:29:35 +01:00
parent ab569916b1
commit fb5191e812
27 changed files with 91 additions and 822 deletions

View File

@ -74,7 +74,6 @@ private:
volatile PVOID _lock[2] = {nullptr, nullptr};
friend class ConditionVarWin32Impl;
friend class ConditionVarFullWin32Impl;
};
/**

View File

@ -22,7 +22,6 @@
class AsyncTaskManager;
class AsyncTask;
class ConditionVarFull;
/**
* This class represents a thread-safe handle to a promised future result of

View File

@ -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;
};

View File

@ -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.

View File

@ -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:

View File

@ -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();
}

View File

@ -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:

View File

@ -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
}

View File

@ -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"

View File

@ -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 &copy) = delete;
~ConditionVarFull() = default;
ConditionVarFull &operator = (const ConditionVarFull &copy) = delete;
INLINE Mutex &get_mutex() const;
};
#include "conditionVarFull.I"
typedef ConditionVar ConditionVarFull;
#endif

View File

@ -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;
}

View File

@ -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

View File

@ -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 &copy) = delete;
virtual ~ConditionVarFullDebug();
ConditionVarFullDebug &operator = (const ConditionVarFullDebug &copy) = 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

View File

@ -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();
}

View File

@ -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

View File

@ -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 &copy) = delete;
~ConditionVarFullDirect() = default;
ConditionVarFullDirect &operator = (const ConditionVarFullDirect &copy) = 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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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"

View File

@ -83,7 +83,6 @@ private:
static MutexTrueImpl *_global_lock;
friend class ConditionVarDebug;
friend class ConditionVarFullDebug;
};
INLINE std::ostream &

View File

@ -57,7 +57,6 @@ private:
mutable MutexTrueImpl _impl;
friend class ConditionVarDirect;
friend class ConditionVarFullDirect;
};
INLINE std::ostream &

View File

@ -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"

View File

@ -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
}

View File

@ -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;