Browse Source

condition variables

David Rose 23 years ago
parent
commit
f3d2494ba8

+ 22 - 2
panda/src/express/Sources.pp

@@ -14,7 +14,11 @@
     atomicAdjustNsprImpl.I \
     atomicAdjustNsprImpl.I \
     bigEndian.h buffer.I buffer.h \
     bigEndian.h buffer.I buffer.h \
     checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
     checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
-    circBuffer.h clockObject.I clockObject.h config_express.h \
+    circBuffer.h clockObject.I clockObject.h \
+    conditionVarDummyImpl.h conditionVarDummyImpl.I conditionVar.h \
+    conditionVar.I conditionVarImpl.h conditionVarNsprImpl.h \
+    conditionVarNsprImpl.I \
+    config_express.h \
     datagram.I datagram.h datagramGenerator.I \
     datagram.I datagram.h datagramGenerator.I \
     datagramGenerator.h \
     datagramGenerator.h \
     datagramIterator.I datagramIterator.h datagramSink.I datagramSink.h \
     datagramIterator.I datagramIterator.h datagramSink.I datagramSink.h \
@@ -67,6 +71,7 @@
   #define INCLUDED_SOURCES  \
   #define INCLUDED_SOURCES  \
     atomicAdjust.cxx atomicAdjustDummyImpl.cxx atomicAdjustNsprImpl.cxx \
     atomicAdjust.cxx atomicAdjustDummyImpl.cxx atomicAdjustNsprImpl.cxx \
     buffer.cxx checksumHashGenerator.cxx clockObject.cxx \
     buffer.cxx checksumHashGenerator.cxx clockObject.cxx \
+    conditionVar.cxx conditionVarDummyImpl.cxx conditionVarNsprImpl.cxx \
     config_express.cxx datagram.cxx datagramGenerator.cxx \
     config_express.cxx datagram.cxx datagramGenerator.cxx \
     datagramIterator.cxx \
     datagramIterator.cxx \
     datagramSink.cxx dcast.cxx error_utils.cxx \
     datagramSink.cxx dcast.cxx error_utils.cxx \
@@ -99,7 +104,11 @@
     atomicAdjustNsprImpl.I \
     atomicAdjustNsprImpl.I \
     bigEndian.h buffer.I buffer.h checksumHashGenerator.I  \
     bigEndian.h buffer.I buffer.h checksumHashGenerator.I  \
     checksumHashGenerator.h circBuffer.I circBuffer.h clockObject.I \
     checksumHashGenerator.h circBuffer.I circBuffer.h clockObject.I \
-    clockObject.h config_express.h datagram.I datagram.h \
+    clockObject.h \
+    conditionVarDummyImpl.h conditionVarDummyImpl.I conditionVar.h \
+    conditionVar.I conditionVarImpl.h conditionVarNsprImpl.h \
+    conditionVarNsprImpl.I \
+    config_express.h datagram.I datagram.h \
     datagramGenerator.I datagramGenerator.h \
     datagramGenerator.I datagramGenerator.h \
     datagramIterator.I datagramIterator.h \
     datagramIterator.I datagramIterator.h \
     datagramSink.I datagramSink.h dcast.T dcast.h \
     datagramSink.I datagramSink.h dcast.T dcast.h \
@@ -192,3 +201,14 @@
 
 
 #end test_bin_target
 #end test_bin_target
 
 
+
+#begin test_bin_target
+  #define TARGET test_diners
+  #define LOCAL_LIBS $[LOCAL_LIBS] express
+  #define OTHER_LIBS dtoolutil:c dtool:m pystub
+
+  #define SOURCES \
+    test_diners.cxx
+
+#end test_bin_target
+

+ 144 - 0
panda/src/express/conditionVar.I

