diff --git a/dtool/src/dtoolbase/mutexWin32Impl.h b/dtool/src/dtoolbase/mutexWin32Impl.h index f7949cb910..382793b125 100644 --- a/dtool/src/dtoolbase/mutexWin32Impl.h +++ b/dtool/src/dtoolbase/mutexWin32Impl.h @@ -42,6 +42,7 @@ public: private: CRITICAL_SECTION _lock; friend class ConditionVarWin32Impl; + friend class ConditionVarFullWin32Impl; }; #include "mutexWin32Impl.I" diff --git a/panda/src/pipeline/Sources.pp b/panda/src/pipeline/Sources.pp index 3c55ff7786..231c07c129 100644 --- a/panda/src/pipeline/Sources.pp +++ b/panda/src/pipeline/Sources.pp @@ -14,9 +14,12 @@ conditionVarDebug.h conditionVarDebug.I \ conditionVarDirect.h conditionVarDirect.I \ conditionVarDummyImpl.h conditionVarDummyImpl.I \ + conditionVarFull.h conditionVarFull.I \ + conditionVarFullDebug.h conditionVarFullDebug.I \ + conditionVarFullDirect.h conditionVarFullDirect.I \ + conditionVarFullWin32Impl.h conditionVarFullWin32Impl.I \ conditionVarImpl.h \ conditionVarNsprImpl.h conditionVarNsprImpl.I \ - conditionVarLinuxImpl.h conditionVarLinuxImpl.I \ conditionVarPosixImpl.h conditionVarPosixImpl.I \ conditionVarWin32Impl.h conditionVarWin32Impl.I \ conditionVarSpinlockImpl.h conditionVarSpinlockImpl.I \ @@ -47,7 +50,6 @@ reMutexHolder.I reMutexHolder.h \ threadDummyImpl.h threadDummyImpl.I thread.h thread.I threadImpl.h \ threadNsprImpl.h threadNsprImpl.I \ - threadLinuxImpl.h threadLinuxImpl.I \ threadPosixImpl.h threadPosixImpl.I \ threadWin32Impl.h threadWin32Impl.I \ threadPriority.h @@ -57,8 +59,11 @@ conditionVarDebug.cxx \ conditionVarDirect.cxx \ conditionVarDummyImpl.cxx \ + conditionVarFull.cxx \ + conditionVarFullDebug.cxx \ + conditionVarFullDirect.cxx \ + conditionVarFullWin32Impl.cxx \ conditionVarNsprImpl.cxx \ - conditionVarLinuxImpl.cxx \ conditionVarPosixImpl.cxx \ conditionVarWin32Impl.cxx \ conditionVarSpinlockImpl.cxx \ @@ -87,7 +92,6 @@ reMutexHolder.cxx \ thread.cxx threadDummyImpl.cxx \ threadNsprImpl.cxx \ - threadLinuxImpl.cxx \ threadPosixImpl.cxx \ threadWin32Impl.cxx @@ -96,9 +100,12 @@ conditionVarDebug.h conditionVarDebug.I \ conditionVarDirect.h conditionVarDirect.I \ conditionVarDummyImpl.h conditionVarDummyImpl.I \ + conditionVarFull.h conditionVarFull.I \ + conditionVarFullDebug.h conditionVarFullDebug.I \ + conditionVarFullDirect.h conditionVarFullDirect.I \ + conditionVarFullWin32Impl.h conditionVarFullWin32Impl.I \ conditionVarImpl.h \ conditionVarNsprImpl.h conditionVarNsprImpl.I \ - conditionVarLinuxImpl.h conditionVarLinuxImpl.I \ conditionVarPosixImpl.h conditionVarPosixImpl.I \ conditionVarWin32Impl.h conditionVarWin32Impl.I \ conditionVarSpinlockImpl.h conditionVarSpinlockImpl.I \ @@ -129,7 +136,6 @@ reMutexHolder.I reMutexHolder.h \ threadDummyImpl.h threadDummyImpl.I thread.h thread.I threadImpl.h \ threadNsprImpl.h threadNsprImpl.I \ - threadLinuxImpl.h threadLinuxImpl.I \ threadPosixImpl.h threadPosixImpl.I \ threadWin32Impl.h threadWin32Impl.I \ threadPriority.h diff --git a/panda/src/pipeline/conditionVar.h b/panda/src/pipeline/conditionVar.h index 799898d491..a218dcff9e 100644 --- a/panda/src/pipeline/conditionVar.h +++ b/panda/src/pipeline/conditionVar.h @@ -30,6 +30,12 @@ // waiting for something to happen. A 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 +// signal_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 diff --git a/panda/src/pipeline/conditionVarDebug.cxx b/panda/src/pipeline/conditionVarDebug.cxx index 9dfe907625..34ee1c3499 100755 --- a/panda/src/pipeline/conditionVarDebug.cxx +++ b/panda/src/pipeline/conditionVarDebug.cxx @@ -111,7 +111,8 @@ wait() { // 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. +// 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 diff --git a/panda/src/pipeline/conditionVarDirect.I b/panda/src/pipeline/conditionVarDirect.I index 75c3d30cad..5202a8f2a2 100755 --- a/panda/src/pipeline/conditionVarDirect.I +++ b/panda/src/pipeline/conditionVarDirect.I @@ -115,7 +115,8 @@ wait() { // 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. +// 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 diff --git a/panda/src/pipeline/conditionVarFull.I b/panda/src/pipeline/conditionVarFull.I new file mode 100644 index 0000000000..8dcbb73536 --- /dev/null +++ b/panda/src/pipeline/conditionVarFull.I @@ -0,0 +1,88 @@ +// Filename: conditionVarFull.I +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFull::Constructor +// Access: Public +// Description: 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 +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFull::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ConditionVarFull:: +~ConditionVarFull() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFull::Copy Constructor +// Access: Private +// Description: Do not attempt to copy condition variables. +//////////////////////////////////////////////////////////////////// +INLINE ConditionVarFull:: +ConditionVarFull(const ConditionVarFull ©) : +#ifdef DEBUG_THREADS + ConditionVarFullDebug(copy.get_mutex()) +#else + ConditionVarFullDirect(copy.get_mutex()) +#endif // DEBUG_THREADS +{ + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFull::Copy Assignment Operator +// Access: Private +// Description: Do not attempt to copy condition variables. +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarFull:: +operator = (const ConditionVarFull ©) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFull::get_mutex +// Access: Public +// Description: 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 new file mode 100644 index 0000000000..bd386aa4b8 --- /dev/null +++ b/panda/src/pipeline/conditionVarFull.cxx @@ -0,0 +1,19 @@ +// Filename: conditionVarFull.cxx +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "conditionVarFull.h" diff --git a/panda/src/pipeline/conditionVarFull.h b/panda/src/pipeline/conditionVarFull.h new file mode 100644 index 0000000000..b0e79a1438 --- /dev/null +++ b/panda/src/pipeline/conditionVarFull.h @@ -0,0 +1,73 @@ +// Filename: conditionVarFull.h +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONDITIONVARFULL_H +#define CONDITIONVARFULL_H + +#include "pandabase.h" +#include "conditionVarFullDebug.h" +#include "conditionVarFullDirect.h" + +//////////////////////////////////////////////////////////////////// +// Class : ConditionVarFull +// Description : 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 signal_all() method, which is guaranteed +// to wake up all threads currently waiting on the +// condition (whereas signal() 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 signal_all() requires more +// overhead, so you should use ConditionVar for cases +// when you do not require the signal_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 signal() or signal_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 ConditionVarFull : public ConditionVarFullDebug +#else +class EXPCL_PANDA ConditionVarFull : public ConditionVarFullDirect +#endif // DEBUG_THREADS +{ +public: + INLINE ConditionVarFull(Mutex &mutex); + INLINE ~ConditionVarFull(); +private: + INLINE ConditionVarFull(const ConditionVarFull ©); + INLINE void operator = (const ConditionVarFull ©); + +public: + INLINE Mutex &get_mutex() const; +}; + +#include "conditionVarFull.I" + +#endif diff --git a/panda/src/pipeline/threadLinuxImpl.I b/panda/src/pipeline/conditionVarFullDebug.I similarity index 50% rename from panda/src/pipeline/threadLinuxImpl.I rename to panda/src/pipeline/conditionVarFullDebug.I index 896779bf6c..822e20f558 100644 --- a/panda/src/pipeline/threadLinuxImpl.I +++ b/panda/src/pipeline/conditionVarFullDebug.I @@ -1,5 +1,5 @@ -// Filename: threadLinuxImpl.I -// Created by: drose (28Mar06) +// Filename: conditionVarFullDebug.I +// Created by: drose (28Aug06) // //////////////////////////////////////////////////////////////////// // @@ -18,49 +18,35 @@ //////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::Constructor -// Access: Public -// Description: +// Function: ConditionVarFullDebug::Copy Constructor +// Access: Private +// Description: Do not attempt to copy condition variables. //////////////////////////////////////////////////////////////////// -INLINE ThreadLinuxImpl:: -ThreadLinuxImpl(Thread *parent_obj) : - _cv(_mutex), - _parent_obj(parent_obj) +INLINE ConditionVarFullDebug:: +ConditionVarFullDebug(const ConditionVarFullDebug ©) : + _mutex(copy._mutex), + _impl(*_mutex._global_lock) { - _thread = 0; - _joinable = false; - _status = S_new; - _stack = NULL; + nassertv(false); } //////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::prepare_for_exit +// Function: ConditionVarFullDebug::Copy Assignment Operator +// Access: Private +// Description: Do not attempt to copy condition variables. +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarFullDebug:: +operator = (const ConditionVarFullDebug ©) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDebug::get_mutex // Access: Public -// Description: +// Description: Returns the mutex associated with this condition +// variable. //////////////////////////////////////////////////////////////////// -INLINE void ThreadLinuxImpl:: -prepare_for_exit() { -} - -//////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::is_threading_supported -// Access: Public, Static -// Description: -//////////////////////////////////////////////////////////////////// -INLINE bool ThreadLinuxImpl:: -is_threading_supported() { - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::sleep -// Access: Public, Static -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void ThreadLinuxImpl:: -sleep(double seconds) { - struct timespec rqtp; - rqtp.tv_sec = time_t(seconds); - rqtp.tv_nsec = long((seconds - (double)rqtp.tv_sec) * 1000000000.0); - nanosleep(&rqtp, NULL); +INLINE MutexDebug &ConditionVarFullDebug:: +get_mutex() const { + return _mutex; } diff --git a/panda/src/pipeline/conditionVarFullDebug.cxx b/panda/src/pipeline/conditionVarFullDebug.cxx new file mode 100644 index 0000000000..c123e24608 --- /dev/null +++ b/panda/src/pipeline/conditionVarFullDebug.cxx @@ -0,0 +1,191 @@ +// Filename: conditionVarFullDebug.cxx +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "conditionVarFullDebug.h" +#include "thread.h" +#include "config_pipeline.h" + +#ifdef DEBUG_THREADS + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDebug::Constructor +// Access: Public +// Description: 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); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDebug::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +ConditionVarFullDebug:: +~ConditionVarFullDebug() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDebug::wait +// Access: Public +// Description: 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 signal() 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 signal(). 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(); + + if (!_mutex.do_debug_is_locked()) { + ostringstream ostr; + ostr << *Thread::get_current_thread() << " attempted to wait on " + << *this << " without holding " << _mutex; + nassert_raise(ostr.str()); + _mutex._global_lock->release(); + return; + } + + if (thread_cat.is_spam()) { + thread_cat.spam() + << *Thread::get_current_thread() << " waiting on " << *this << "\n"; + } + + _mutex.do_release(); + _impl.wait(); + _mutex.do_lock(); + + if (thread_cat.is_spam()) { + thread_cat.spam() + << *Thread::get_current_thread() << " awake on " << *this << "\n"; + } + + _mutex._global_lock->release(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDebug::signal +// Access: Public +// Description: 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 +// signal is lost. +//////////////////////////////////////////////////////////////////// +void ConditionVarFullDebug:: +signal() { + _mutex._global_lock->lock(); + if (!_mutex.do_debug_is_locked()) { + ostringstream ostr; + ostr << *Thread::get_current_thread() << " attempted to signal " + << *this << " without holding " << _mutex; + nassert_raise(ostr.str()); + _mutex._global_lock->release(); + return; + } + + if (thread_cat.is_spam()) { + thread_cat.spam() + << *Thread::get_current_thread() << " signalling " << *this << "\n"; + } + + _impl.signal(); + _mutex._global_lock->release(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDebug::signal +// Access: Public +// Description: 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 +// signal is lost. +//////////////////////////////////////////////////////////////////// +void ConditionVarFullDebug:: +signal_all() { + _mutex._global_lock->lock(); + if (!_mutex.do_debug_is_locked()) { + ostringstream ostr; + ostr << *Thread::get_current_thread() << " attempted to signal " + << *this << " without holding " << _mutex; + nassert_raise(ostr.str()); + _mutex._global_lock->release(); + return; + } + + if (thread_cat.is_spam()) { + thread_cat.spam() + << *Thread::get_current_thread() << " signalling all " << *this << "\n"; + } + + _impl.signal_all(); + _mutex._global_lock->release(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDebug::output +// Access: Public, Virtual +// Description: 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 new file mode 100644 index 0000000000..713ec82160 --- /dev/null +++ b/panda/src/pipeline/conditionVarFullDebug.h @@ -0,0 +1,71 @@ +// Filename: conditionVarFullDebug.h +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONDITIONVARFULLDEBUG_H +#define CONDITIONVARFULLDEBUG_H + +#include "pandabase.h" +#include "pmutex.h" +#include "conditionVarImpl.h" + +#ifdef DEBUG_THREADS + +//////////////////////////////////////////////////////////////////// +// Class : ConditionVarFullDebug +// Description : 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 ConditionVarFullDebug { +public: + ConditionVarFullDebug(MutexDebug &mutex); + virtual ~ConditionVarFullDebug(); +private: + INLINE ConditionVarFullDebug(const ConditionVarFullDebug ©); + INLINE void operator = (const ConditionVarFullDebug ©); + +public: + INLINE MutexDebug &get_mutex() const; + + void wait(); + void signal(); + void signal_all(); + virtual void output(ostream &out) const; + +private: + MutexDebug &_mutex; + ConditionVarFullImpl _impl; +}; + +INLINE ostream & +operator << (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 new file mode 100644 index 0000000000..50738e576e --- /dev/null +++ b/panda/src/pipeline/conditionVarFullDirect.I @@ -0,0 +1,152 @@ +// Filename: conditionVarFullDirect.I +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDirect::Constructor +// Access: Public +// Description: 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) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDirect::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ConditionVarFullDirect:: +~ConditionVarFullDirect() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDirect::Copy Constructor +// Access: Private +// Description: Do not attempt to copy condition variables. +//////////////////////////////////////////////////////////////////// +INLINE ConditionVarFullDirect:: +ConditionVarFullDirect(const ConditionVarFullDirect ©) : + _mutex(copy._mutex), + _impl(_mutex._impl) +{ + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDirect::Copy Assignment Operator +// Access: Private +// Description: Do not attempt to copy condition variables. +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarFullDirect:: +operator = (const ConditionVarFullDirect ©) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDirect::get_mutex +// Access: Public +// Description: Returns the mutex associated with this condition +// variable. +//////////////////////////////////////////////////////////////////// +INLINE MutexDirect &ConditionVarFullDirect:: +get_mutex() const { + return _mutex; +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDirect::wait +// Access: Public +// Description: 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 signal() 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 signal(). 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(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDirect::signal +// Access: Public +// Description: 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 +// signal is lost. +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarFullDirect:: +signal() { + TAU_PROFILE("ConditionVarFullDirect::signal()", " ", TAU_USER); + _impl.signal(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullDirect::signal_all +// Access: Public +// Description: 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 +// signal is lost. +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarFullDirect:: +signal_all() { + TAU_PROFILE("ConditionVarFullDirect::signal()", " ", TAU_USER); + _impl.signal_all(); +} diff --git a/panda/src/pipeline/conditionVarLinuxImpl.I b/panda/src/pipeline/conditionVarFullDirect.cxx similarity index 59% rename from panda/src/pipeline/conditionVarLinuxImpl.I rename to panda/src/pipeline/conditionVarFullDirect.cxx index 0c1dd28c7c..719b4fad9e 100644 --- a/panda/src/pipeline/conditionVarLinuxImpl.I +++ b/panda/src/pipeline/conditionVarFullDirect.cxx @@ -1,5 +1,5 @@ -// Filename: conditionVarLinuxImpl.I -// Created by: drose (28Mar06) +// Filename: conditionVarFullDirect.cxx +// Created by: drose (28Aug06) // //////////////////////////////////////////////////////////////////// // @@ -16,24 +16,19 @@ // //////////////////////////////////////////////////////////////////// +#include "conditionVarFullDirect.h" + +#ifndef DEBUG_THREADS //////////////////////////////////////////////////////////////////// -// Function: ConditionVarLinuxImpl::Constructor +// Function: ConditionVarFullDirect::output // Access: Public -// Description: +// Description: This method is declared virtual in ConditionVarFullDebug, +// but non-virtual in ConditionVarFullDirect. //////////////////////////////////////////////////////////////////// -INLINE ConditionVarLinuxImpl:: -ConditionVarLinuxImpl(MutexLinuxImpl &mutex) : - _mutex(mutex) -{ - _counter = 0; +void ConditionVarFullDirect:: +output(ostream &out) const { + out << "ConditionVarFull " << (void *)this << " on " << _mutex; } -//////////////////////////////////////////////////////////////////// -// Function: ConditionVarLinuxImpl::Destructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ConditionVarLinuxImpl:: -~ConditionVarLinuxImpl() { -} +#endif // !DEBUG_THREADS diff --git a/panda/src/pipeline/conditionVarFullDirect.h b/panda/src/pipeline/conditionVarFullDirect.h new file mode 100644 index 0000000000..f0289965f9 --- /dev/null +++ b/panda/src/pipeline/conditionVarFullDirect.h @@ -0,0 +1,71 @@ +// Filename: conditionVarFullDirect.h +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONDITIONVARFULLDIRECT_H +#define CONDITIONVARFULLDIRECT_H + +#include "pandabase.h" +#include "mutexDirect.h" +#include "conditionVarImpl.h" + +#ifndef DEBUG_THREADS + +//////////////////////////////////////////////////////////////////// +// Class : ConditionVarFullDirect +// Description : 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 ConditionVarFullDirect { +public: + INLINE ConditionVarFullDirect(MutexDirect &mutex); + INLINE ~ConditionVarFullDirect(); +private: + INLINE ConditionVarFullDirect(const ConditionVarFullDirect ©); + INLINE void operator = (const ConditionVarFullDirect ©); + +public: + INLINE MutexDirect &get_mutex() const; + + INLINE void wait(); + INLINE void signal(); + INLINE void signal_all(); + void output(ostream &out) const; + +private: + MutexDirect &_mutex; + ConditionVarFullImpl _impl; +}; + +INLINE ostream & +operator << (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 new file mode 100644 index 0000000000..8c359809e5 --- /dev/null +++ b/panda/src/pipeline/conditionVarFullWin32Impl.I @@ -0,0 +1,77 @@ +// Filename: conditionVarFullWin32Impl.I +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullWin32Impl::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ConditionVarFullWin32Impl:: +ConditionVarFullWin32Impl(MutexWin32Impl &mutex) { + _external_mutex = &mutex._lock; + + // Create an auto-reset event. + _event_signal = CreateEvent(NULL, false, false, NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullWin32Impl::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ConditionVarFullWin32Impl:: +~ConditionVarFullWin32Impl() { + CloseHandle(_event_signal); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullWin32Impl::wait +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarFullWin32Impl:: +wait() { + LeaveCriticalSection(_external_mutex); + + DWORD result = WaitForSingleObject(_event_signal, INFINITE); + nassertv(result == WAIT_OBJECT_0); + + EnterCriticalSection(_external_mutex); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullWin32Impl::signal +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarFullWin32Impl:: +signal() { + SetEvent(_event_signal); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarFullWin32Impl::signal_all +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarFullWin32Impl:: +signal_all() { + // TODO. + nassertv(false); +} diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.cxx b/panda/src/pipeline/conditionVarFullWin32Impl.cxx new file mode 100644 index 0000000000..d7785e7c49 --- /dev/null +++ b/panda/src/pipeline/conditionVarFullWin32Impl.cxx @@ -0,0 +1,25 @@ +// Filename: conditionVarFullWin32Impl.cxx +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "selectThreadImpl.h" + +#ifdef WIN32_VC + +#include "conditionVarFullWin32Impl.h" + +#endif // WIN32_VC diff --git a/panda/src/pipeline/conditionVarFullWin32Impl.h b/panda/src/pipeline/conditionVarFullWin32Impl.h new file mode 100644 index 0000000000..e21cacc467 --- /dev/null +++ b/panda/src/pipeline/conditionVarFullWin32Impl.h @@ -0,0 +1,65 @@ +// Filename: conditionVarFullWin32Impl.h +// Created by: drose (28Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONDITIONVARFULLWIN32IMPL_H +#define CONDITIONVARFULLWIN32IMPL_H + +#include "pandabase.h" +#include "selectThreadImpl.h" + +#ifdef WIN32_VC + +#include "mutexWin32Impl.h" +#include "pnotify.h" + +class MutexWin32Impl; + +//////////////////////////////////////////////////////////////////// +// Class : ConditionVarFullWin32Impl +// Description : Uses Windows native calls to implement a +// conditionVarFull. +// +// 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 POSIX broadcast. See +// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html for +// a full implementation that includes broadcast. This +// class is much simpler than that full implementation, +// so we can avoid the overhead require to support +// broadcast. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA ConditionVarFullWin32Impl { +public: + INLINE ConditionVarFullWin32Impl(MutexWin32Impl &mutex); + INLINE ~ConditionVarFullWin32Impl(); + + INLINE void wait(); + INLINE void signal(); + INLINE void signal_all(); + +private: + CRITICAL_SECTION *_external_mutex; + HANDLE _event_signal; +}; + +#include "conditionVarFullWin32Impl.I" + +#endif // WIN32_VC + +#endif diff --git a/panda/src/pipeline/conditionVarImpl.h b/panda/src/pipeline/conditionVarImpl.h index c69f467be2..97f068b50f 100644 --- a/panda/src/pipeline/conditionVarImpl.h +++ b/panda/src/pipeline/conditionVarImpl.h @@ -26,31 +26,32 @@ #include "conditionVarDummyImpl.h" typedef ConditionVarDummyImpl ConditionVarImpl; +typedef ConditionVarDummyImpl 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; - -#elif defined(THREAD_LINUX_IMPL) - -#include "conditionVarLinuxImpl.h" -typedef ConditionVarLinuxImpl ConditionVarImpl; +typedef ConditionVarFullWin32Impl ConditionVarFullImpl; #elif defined(THREAD_POSIX_IMPL) #include "conditionVarPosixImpl.h" typedef ConditionVarPosixImpl ConditionVarImpl; +typedef ConditionVarPosixImpl ConditionVarFullImpl; #elif defined(THREAD_NSPR_IMPL) #include "conditionVarNsprImpl.h" typedef ConditionVarNsprImpl ConditionVarImpl; +typedef ConditionVarNsprImpl ConditionVarFullImpl; #endif diff --git a/panda/src/pipeline/conditionVarLinuxImpl.cxx b/panda/src/pipeline/conditionVarLinuxImpl.cxx deleted file mode 100644 index 3168603897..0000000000 --- a/panda/src/pipeline/conditionVarLinuxImpl.cxx +++ /dev/null @@ -1,55 +0,0 @@ -// Filename: conditionVarLinuxImpl.cxx -// Created by: drose (28Mar06) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://etc.cmu.edu/panda3d/docs/license/ . -// -// To contact the maintainers of this program write to -// panda3d-general@lists.sourceforge.net . -// -//////////////////////////////////////////////////////////////////// - -#include "selectThreadImpl.h" - -#ifdef HAVE_LINUX_NATIVE_THREADS - -#include "conditionVarLinuxImpl.h" - -#include -#include -#include - -//////////////////////////////////////////////////////////////////// -// Function: ConditionVarLinuxImpl::wait -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -void ConditionVarLinuxImpl:: -wait() { - // Grab the current value of the counter before we release the - // mutex. - PN_int32 orig_counter = _counter; - _mutex.release(); - syscall(SYS_futex, &_counter, FUTEX_WAIT, orig_counter, (void *)NULL); - _mutex.lock(); -} - -//////////////////////////////////////////////////////////////////// -// Function: ConditionVarLinuxImpl::signal -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -void ConditionVarLinuxImpl:: -signal() { - AtomicAdjust::inc(_counter); - syscall(SYS_futex, &_counter, FUTEX_WAKE, 1); -} - -#endif // HAVE_LINUX_NATIVE_THREADS diff --git a/panda/src/pipeline/conditionVarLinuxImpl.h b/panda/src/pipeline/conditionVarLinuxImpl.h deleted file mode 100644 index 955d579862..0000000000 --- a/panda/src/pipeline/conditionVarLinuxImpl.h +++ /dev/null @@ -1,53 +0,0 @@ -// Filename: conditionVarLinuxImpl.h -// Created by: drose (28Mar06) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://etc.cmu.edu/panda3d/docs/license/ . -// -// To contact the maintainers of this program write to -// panda3d-general@lists.sourceforge.net . -// -//////////////////////////////////////////////////////////////////// - -#ifndef CONDITIONVARLINUXIMPL_H -#define CONDITIONVARLINUXIMPL_H - -#include "pandabase.h" -#include "selectThreadImpl.h" - -#ifdef HAVE_LINUX_NATIVE_THREADS - -#include "mutexLinuxImpl.h" -#include "pnotify.h" - -class MutexLinuxImpl; - -//////////////////////////////////////////////////////////////////// -// Class : ConditionVarLinuxImpl -// Description : Uses Linux threads to implement a conditionVar. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA ConditionVarLinuxImpl { -public: - INLINE ConditionVarLinuxImpl(MutexLinuxImpl &mutex); - INLINE ~ConditionVarLinuxImpl(); - - void wait(); - void signal(); - -private: - MutexLinuxImpl &_mutex; - PN_int32 _counter; -}; - -#include "conditionVarLinuxImpl.I" - -#endif // HAVE_LINUX_NATIVE_THREADS - -#endif diff --git a/panda/src/pipeline/conditionVarNsprImpl.I b/panda/src/pipeline/conditionVarNsprImpl.I index 1d18e4e17a..01ec07c9c4 100644 --- a/panda/src/pipeline/conditionVarNsprImpl.I +++ b/panda/src/pipeline/conditionVarNsprImpl.I @@ -59,3 +59,14 @@ signal() { int status = PR_NotifyCondVar(_cvar); nassertv(status == PR_SUCCESS); } + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarNsprImpl::signal_all +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarNsprImpl:: +signal_all() { + int status = PR_NotifyAllCondVar(_cvar); + nassertv(status == PR_SUCCESS); +} diff --git a/panda/src/pipeline/conditionVarNsprImpl.h b/panda/src/pipeline/conditionVarNsprImpl.h index c305af0f6e..289ead6c79 100644 --- a/panda/src/pipeline/conditionVarNsprImpl.h +++ b/panda/src/pipeline/conditionVarNsprImpl.h @@ -42,6 +42,7 @@ public: INLINE void wait(); INLINE void signal(); + INLINE void signal_all(); private: PRCondVar *_cvar; diff --git a/panda/src/pipeline/conditionVarPosixImpl.I b/panda/src/pipeline/conditionVarPosixImpl.I index ff9006bf63..ff5860441d 100644 --- a/panda/src/pipeline/conditionVarPosixImpl.I +++ b/panda/src/pipeline/conditionVarPosixImpl.I @@ -66,3 +66,15 @@ signal() { int result = pthread_cond_signal(&_cvar); nassertv(result == 0); } + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarPosixImpl::signal_all +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarPosixImpl:: +signal_all() { + TAU_PROFILE("ConditionVarPosixImpl::signal()", " ", TAU_USER); + int result = pthread_cond_broadcast(&_cvar); + nassertv(result == 0); +} diff --git a/panda/src/pipeline/conditionVarPosixImpl.h b/panda/src/pipeline/conditionVarPosixImpl.h index d177512b36..5daedf239a 100644 --- a/panda/src/pipeline/conditionVarPosixImpl.h +++ b/panda/src/pipeline/conditionVarPosixImpl.h @@ -42,6 +42,7 @@ public: INLINE void wait(); INLINE void signal(); + INLINE void signal_all(); private: MutexPosixImpl &_mutex; diff --git a/panda/src/pipeline/conditionVarSpinlockImpl.I b/panda/src/pipeline/conditionVarSpinlockImpl.I index 38033e1b39..c831e7fd63 100644 --- a/panda/src/pipeline/conditionVarSpinlockImpl.I +++ b/panda/src/pipeline/conditionVarSpinlockImpl.I @@ -46,3 +46,13 @@ signal() { // This will wake up all waiters on the lock. But that's allowed. AtomicAdjust::inc(_event); } + +//////////////////////////////////////////////////////////////////// +// Function: ConditionVarSpinlockImpl::signal_all +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void ConditionVarSpinlockImpl:: +signal_all() { + AtomicAdjust::inc(_event); +} diff --git a/panda/src/pipeline/conditionVarSpinlockImpl.h b/panda/src/pipeline/conditionVarSpinlockImpl.h index 39bdececef..67a3432140 100644 --- a/panda/src/pipeline/conditionVarSpinlockImpl.h +++ b/panda/src/pipeline/conditionVarSpinlockImpl.h @@ -46,6 +46,7 @@ public: void wait(); INLINE void signal(); + INLINE void signal_all(); private: MutexSpinlockImpl &_mutex; diff --git a/panda/src/pipeline/mutexDebug.h b/panda/src/pipeline/mutexDebug.h index 7c4e160faf..0eaae95567 100644 --- a/panda/src/pipeline/mutexDebug.h +++ b/panda/src/pipeline/mutexDebug.h @@ -71,6 +71,7 @@ private: static MutexImpl *_global_lock; friend class ConditionVarDebug; + friend class ConditionVarFullDebug; }; INLINE ostream & diff --git a/panda/src/pipeline/mutexDirect.h b/panda/src/pipeline/mutexDirect.h index 69e18f820a..21fc2c1c09 100644 --- a/panda/src/pipeline/mutexDirect.h +++ b/panda/src/pipeline/mutexDirect.h @@ -52,6 +52,7 @@ private: MutexImpl _impl; friend class ConditionVarDirect; + friend class ConditionVarFullDirect; }; INLINE ostream & diff --git a/panda/src/pipeline/pipeline_composite1.cxx b/panda/src/pipeline/pipeline_composite1.cxx index 707c36d58d..c9f7cc963b 100644 --- a/panda/src/pipeline/pipeline_composite1.cxx +++ b/panda/src/pipeline/pipeline_composite1.cxx @@ -2,8 +2,10 @@ #include "conditionVarDebug.cxx" #include "conditionVarDirect.cxx" #include "conditionVarDummyImpl.cxx" +#include "conditionVarFull.cxx" +#include "conditionVarFullDebug.cxx" +#include "conditionVarFullDirect.cxx" #include "conditionVarNsprImpl.cxx" -#include "conditionVarLinuxImpl.cxx" #include "conditionVarPosixImpl.cxx" #include "conditionVarWin32Impl.cxx" #include "conditionVarSpinlockImpl.cxx" diff --git a/panda/src/pipeline/pipeline_composite2.cxx b/panda/src/pipeline/pipeline_composite2.cxx index 92827f81fc..c12be1cf35 100644 --- a/panda/src/pipeline/pipeline_composite2.cxx +++ b/panda/src/pipeline/pipeline_composite2.cxx @@ -15,6 +15,5 @@ #include "thread.cxx" #include "threadDummyImpl.cxx" #include "threadNsprImpl.cxx" -#include "threadLinuxImpl.cxx" #include "threadPosixImpl.cxx" #include "threadWin32Impl.cxx" diff --git a/panda/src/pipeline/thread.h b/panda/src/pipeline/thread.h index 354ef53e91..d1837b59c4 100644 --- a/panda/src/pipeline/thread.h +++ b/panda/src/pipeline/thread.h @@ -130,7 +130,6 @@ private: friend class ThreadDummyImpl; friend class ThreadWin32Impl; - friend class ThreadLinuxImpl; friend class ThreadPosixImpl; friend class ThreadNsprImpl; }; diff --git a/panda/src/pipeline/threadImpl.h b/panda/src/pipeline/threadImpl.h index bc5aa58167..45925fb9b4 100644 --- a/panda/src/pipeline/threadImpl.h +++ b/panda/src/pipeline/threadImpl.h @@ -32,11 +32,6 @@ typedef ThreadDummyImpl ThreadImpl; #include "threadWin32Impl.h" typedef ThreadWin32Impl ThreadImpl; -#elif defined(THREAD_LINUX_IMPL) - -#include "threadLinuxImpl.h" -typedef ThreadLinuxImpl ThreadImpl; - #elif defined(THREAD_POSIX_IMPL) #include "threadPosixImpl.h" diff --git a/panda/src/pipeline/threadLinuxImpl.cxx b/panda/src/pipeline/threadLinuxImpl.cxx deleted file mode 100644 index dcb6c65604..0000000000 --- a/panda/src/pipeline/threadLinuxImpl.cxx +++ /dev/null @@ -1,260 +0,0 @@ -// Filename: threadLinuxImpl.cxx -// Created by: drose (28Mar06) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://etc.cmu.edu/panda3d/docs/license/ . -// -// To contact the maintainers of this program write to -// panda3d-general@lists.sourceforge.net . -// -//////////////////////////////////////////////////////////////////// - -#include "threadLinuxImpl.h" -#include "selectThreadImpl.h" - -#ifdef THREAD_LINUX_IMPL - -#include "pointerTo.h" -#include "config_pipeline.h" - -#include -#include -#include -#include -#include // for perror - -MutexLinuxImpl ThreadLinuxImpl::_thread_pointers_lock; -ThreadLinuxImpl::ThreadPointers ThreadLinuxImpl::_thread_pointers; -bool ThreadLinuxImpl::_got_main_thread_pointer; - -inline static pid_t gettid() { -#ifdef __i386__ - pid_t ret; - __asm__("int $0x80" : "=a" (ret) : "0" (224) /* SYS_gettid */); - return ret; -#else -#error only i386 supported right now. -#endif -} - -//////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::Destructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -ThreadLinuxImpl:: -~ThreadLinuxImpl() { - if (thread_cat.is_debug()) { - thread_cat.debug() << "Deleting thread " << _parent_obj->get_name() << "\n"; - } - - if (_stack != NULL) { - delete[] _stack; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::start -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -bool ThreadLinuxImpl:: -start(ThreadPriority priority, bool global, bool joinable) { - _mutex.lock(); - if (thread_cat.is_debug()) { - thread_cat.debug() << "Starting " << *_parent_obj << "\n"; - } - - nassertd(_status == S_new && _thread == 0 && _stack == NULL) { - _mutex.release(); - return false; - } - - _joinable = joinable; - _status = S_start_called; - - if (!_got_main_thread_pointer) { - // If we haven't spawned any threads yet, this must be the main - // thread. - bind_thread(Thread::get_main_thread()); - _got_main_thread_pointer = true; - } - - // Increment the parent object's reference count first. The thread - // will eventually decrement it when it terminates. - _parent_obj->ref(); - - _stack = new unsigned char[thread_stack_size]; - - int flags = SIGCHLD | CLONE_PARENT | CLONE_VM; - if (!global) { - // Make a thread that uses the same pid as the parent. - flags |= CLONE_SIGHAND | CLONE_THREAD; - } - - _thread = - clone(&root_func, _stack + thread_stack_size, - flags, (void *)this); - - if (_thread == -1) { - // Oops, we couldn't start the thread. Be sure to decrement the - // reference count we incremented above, and return false to - // indicate failure. - perror("clone"); - unref_delete(_parent_obj); - _mutex.release(); - return false; - } - - _mutex.release(); - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::interrupt -// Access: Public -// Description: Sends an interrupt message to the thread. This will -// interrupt any blocking-type system calls the thread -// may be waiting on, such as I/O, so that the thread -// may continue some other processing. The specific -// behavior is implementation dependent. -//////////////////////////////////////////////////////////////////// -void ThreadLinuxImpl:: -interrupt() { -} - -//////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::join -// Access: Public -// Description: Blocks the calling process until the thread -// terminates. If the thread has already terminated, -// this returns immediately. -//////////////////////////////////////////////////////////////////// -void ThreadLinuxImpl:: -join() { - _mutex.lock(); - nassertd(_joinable && _status != S_new) { - _mutex.release(); - return; - } - - while (_status != S_finished) { - _cv.wait(); - } - _mutex.release(); -} - -//////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::get_current_thread -// Access: Public, Static -// Description: -//////////////////////////////////////////////////////////////////// -Thread *ThreadLinuxImpl:: -get_current_thread() { - if (!_got_main_thread_pointer) { - // If we haven't spawned any threads yet, this must be the main - // thread. - bind_thread(Thread::get_main_thread()); - _got_main_thread_pointer = true; - return Thread::get_main_thread(); - } - - _thread_pointers_lock.lock(); - Thread *result = NULL; - - ThreadPointers::const_iterator ti; - pid_t my_tid = gettid(); - ti = _thread_pointers.find(my_tid); - if (ti != _thread_pointers.end()) { - result = (*ti).second; - } - _thread_pointers_lock.release(); - - nassertr(result != NULL, NULL); - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::bind_thread -// Access: Public, Static -// Description: Associates the indicated Thread object with the -// currently-executing thread. You should not call this -// directly; use Thread::bind_thread() instead. -//////////////////////////////////////////////////////////////////// -void ThreadLinuxImpl:: -bind_thread(Thread *thread) { - _thread_pointers_lock.lock(); - pid_t my_tid = gettid(); - bool inserted = _thread_pointers.insert(ThreadPointers::value_type(my_tid, thread)).second; - _thread_pointers_lock.release(); - nassertv(inserted); -} - -//////////////////////////////////////////////////////////////////// -// Function: ThreadLinuxImpl::root_func -// Access: Private, Static -// Description: The entry point of each thread. -//////////////////////////////////////////////////////////////////// -int ThreadLinuxImpl:: -root_func(void *data) { - ThreadLinuxImpl *self = (ThreadLinuxImpl *)data; - - { - _thread_pointers_lock.lock(); - pid_t my_tid = gettid(); - - bool inserted = _thread_pointers.insert(ThreadPointers::value_type(my_tid, self->_parent_obj)).second; - nassertd(inserted) { - _thread_pointers_lock.release(); - return 1; - } - _thread_pointers_lock.release(); - } - - { - self->_mutex.lock(); - nassertd(self->_status == S_start_called) { - self->_mutex.release(); - return 1; - } - - self->_status = S_running; - self->_cv.signal(); - self->_mutex.release(); - } - - self->_parent_obj->thread_main(); - - if (thread_cat.is_debug()) { - thread_cat.debug() - << "Terminating thread " << self->_parent_obj->get_name() - << ", count = " << self->_parent_obj->get_ref_count() << "\n"; - } - - { - self->_mutex.lock(); - nassertd(self->_status == S_running) { - self->_mutex.release(); - return 1; - } - self->_status = S_finished; - self->_cv.signal(); - self->_mutex.release(); - } - - // Now drop the parent object reference that we grabbed in start(). - // This might delete the parent object, and in turn, delete the - // ThreadLinuxImpl object. - unref_delete(self->_parent_obj); - - return 0; -} - -#endif // THREAD_LINUX_IMPL diff --git a/panda/src/pipeline/threadLinuxImpl.h b/panda/src/pipeline/threadLinuxImpl.h deleted file mode 100644 index 034f8b613d..0000000000 --- a/panda/src/pipeline/threadLinuxImpl.h +++ /dev/null @@ -1,84 +0,0 @@ -// Filename: threadLinuxImpl.h -// Created by: drose (28Mar06) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://etc.cmu.edu/panda3d/docs/license/ . -// -// To contact the maintainers of this program write to -// panda3d-general@lists.sourceforge.net . -// -//////////////////////////////////////////////////////////////////// - -#ifndef THREADLINUXIMPL_H -#define THREADLINUXIMPL_H - -#include "pandabase.h" -#include "selectThreadImpl.h" - -#ifdef THREAD_LINUX_IMPL - -#include "pnotify.h" -#include "threadPriority.h" -#include "mutexLinuxImpl.h" -#include "conditionVarLinuxImpl.h" - -class Thread; - -//////////////////////////////////////////////////////////////////// -// Class : ThreadLinuxImpl -// Description : Uses low-level Linux-specific calls to implement -// threads. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA ThreadLinuxImpl { -public: - INLINE ThreadLinuxImpl(Thread *parent_obj); - ~ThreadLinuxImpl(); - - bool start(ThreadPriority priority, bool global, bool joinable); - void interrupt(); - void join(); - - INLINE static void prepare_for_exit(); - - static Thread *get_current_thread(); - static void bind_thread(Thread *thread); - INLINE static bool is_threading_supported(); - INLINE static void sleep(double seconds); - -private: - static int root_func(void *data); - - enum Status { - S_new, - S_start_called, - S_running, - S_finished - }; - - MutexLinuxImpl _mutex; - ConditionVarLinuxImpl _cv; - Thread *_parent_obj; - int _thread; - bool _joinable; - Status _status; - unsigned char *_stack; - - // per-thread data. - typedef pmap ThreadPointers; - static ThreadPointers _thread_pointers; - static MutexLinuxImpl _thread_pointers_lock; - static bool _got_main_thread_pointer; -}; - -#include "threadLinuxImpl.I" - -#endif // THREAD_LINUX_IMPL - -#endif