@@ -0,0 +1,144 @@
+// Filename: conditionVar.I
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVar::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 ConditionVar::
+ConditionVar(Mutex &mutex) :
+  _mutex(mutex),
+  _impl(mutex._impl)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVar::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVar::
+~ConditionVar() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVar::Copy Constructor
+//       Access: Private
+//  Description: Do not attempt to copy condition variables.
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVar::
+ConditionVar(const ConditionVar &copy) : 
+  _mutex(*(Mutex *)NULL), 
+  _impl(*(MutexImpl *)NULL)
+{
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVar::Copy Assignment Operator
+//       Access: Private
+//  Description: Do not attempt to copy condition variables.
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVar::
+operator = (const ConditionVar &copy) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVar::get_mutex
+//       Access: Public
+//  Description: Returns the mutex associated with this condition
+//               variable.
+////////////////////////////////////////////////////////////////////
+INLINE Mutex &ConditionVar::
+get_mutex() {
+  return _mutex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVar::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 ConditionVar 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 ConditionVar::
+wait() {
+  _impl.wait();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVar::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.
+//
+//               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 ConditionVar::
+signal() {
+  _impl.signal();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVar::signal_all
+//       Access: Public
+//  Description: Wakes up all of the other threads currently blocked
+//               on wait().
+//
+//               The caller must be holding the mutex associated with
+//               the condition variable before making this call, which
+//               will not release the mutex.
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVar::
+signal_all() {
+  _impl.signal_all();
+}

+ 19 - 0
panda/src/express/conditionVar.cxx

@@ -0,0 +1,19 @@
+// Filename: conditionVar.cxx
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "conditionVar.h"

+ 61 - 0
panda/src/express/conditionVar.h

@@ -0,0 +1,61 @@
+// Filename: conditionVar.h
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONDITIONVAR_H
+#define CONDITIONVAR_H
+
+#include "pandabase.h"
+#include "mutex.h"
+#include "conditionVarImpl.h"
+#include "notify.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ConditionVar
+// Description : A condition variable, used to implement a more
+//               sophisticated kind of thread synchronization that is
+//               possible with a simple mutex.  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_PANDAEXPRESS ConditionVar {
+public:
+  INLINE ConditionVar(Mutex &mutex);
+  INLINE ~ConditionVar();
+private:
+  INLINE ConditionVar(const ConditionVar &copy);
+  INLINE void operator = (const ConditionVar &copy);
+
+public:
+  INLINE Mutex &get_mutex();
+
+  INLINE void wait();
+  INLINE void signal();
+  INLINE void signal_all();
+
+private:
+  Mutex &_mutex;
+  ConditionVarImpl _impl;
+};
+
+#include "conditionVar.I"
+
+#endif

+ 63 - 0
panda/src/express/conditionVarDummyImpl.I

@@ -0,0 +1,63 @@
+// Filename: conditionVarDummyImpl.I
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarDummyImpl::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVarDummyImpl::
+ConditionVarDummyImpl(MutexDummyImpl &) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarDummyImpl::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVarDummyImpl::
+~ConditionVarDummyImpl() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarDummyImpl::lock
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVarDummyImpl::
+wait() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarDummyImpl::signal
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVarDummyImpl::
+signal() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarDummyImpl::signal_all
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVarDummyImpl::
+signal_all() {
+}

+ 25 - 0
panda/src/express/conditionVarDummyImpl.cxx

@@ -0,0 +1,25 @@
+// Filename: conditionVarDummyImpl.cxx
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "selectIpcImpl.h"
+
+#ifdef IPC_DUMMY_IMPL
+
+#include "conditionVarDummyImpl.h"
+
+#endif  // IPC_DUMMY_IMPL

+ 51 - 0
panda/src/express/conditionVarDummyImpl.h

@@ -0,0 +1,51 @@
+// Filename: conditionVarDummyImpl.h
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONDITIONVARDUMMYIMPL_H
+#define CONDITIONVARDUMMYIMPL_H
+
+#include "pandabase.h"
+#include "selectIpcImpl.h"
+
+#ifdef IPC_DUMMY_IMPL
+
+#include "notify.h"
+
+class MutexDummyImpl;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ConditionVarDummyImpl
+// Description : A fake condition variable implementation for
+//               single-threaded applications that don't need any
+//               synchronization control.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS ConditionVarDummyImpl {
+public:
+  INLINE ConditionVarDummyImpl(MutexDummyImpl &mutex);
+  INLINE ~ConditionVarDummyImpl();
+
+  INLINE void wait();
+  INLINE void signal();
+  INLINE void signal_all();
+};
+
+#include "conditionVarDummyImpl.I"
+
+#endif  // IPC_DUMMY_IMPL
+
+#endif

+ 40 - 0
panda/src/express/conditionVarImpl.h

@@ -0,0 +1,40 @@
+// Filename: conditionVarImpl.h
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONDITIONVARIMPL_H
+#define CONDITIONVARIMPL_H
+
+#include "pandabase.h"
+#include "selectIpcImpl.h"
+
+#if defined(IPC_DUMMY_IMPL)
+
+#include "conditionVarDummyImpl.h"
+typedef ConditionVarDummyImpl ConditionVarImpl;
+
+#elif defined(IPC_NSPR_IMPL)
+
+#include "conditionVarNsprImpl.h"
+typedef ConditionVarNsprImpl ConditionVarImpl;
+
+#endif
+
+#endif
+
+
+

+ 72 - 0
panda/src/express/conditionVarNsprImpl.I

@@ -0,0 +1,72 @@
+// Filename: conditionVarNsprImpl.I
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarNsprImpl::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVarNsprImpl::
+ConditionVarNsprImpl(MutexNsprImpl &mutex) {
+  _cvar = PR_NewCondVar(mutex._lock);
+  nassertv(_cvar != (PRCondVar *)NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarNsprImpl::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVarNsprImpl::
+~ConditionVarNsprImpl() {
+  PR_DestroyCondVar(_cvar);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarNsprImpl::wait
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVarNsprImpl::
+wait() {
+  int status = PR_WaitCondVar(_cvar, PR_INTERVAL_NO_TIMEOUT);
+  nassertv(status == PR_SUCCESS);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarNsprImpl::signal
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVarNsprImpl::
+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);
+}

+ 25 - 0
panda/src/express/conditionVarNsprImpl.cxx

@@ -0,0 +1,25 @@
+// Filename: conditionVarNsprImpl.cxx
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "selectIpcImpl.h"
+
+#ifdef IPC_NSPR_IMPL
+
+#include "conditionVarNsprImpl.h"
+
+#endif  // IPC_NSPR_IMPL

+ 55 - 0
panda/src/express/conditionVarNsprImpl.h

@@ -0,0 +1,55 @@
+// Filename: conditionVarNsprImpl.h
+// Created by:  drose (09Aug02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONDITIONVARNSPRIMPL_H
+#define CONDITIONVARNSPRIMPL_H
+
+#include "pandabase.h"
+#include "selectIpcImpl.h"
+
+#ifdef IPC_NSPR_IMPL
+
+#include "mutexNsprImpl.h"
+#include "notify.h"
+
+#include <prcvar.h>
+
+class MutexNsprImpl;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ConditionVarNsprImpl
+// Description : Uses NSPR to implement a conditionVar.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS ConditionVarNsprImpl {
+public:
+  INLINE ConditionVarNsprImpl(MutexNsprImpl &mutex);
+  INLINE ~ConditionVarNsprImpl();
+
+  INLINE void wait();
+  INLINE void signal();
+  INLINE void signal_all();
+
+private:
+  PRCondVar *_cvar;
+};
+
+#include "conditionVarNsprImpl.I"
+
+#endif  // IPC_NSPR_IMPL
+
+#endif

+ 3 - 0
panda/src/express/express_composite1.cxx

@@ -4,6 +4,9 @@
 #include "buffer.cxx"
 #include "buffer.cxx"
 #include "checksumHashGenerator.cxx"
 #include "checksumHashGenerator.cxx"
 #include "clockObject.cxx"
 #include "clockObject.cxx"
+#include "conditionVar.cxx"
+#include "conditionVarDummyImpl.cxx"
+#include "conditionVarNsprImpl.cxx"
 #include "config_express.cxx"
 #include "config_express.cxx"
 #include "datagram.cxx"
 #include "datagram.cxx"
 #include "datagramGenerator.cxx"
 #include "datagramGenerator.cxx"

+ 1 - 0
panda/src/express/mutex.h

@@ -44,6 +44,7 @@ public:
 
 
 private:
 private:
   MutexImpl _impl;
   MutexImpl _impl;
+  friend class ConditionVar;
 };
 };
 
 
 #include "mutex.I"
 #include "mutex.I"

+ 1 - 0
panda/src/express/mutexDummyImpl.h

@@ -23,6 +23,7 @@
 #include "selectIpcImpl.h"
 #include "selectIpcImpl.h"
 
 
 #ifdef IPC_DUMMY_IMPL
 #ifdef IPC_DUMMY_IMPL
+
 #include "notify.h"
 #include "notify.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
panda/src/express/mutexNsprImpl.I

@@ -25,6 +25,7 @@
 INLINE MutexNsprImpl::
 INLINE MutexNsprImpl::
 MutexNsprImpl() {
 MutexNsprImpl() {
   _lock = PR_NewLock();
   _lock = PR_NewLock();
+  nassertv(_lock != (PRLock *)NULL);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
panda/src/express/mutexNsprImpl.h

@@ -42,6 +42,7 @@ public:
 
 
 private:
 private:
   PRLock *_lock;
   PRLock *_lock;
+  friend class ConditionVarNsprImpl;
 };
 };
 
 
 #include "mutexNsprImpl.I"
 #include "mutexNsprImpl.I"

+ 152 - 0
panda/src/express/test_diners.cxx

@@ -0,0 +1,152 @@
+// Filename: test_diners.cxx
+// Created by:  cary (16Sep98)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+// A solution to the famous dining philosophers, implemented using the
+// threading abstraction.  This program exercises thread creation and
+// destruction, mutexes, and condition variables.
+
+#include "pandabase.h"
+#include "thread.h"
+#include "conditionVar.h"
+#include "mutexHolder.h"
+#include "pointerTo.h"
+
+#ifdef WIN32_VC
+static int last_rand = 0;
+#endif /* __WIN32__ */
+
+Mutex rand_mutex;
+
+static double random_f(double max)
+{
+   MutexHolder l(rand_mutex);
+   int i = rand();
+#ifdef WIN32_VC
+   last_rand = i;
+#endif /* __WIN32__ */
+   return max * (double)i / (double)RAND_MAX;
+}
+
+Mutex print_mutex;
+
+#define PRINTMSG(x) { MutexHolder l(print_mutex); x; }
+
+// n philosophers sharing n chopsticks.  Philosophers are poor folk and can't
+// afford luxuries like 2 chopsticks per person.
+#define N_DINERS 5
+
+Mutex chopsticks[N_DINERS];
+
+// At most n philosophers are allowed into the room, others would have to
+// wait at the door.  This restriction demonstrates the use of condition
+// variables.
+
+Mutex room_mutex;
+
+ConditionVar room_condition(room_mutex);
+int room_occupancy = 0;
+
+class philosopher;
+PT(philosopher) phils[N_DINERS];
+
+class philosopher : public Thread {
+   private:
+     int _id;
+     void thread_main() {
+#ifdef WIN32_VC
+         rand_mutex.lock();
+         srand(last_rand);
+         rand_mutex.release();
+#endif /* __WIN32__ */
+         int l = _id;
+         int r = l+1;
+         if (r == N_DINERS)
+            r = 0;
+         if (l & 1) {
+            int t = l;
+            l = r;
+            r = t;
+         }
+         PRINTMSG(cerr << "Philosopher #" << _id << " has entered the room."
+                  << endl);
+         int count = (int)random_f(10.0) + 1;
+         while (--count) {
+            chopsticks[l].lock();
+            chopsticks[r].lock();
+            PRINTMSG(cerr << "Philosopher #" << _id
+                     << " is eating spaghetti now." << endl);
+            Thread::sleep(random_f(3.0));
+            chopsticks[l].release();
+            chopsticks[r].release();
+            PRINTMSG(cerr << "Philosopher #" << _id
+                     << " is pondering about life." << endl);
+            Thread::sleep(random_f(3.0));
+         }
+         room_mutex.lock();
+         --room_occupancy;
+         phils[_id] = (philosopher*)0L;
+         room_condition.signal();
+         room_mutex.release();
+         PRINTMSG(cerr << "Philosopher #" << _id << " has left the room ("
+                  << room_occupancy << " left)." << endl);
+      }
+
+      inline void* make_arg(const int i) { return (void*)new int(i); }
+   public:
+      philosopher(const int id) : Thread("philosopher") {
+        _id = id;
+      }
+};
+
+int main(int, char**)
+{
+   int i;
+   room_mutex.lock();
+   for (i=0; i<N_DINERS; ++i) {
+      phils[i] = new philosopher(i);
+      phils[i]->start(TP_normal, false, false);
+   }
+   room_occupancy = N_DINERS;
+   while (1) {
+      while (room_occupancy == N_DINERS) {
+         PRINTMSG(cerr << "main thread about to block " << room_occupancy
+                  << endl);
+         room_condition.wait();
+      }
+      // hmm.. someone left the room.
+      room_mutex.release();
+      // sleep for a while and then create a new philosopher
+      PRINTMSG(cerr << "main thread sleep" << endl);
+      Thread::sleep(2.0);
+      PRINTMSG(cerr << "main thread wake up" << endl);
+      room_mutex.lock();
+      for (i=0; i<N_DINERS; ++i)
+         if (phils[i] == (philosopher*)0L)
+            break;
+      if (i == N_DINERS) {
+         PRINTMSG(cerr
+                  << "Contrary to what I was tolk, no one has left the room!!!"
+                  << endl);
+         PRINTMSG(cerr << "I give up!" << endl);
+         Thread::prepare_for_exit();
+         exit(1);
+      }
+      phils[i] = new philosopher(i);
+      ++room_occupancy;
+   }
+}