Browse Source

use native Windows threading primitives

David Rose 20 years ago
parent
commit
0405754d17
38 changed files with 1197 additions and 264 deletions
  1. 8 8
      panda/src/egg/lexer.cxx.prebuilt
  2. 8 8
      panda/src/egg/lexer.lxx
  3. 11 11
      panda/src/egg/parser.cxx.prebuilt
  4. 6 6
      panda/src/egg/parser.h.prebuilt
  5. 15 15
      panda/src/egg/parser.yxx
  6. 37 17
      panda/src/express/Sources.pp
  7. 5 0
      panda/src/express/atomicAdjustImpl.h
  8. 60 0
      panda/src/express/atomicAdjustWin32Impl.I
  9. 25 0
      panda/src/express/atomicAdjustWin32Impl.cxx
  10. 47 0
      panda/src/express/atomicAdjustWin32Impl.h
  11. 6 20
      panda/src/express/conditionVar.I
  12. 42 0
      panda/src/express/conditionVar.cxx
  13. 4 2
      panda/src/express/conditionVar.h
  14. 5 0
      panda/src/express/conditionVarImpl.h
  15. 0 11
      panda/src/express/conditionVarNsprImpl.I
  16. 0 1
      panda/src/express/conditionVarNsprImpl.h
  17. 66 0
      panda/src/express/conditionVarWin32Impl.I
  18. 25 0
      panda/src/express/conditionVarWin32Impl.cxx
  19. 66 0
      panda/src/express/conditionVarWin32Impl.h
  20. 3 0
      panda/src/express/express_composite1.cxx
  21. 1 0
      panda/src/express/express_composite2.cxx
  22. 8 0
      panda/src/express/mutexImpl.h
  23. 58 0
      panda/src/express/mutexWin32Impl.I
  24. 25 0
      panda/src/express/mutexWin32Impl.cxx
  25. 52 0
      panda/src/express/mutexWin32Impl.h
  26. 12 0
      panda/src/express/pmutex.h
  27. 103 64
      panda/src/express/reMutex.I
  28. 4 0
      panda/src/express/reMutex.cxx
  29. 6 5
      panda/src/express/reMutex.h
  30. 6 0
      panda/src/express/selectThreadImpl.h
  31. 91 86
      panda/src/express/test_diners.cxx
  32. 1 0
      panda/src/express/thread.h
  33. 5 0
      panda/src/express/threadImpl.h
  34. 8 2
      panda/src/express/threadNsprImpl.cxx
  35. 91 0
      panda/src/express/threadWin32Impl.I
  36. 202 0
      panda/src/express/threadWin32Impl.cxx
  37. 83 0
      panda/src/express/threadWin32Impl.h
  38. 2 8
      panda/src/putil/pipelineCyclerTrueImpl.I

+ 8 - 8
panda/src/egg/lexer.cxx.prebuilt

@@ -1989,7 +1989,7 @@ YY_RULE_SETUP
   accept(); 
   eggyylval._number = atof(eggyytext); 
   eggyylval._string = yytext;
-  return NUMBER; 
+  return EGG_NUMBER; 
 }
 	YY_BREAK
 case 91:
@@ -2000,7 +2000,7 @@ YY_RULE_SETUP
   accept(); 
   eggyylval._ulong = strtoul(yytext+2, NULL, 16);
   eggyylval._string = yytext;
-  return ULONG; 
+  return EGG_ULONG; 
 }
 	YY_BREAK
 case 92:
@@ -2011,7 +2011,7 @@ YY_RULE_SETUP
   accept(); 
   eggyylval._ulong = strtoul(yytext+2, NULL, 2);
   eggyylval._string = yytext;
-  return ULONG; 
+  return EGG_ULONG; 
 }
 	YY_BREAK
 case 93:
@@ -2023,7 +2023,7 @@ YY_RULE_SETUP
   memset(&eggyylval._number, 0, sizeof(eggyylval._number));
   *(unsigned long *)&eggyylval._number = strtoul(yytext+3, NULL, 0);
   eggyylval._string = yytext;
-  return NUMBER;
+  return EGG_NUMBER;
 }
 	YY_BREAK
 case 94:
@@ -2034,7 +2034,7 @@ YY_RULE_SETUP
   accept(); 
   eggyylval._number = HUGE_VAL;
   eggyylval._string = yytext;
-  return NUMBER; 
+  return EGG_NUMBER; 
 }
 	YY_BREAK
 case 95:
@@ -2045,7 +2045,7 @@ YY_RULE_SETUP
   accept(); 
   eggyylval._number = -HUGE_VAL;
   eggyylval._string = yytext;
-  return NUMBER; 
+  return EGG_NUMBER; 
 }
 	YY_BREAK
 case 96:
@@ -2055,7 +2055,7 @@ YY_RULE_SETUP
   // Quoted string.
   accept();
   eggyylval._string = scan_quoted_string();
-  return STRING;
+  return EGG_STRING;
 }
 	YY_BREAK
 case 97:
@@ -2065,7 +2065,7 @@ YY_RULE_SETUP
   // Unquoted string.
   accept();
   eggyylval._string = yytext;
-  return STRING;
+  return EGG_STRING;
 }
 	YY_BREAK
 case 98:

+ 8 - 8
panda/src/egg/lexer.lxx

@@ -679,7 +679,7 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   accept(); 
   eggyylval._number = atof(eggyytext); 
   eggyylval._string = yytext;
-  return NUMBER; 
+  return EGG_NUMBER; 
 }
 
 {HEX} {
@@ -687,7 +687,7 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   accept(); 
   eggyylval._ulong = strtoul(yytext+2, NULL, 16);
   eggyylval._string = yytext;
-  return ULONG; 
+  return EGG_ULONG; 
 }
 
 {BINARY} {
@@ -695,7 +695,7 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   accept(); 
   eggyylval._ulong = strtoul(yytext+2, NULL, 2);
   eggyylval._string = yytext;
-  return ULONG; 
+  return EGG_ULONG; 
 }
 
 "nan"{HEX} {
@@ -704,7 +704,7 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   memset(&eggyylval._number, 0, sizeof(eggyylval._number));
   *(unsigned long *)&eggyylval._number = strtoul(yytext+3, NULL, 0);
   eggyylval._string = yytext;
-  return NUMBER;
+  return EGG_NUMBER;
 }
 
 "inf" { 
@@ -712,7 +712,7 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   accept(); 
   eggyylval._number = HUGE_VAL;
   eggyylval._string = yytext;
-  return NUMBER; 
+  return EGG_NUMBER; 
 }
 
 "-inf" {
@@ -720,7 +720,7 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   accept(); 
   eggyylval._number = -HUGE_VAL;
   eggyylval._string = yytext;
-  return NUMBER; 
+  return EGG_NUMBER; 
 }
 
 
@@ -728,12 +728,12 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   // Quoted string.
   accept();
   eggyylval._string = scan_quoted_string();
-  return STRING;
+  return EGG_STRING;
 }
 
 [^ \t\n\r{}"]+ { 
   // Unquoted string.
   accept();
   eggyylval._string = yytext;
-  return STRING;
+  return EGG_STRING;
 }

+ 11 - 11
panda/src/egg/parser.cxx.prebuilt

@@ -62,9 +62,9 @@
    /* Put the tokens into the symbol table, so that GDB and other debuggers
       know about them.  */
    enum yytokentype {
-     NUMBER = 258,
-     ULONG = 259,
-     STRING = 260,
+     EGG_NUMBER = 258,
+     EGG_ULONG = 259,
+     EGG_STRING = 260,
      BEZIERCURVE = 261,
      BFACE = 262,
      BILLBOARD = 263,
@@ -152,9 +152,9 @@
      START_PRIMITIVE_BODY = 345
    };
 #endif
-#define NUMBER 258
-#define ULONG 259
-#define STRING 260
+#define EGG_NUMBER 258
+#define EGG_ULONG 259
+#define EGG_STRING 260
 #define BEZIERCURVE 261
 #define BFACE 262
 #define BILLBOARD 263
@@ -759,11 +759,11 @@ static const unsigned short yyrline[] =
    First, the terminals, then, starting at YYNTOKENS, nonterminals. */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "NUMBER", "ULONG", "STRING", "BEZIERCURVE", 
-  "BFACE", "BILLBOARD", "BILLBOARDCENTER", "BINORMAL", "BUNDLE", "CLOSED", 
-  "COLLIDE", "COMMENT", "COMPONENT", "COORDSYSTEM", "CV", "DART", 
-  "DNORMAL", "DRGBA", "DUV", "DXYZ", "DCS", "DISTANCE", "DTREF", 
-  "DYNAMICVERTEXPOOL", "EXTERNAL_FILE", "FLIGHT", "GROUP", "HIP", 
+  "$end", "error", "$undefined", "EGG_NUMBER", "EGG_ULONG", "EGG_STRING", 
+  "BEZIERCURVE", "BFACE", "BILLBOARD", "BILLBOARDCENTER", "BINORMAL", 
+  "BUNDLE", "CLOSED", "COLLIDE", "COMMENT", "COMPONENT", "COORDSYSTEM", 
+  "CV", "DART", "DNORMAL", "DRGBA", "DUV", "DXYZ", "DCS", "DISTANCE", 
+  "DTREF", "DYNAMICVERTEXPOOL", "EXTERNAL_FILE", "FLIGHT", "GROUP", "HIP", 
   "INTANGENT", "JOINT", "KNOTS", "INCLUDE", "INSTANCE", "LINE", "LOOP", 
   "MATERIAL", "MATRIX3", "MATRIX4", "MODEL", "MREF", "NORMAL", 
   "NURBSCURVE", "NURBSSURFACE", "OBJECTTYPE", "ORDER", "OUTTANGENT", 

+ 6 - 6
panda/src/egg/parser.h.prebuilt

@@ -29,9 +29,9 @@
    /* Put the tokens into the symbol table, so that GDB and other debuggers
       know about them.  */
    enum yytokentype {
-     NUMBER = 258,
-     ULONG = 259,
-     STRING = 260,
+     EGG_NUMBER = 258,
+     EGG_ULONG = 259,
+     EGG_STRING = 260,
      BEZIERCURVE = 261,
      BFACE = 262,
      BILLBOARD = 263,
@@ -119,9 +119,9 @@
      START_PRIMITIVE_BODY = 345
    };
 #endif
-#define NUMBER 258
-#define ULONG 259
-#define STRING 260
+#define EGG_NUMBER 258
+#define EGG_ULONG 259
+#define EGG_STRING 260
 #define BEZIERCURVE 261
 #define BFACE 262
 #define BILLBOARD 263

+ 15 - 15
panda/src/egg/parser.yxx

@@ -142,9 +142,9 @@ egg_cleanup_parser() {
 
 %}
 
-%token <_number> NUMBER
-%token <_ulong> ULONG
-%token <_string> STRING
+%token <_number> EGG_NUMBER
+%token <_ulong> EGG_ULONG
+%token <_string> EGG_STRING
 
 %token BEZIERCURVE BFACE BILLBOARD BILLBOARDCENTER BINORMAL BUNDLE CLOSED
 %token COLLIDE COMMENT COMPONENT
@@ -1329,7 +1329,7 @@ group_body:
   int value = (int)$4;
   group->set_dcs_type(value!=0 ? EggGroup::DC_default : EggGroup::DC_none);
 }
-        | group_body DCS '{' STRING '}'
+        | group_body DCS '{' EGG_STRING '}'
 {
   // The special flavor of DCS, with { sync } or { nosync }.
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
@@ -1349,7 +1349,7 @@ group_body:
   int value = (int)$4;
   group->set_dart_type(value!=0 ? EggGroup::DT_default : EggGroup::DT_none);
 }
-        | group_body DART '{' STRING '}'
+        | group_body DART '{' EGG_STRING '}'
 {
   // The special flavor of DART, with { sync } or { nosync }.
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
@@ -2826,15 +2826,15 @@ optional_string:
  *
  */
 string:
-        NUMBER
+        EGG_NUMBER
 {
   $$ = $<_string>1;
 }
-        | ULONG
+        | EGG_ULONG
 {
   $$ = $<_string>1;
 }
-        | STRING
+        | EGG_STRING
         ;
 
 /*
@@ -2885,8 +2885,8 @@ repeated_string_body:
  *
  */
 real:
-        NUMBER
-        | ULONG
+        EGG_NUMBER
+        | EGG_ULONG
 {
   $$ = $1;
 }
@@ -2901,19 +2901,19 @@ real:
  *
  */
 real_or_string:
-        NUMBER
+        EGG_NUMBER
 {
   $<_number>$ = $1;
   $<_ulong>$ = (unsigned long)$1;
   $<_string>$ = $<_string>1;
 }
-        | ULONG
+        | EGG_ULONG
 {
   $<_number>$ = $1;
   $<_ulong>$ = $1;
   $<_string>$ = $<_string>1;
 }
-        | STRING
+        | EGG_STRING
 {
   $<_number>$ = 0.0;
   $<_ulong>$ = 0;
@@ -2930,7 +2930,7 @@ real_or_string:
  *
  */
 integer:
-        NUMBER
+        EGG_NUMBER
 {
   int i = (int)$1;
   if ((double)i != $1) {
@@ -2938,7 +2938,7 @@ integer:
     $$ = (double)i;
   }
 }
-        | ULONG
+        | EGG_ULONG
 {
   $$ = $1;
 }

+ 37 - 17
panda/src/express/Sources.pp

@@ -10,14 +10,16 @@
 
   #define SOURCES \
     atomicAdjustDummyImpl.h atomicAdjustDummyImpl.I atomicAdjust.h \
-    atomicAdjust.I atomicAdjustImpl.h atomicAdjustNsprImpl.h \
-    atomicAdjustNsprImpl.I \
+    atomicAdjust.I atomicAdjustImpl.h \
+    atomicAdjustNsprImpl.h atomicAdjustNsprImpl.I \
+    atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I \
     bigEndian.h buffer.I buffer.h \
     checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
     circBuffer.h clockObject.I clockObject.h \
     conditionVarDummyImpl.h conditionVarDummyImpl.I conditionVar.h \
-    conditionVar.I conditionVarImpl.h conditionVarNsprImpl.h \
-    conditionVarNsprImpl.I \
+    conditionVar.I conditionVarImpl.h \
+    conditionVarNsprImpl.h conditionVarNsprImpl.I \
+    conditionVarWin32Impl.h conditionVarWin32Impl.I \
     config_express.h \
     datagram.I datagram.h datagramGenerator.I \
     datagramGenerator.h \
@@ -37,7 +39,9 @@
     memoryUsagePointers.I memoryUsagePointers.h \
     multifile.I multifile.h \
     mutexDummyImpl.h mutexDummyImpl.I pmutex.h mutexHolder.h \
-    mutexHolder.I pmutex.I mutexImpl.h mutexNsprImpl.h mutexNsprImpl.I \
+    mutexHolder.I pmutex.I mutexImpl.h \
+    mutexNsprImpl.h mutexNsprImpl.I \
+    mutexWin32Impl.h mutexWin32Impl.I \
     namable.I \
     namable.h nativeNumericData.I nativeNumericData.h \
     numeric_types.h \
@@ -61,7 +65,9 @@
     subStream.I subStream.h subStreamBuf.h \
     textEncoder.h textEncoder.I \
     threadDummyImpl.h threadDummyImpl.I thread.h thread.I threadImpl.h \
-    threadNsprImpl.h threadNsprImpl.I threadPriority.h \
+    threadNsprImpl.h threadNsprImpl.I \
+    threadWin32Impl.h threadWin32Impl.I \
+    threadPriority.h \
     tokenBoard.I \
     tokenBoard.h trueClock.I trueClock.h \
     typedReferenceCount.I typedReferenceCount.h typedef.h \
@@ -81,9 +87,13 @@
     zStream.I zStream.h zStreamBuf.h
 
   #define INCLUDED_SOURCES  \
-    atomicAdjust.cxx atomicAdjustDummyImpl.cxx atomicAdjustNsprImpl.cxx \
+    atomicAdjust.cxx atomicAdjustDummyImpl.cxx \
+    atomicAdjustNsprImpl.cxx \
+    atomicAdjustWin32Impl.cxx \
     buffer.cxx checksumHashGenerator.cxx clockObject.cxx \
-    conditionVar.cxx conditionVarDummyImpl.cxx conditionVarNsprImpl.cxx \
+    conditionVar.cxx conditionVarDummyImpl.cxx \
+    conditionVarNsprImpl.cxx \
+    conditionVarWin32Impl.cxx \
     config_express.cxx datagram.cxx datagramGenerator.cxx \
     datagramIterator.cxx \
     datagramSink.cxx dcast.cxx \
@@ -94,7 +104,9 @@
     mainThread.cxx \
     memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
     memoryUsagePointers.cxx multifile.cxx \
-    pmutex.cxx mutexHolder.cxx mutexDummyImpl.cxx mutexNsprImpl.cxx \
+    pmutex.cxx mutexHolder.cxx mutexDummyImpl.cxx \
+    mutexNsprImpl.cxx \
+    mutexWin32Impl.cxx \
     namable.cxx \
     nativeNumericData.cxx \
     ordered_vector.cxx \
@@ -115,7 +127,9 @@
     stringDecoder.cxx \
     subStream.cxx subStreamBuf.cxx \
     textEncoder.cxx \
-    thread.cxx threadDummyImpl.cxx threadNsprImpl.cxx \
+    thread.cxx threadDummyImpl.cxx \
+    threadNsprImpl.cxx \
+    threadWin32Impl.cxx \
     trueClock.cxx \
     typedReferenceCount.cxx \
     unicodeLatinMap.cxx \
@@ -133,14 +147,16 @@
 
   #define INSTALL_HEADERS  \
     atomicAdjustDummyImpl.h atomicAdjustDummyImpl.I atomicAdjust.h \
-    atomicAdjust.I atomicAdjustImpl.h atomicAdjustNsprImpl.h \
-    atomicAdjustNsprImpl.I \
+    atomicAdjust.I atomicAdjustImpl.h \
+    atomicAdjustNsprImpl.h atomicAdjustNsprImpl.I \
+    atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I \
     bigEndian.h buffer.I buffer.h checksumHashGenerator.I  \
     checksumHashGenerator.h circBuffer.I circBuffer.h clockObject.I \
     clockObject.h \
     conditionVarDummyImpl.h conditionVarDummyImpl.I conditionVar.h \
-    conditionVar.I conditionVarImpl.h conditionVarNsprImpl.h \
-    conditionVarNsprImpl.I \
+    conditionVar.I conditionVarImpl.h \
+    conditionVarNsprImpl.h conditionVarNsprImpl.I \
+    conditionVarWin32Impl.h conditionVarWin32Impl.I \
     config_express.h datagram.I datagram.h \
     datagramGenerator.I datagramGenerator.h \
     datagramIterator.I datagramIterator.h \
@@ -158,7 +174,9 @@
     memoryUsagePointerCounts.h memoryUsagePointers.I \
     memoryUsagePointers.h multifile.I multifile.h \
     mutexDummyImpl.h mutexDummyImpl.I pmutex.h mutexHolder.h \
-    mutexHolder.I pmutex.I mutexImpl.h mutexNsprImpl.h mutexNsprImpl.I \
+    mutexHolder.I pmutex.I mutexImpl.h \
+    mutexNsprImpl.h mutexNsprImpl.I \
+    mutexWin32Impl.h mutexWin32Impl.I \
     namable.I namable.h \
     nativeNumericData.I nativeNumericData.h numeric_types.h \
     ordered_vector.h ordered_vector.I ordered_vector.T \
@@ -181,7 +199,9 @@
     subStream.I subStream.h subStreamBuf.h \
     textEncoder.h textEncoder.I \
     threadDummyImpl.h threadDummyImpl.I thread.h thread.I threadImpl.h \
-    threadNsprImpl.h threadNsprImpl.I threadPriority.h \
+    threadNsprImpl.h threadNsprImpl.I \
+    threadWin32Impl.h threadWin32Impl.I \
+    threadPriority.h \
     tokenBoard.I \
     tokenBoard.h trueClock.I trueClock.h \
     typedReferenceCount.I \
@@ -258,7 +278,7 @@
 #begin test_bin_target
   #define TARGET test_diners
   #define LOCAL_LIBS $[LOCAL_LIBS] express
-  #define OTHER_LIBS dtoolutil:c dtool:m pystub
+  #define OTHER_LIBS dtoolutil:c dtool:m dtoolconfig:m pystub
 
   #define SOURCES \
     test_diners.cxx

+ 5 - 0
panda/src/express/atomicAdjustImpl.h

@@ -27,6 +27,11 @@
 #include "atomicAdjustDummyImpl.h"
 typedef AtomicAdjustDummyImpl AtomicAdjustImpl;
 
+#elif defined(THREAD_WIN32_IMPL)
+
+#include "atomicAdjustWin32Impl.h"
+typedef AtomicAdjustWin32Impl AtomicAdjustImpl;
+
 #elif defined(THREAD_NSPR_IMPL)
 
 #include "atomicAdjustNsprImpl.h"

+ 60 - 0
panda/src/express/atomicAdjustWin32Impl.I

@@ -0,0 +1,60 @@
+// Filename: atomicAdjustWin32Impl.I
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: AtomicAdjustWin32Impl::inc
+//       Access: Public, Static
+//  Description: Atomically increments the indicated variable and
+//               returns the new value.
+////////////////////////////////////////////////////////////////////
+INLINE int AtomicAdjustWin32Impl::
+inc(int &var) {
+  nassertr(sizeof(int) == sizeof(LONG), ++var);
+  return InterlockedIncrement((LONG *)&var);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AtomicAdjustWin32Impl::dec
+//       Access: Public, Static
+//  Description: Atomically decrements the indicated variable and
+//               returns the new value.
+////////////////////////////////////////////////////////////////////
+INLINE int AtomicAdjustWin32Impl::
+dec(int &var) {
+  nassertr(sizeof(int) == sizeof(LONG), --var);
+  return InterlockedDecrement((LONG *)&var);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AtomicAdjustWin32Impl::set
+//       Access: Public, Static
+//  Description: Atomically changes the indicated variable and
+//               returns the original value.
+////////////////////////////////////////////////////////////////////
+INLINE int AtomicAdjustWin32Impl::
+set(int &var, int new_value) {
+#ifndef NDEBUG
+  nassertd(sizeof(int) == sizeof(LONG)) {
+    int temp = var;
+    var = new_value;
+    return temp;
+  }
+#endif
+  return InterlockedExchange((LONG *)&var, new_value);
+}

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

@@ -0,0 +1,25 @@
+// Filename: atomicAdjustWin32Impl.cxx
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "selectThreadImpl.h"
+
+#ifdef THREAD_WIN32_IMPL
+
+#include "atomicAdjustWin32Impl.h"
+
+#endif  // THREAD_WIN32_IMPL

+ 47 - 0
panda/src/express/atomicAdjustWin32Impl.h

@@ -0,0 +1,47 @@
+// Filename: atomicAdjustWin32Impl.h
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef ATOMICADJUSTWIN32IMPL_H
+#define ATOMICADJUSTWIN32IMPL_H
+
+#include "pandabase.h"
+#include "selectThreadImpl.h"
+
+#ifdef THREAD_WIN32_IMPL
+
+#include "notify.h"
+
+#include <windows.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : AtomicAdjustWin32Impl
+// Description : Uses Windows native calls to implement atomic
+//               adjustments.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS AtomicAdjustWin32Impl {
+public:
+  INLINE static int inc(int &var);
+  INLINE static int dec(int &var);
+  INLINE static int set(int &var, int new_value);
+};
+
+#include "atomicAdjustWin32Impl.I"
+
+#endif  // THREAD_WIN32_IMPL
+
+#endif

+ 6 - 20
panda/src/express/conditionVar.I

@@ -101,15 +101,17 @@ get_mutex() {
 //               still be held when wait() returns.  However, it will
 //               be temporarily released during the wait() call
 //               itself.
+//
+//               This is defined as an inline method only when
+//               CHECK_REENTRANT_MUTEX is not defined.  If
+//               CHECK_REENTRANT_MUTEX is defined, it is an
+//               out-of-line method, just to avoid circular
+//               dependencies on #include files.
 ////////////////////////////////////////////////////////////////////
 INLINE void ConditionVar::
 wait() {
   nassertv(_mutex.debug_is_locked());
   _impl.wait();
-
-#ifdef CHECK_REENTRANT_MUTEX
-  _mutex._locking_thread = Thread::get_current_thread();
-#endif
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -133,19 +135,3 @@ signal() {
   nassertv(_mutex.debug_is_locked());
   _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() {
-  nassertv(_mutex.debug_is_locked());
-  _impl.signal_all();
-}

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

@@ -17,3 +17,45 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "conditionVar.h"
+#include "thread.h"
+
+#ifdef CHECK_REENTRANT_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.
+//
+//               This is defined as an inline method only when
+//               CHECK_REENTRANT_MUTEX is not defined.  If
+//               CHECK_REENTRANT_MUTEX is defined, it is an
+//               out-of-line method, just to avoid circular
+//               dependencies on #include files.
+////////////////////////////////////////////////////////////////////
+void ConditionVar::
+wait() {
+  nassertv(_mutex.debug_is_locked());
+  _impl.wait();
+
+  _mutex._locking_thread = Thread::get_current_thread();
+}
+#endif  // CHECK_REENTRANT_MUTEX

+ 4 - 2
panda/src/express/conditionVar.h

@@ -22,7 +22,6 @@
 #include "pandabase.h"
 #include "pmutex.h"
 #include "conditionVarImpl.h"
-#include "thread.h"
 #include "notify.h"
 
 ////////////////////////////////////////////////////////////////////
@@ -48,9 +47,12 @@ private:
 public:
   INLINE Mutex &get_mutex();
 
+#ifdef CHECK_REENTRANT_MUTEX
+  void wait();
+#else  // CHECK_REENTRANT_MUTEX
   INLINE void wait();
+#endif  // CHECK_REENTRANT_MUTEX
   INLINE void signal();
-  INLINE void signal_all();
 
 private:
   Mutex &_mutex;

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

@@ -27,6 +27,11 @@
 #include "conditionVarDummyImpl.h"
 typedef ConditionVarDummyImpl ConditionVarImpl;
 
+#elif defined(THREAD_WIN32_IMPL)
+
+#include "conditionVarWin32Impl.h"
+typedef ConditionVarWin32Impl ConditionVarImpl;
+
 #elif defined(THREAD_NSPR_IMPL)
 
 #include "conditionVarNsprImpl.h"

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

@@ -59,14 +59,3 @@ 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);
-}

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

@@ -42,7 +42,6 @@ public:
 
   INLINE void wait();
   INLINE void signal();
-  INLINE void signal_all();
 
 private:
   PRCondVar *_cvar;

+ 66 - 0
panda/src/express/conditionVarWin32Impl.I

@@ -0,0 +1,66 @@
+// Filename: conditionVarWin32Impl.I
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarWin32Impl::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVarWin32Impl::
+ConditionVarWin32Impl(MutexWin32Impl &mutex) {
+  _external_mutex = &mutex._lock;
+
+  // Create an auto-reset event.
+  _event_signal = CreateEvent(NULL, false, false, NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarWin32Impl::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ConditionVarWin32Impl::
+~ConditionVarWin32Impl() {
+  CloseHandle(_event_signal);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarWin32Impl::wait
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVarWin32Impl::
+wait() {
+  LeaveCriticalSection(_external_mutex);
+
+  DWORD result = WaitForSingleObject(_event_signal, INFINITE);
+  nassertv(result == WAIT_OBJECT_0);
+
+  EnterCriticalSection(_external_mutex);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConditionVarWin32Impl::signal
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConditionVarWin32Impl::
+signal() {
+  SetEvent(_event_signal);
+}

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

@@ -0,0 +1,25 @@
+// Filename: conditionVarWin32Impl.cxx
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "selectThreadImpl.h"
+
+#ifdef THREAD_WIN32_IMPL
+
+#include "conditionVarWin32Impl.h"
+
+#endif  // THREAD_WIN32_IMPL

+ 66 - 0
panda/src/express/conditionVarWin32Impl.h

@@ -0,0 +1,66 @@
+// Filename: conditionVarWin32Impl.h
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONDITIONVARWIN32IMPL_H
+#define CONDITIONVARWIN32IMPL_H
+
+#include "pandabase.h"
+#include "selectThreadImpl.h"
+
+#ifdef THREAD_WIN32_IMPL
+
+#include "mutexWin32Impl.h"
+#include "notify.h"
+
+#include <prcvar.h>
+
+class MutexWin32Impl;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ConditionVarWin32Impl
+// Description : 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 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_PANDAEXPRESS ConditionVarWin32Impl {
+public:
+  INLINE ConditionVarWin32Impl(MutexWin32Impl &mutex);
+  INLINE ~ConditionVarWin32Impl();
+
+  INLINE void wait();
+  INLINE void signal();
+
+private:
+  CRITICAL_SECTION *_external_mutex;
+  HANDLE _event_signal;
+};
+
+#include "conditionVarWin32Impl.I"
+
+#endif  // THREAD_WIN32_IMPL
+
+#endif

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

@@ -1,12 +1,14 @@
 #include "atomicAdjust.cxx"
 #include "atomicAdjustDummyImpl.cxx"
 #include "atomicAdjustNsprImpl.cxx"
+#include "atomicAdjustWin32Impl.cxx"
 #include "buffer.cxx"
 #include "checksumHashGenerator.cxx"
 #include "clockObject.cxx"
 #include "conditionVar.cxx"
 #include "conditionVarDummyImpl.cxx"
 #include "conditionVarNsprImpl.cxx"
+#include "conditionVarWin32Impl.cxx"
 #include "config_express.cxx"
 #include "datagram.cxx"
 #include "datagramGenerator.cxx"
@@ -28,6 +30,7 @@
 #include "mutexHolder.cxx"
 #include "mutexDummyImpl.cxx"
 #include "mutexNsprImpl.cxx"
+#include "mutexWin32Impl.cxx"
 #include "namable.cxx"
 #include "nativeNumericData.cxx"
 #include "ordered_vector.cxx"

+ 1 - 0
panda/src/express/express_composite2.cxx

@@ -21,6 +21,7 @@
 #include "thread.cxx"
 #include "threadDummyImpl.cxx"
 #include "threadNsprImpl.cxx"
+#include "threadWin32Impl.cxx"
 #include "trueClock.cxx"
 #include "typedReferenceCount.cxx"
 #include "unicodeLatinMap.cxx"

+ 8 - 0
panda/src/express/mutexImpl.h

@@ -26,11 +26,19 @@
 
 #include "mutexDummyImpl.h"
 typedef MutexDummyImpl MutexImpl;
+#undef MUTEX_REENTRANT
+
+#elif defined(THREAD_WIN32_IMPL)
+
+#include "mutexWin32Impl.h"
+typedef MutexWin32Impl MutexImpl;
+#define MUTEX_REENTRANT 1  // Win32 Mutexes are already reentrant.
 
 #elif defined(THREAD_NSPR_IMPL)
 
 #include "mutexNsprImpl.h"
 typedef MutexNsprImpl MutexImpl;
+#undef MUTEX_REENTRANT
 
 #endif
 

+ 58 - 0
panda/src/express/mutexWin32Impl.I

@@ -0,0 +1,58 @@
+// Filename: mutexWin32Impl.I
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexWin32Impl::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE MutexWin32Impl::
+MutexWin32Impl() {
+  InitializeCriticalSection(&_lock);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexWin32Impl::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE MutexWin32Impl::
+~MutexWin32Impl() {
+  DeleteCriticalSection(&_lock);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexWin32Impl::lock
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void MutexWin32Impl::
+lock() {
+  EnterCriticalSection(&_lock);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MutexWin32Impl::release
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void MutexWin32Impl::
+release() {
+  LeaveCriticalSection(&_lock);
+}

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

@@ -0,0 +1,25 @@
+// Filename: mutexWin32Impl.cxx
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "selectThreadImpl.h"
+
+#ifdef THREAD_WIN32_IMPL
+
+#include "mutexWin32Impl.h"
+
+#endif  // THREAD_WIN32_IMPL

+ 52 - 0
panda/src/express/mutexWin32Impl.h

@@ -0,0 +1,52 @@
+// Filename: mutexWin32Impl.h
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MUTEXWIN32IMPL_H
+#define MUTEXWIN32IMPL_H
+
+#include "pandabase.h"
+#include "selectThreadImpl.h"
+
+#ifdef THREAD_WIN32_IMPL
+
+#include "notify.h"
+
+#include <windows.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : MutexWin32Impl
+// Description : Uses Windows native calls to implement a mutex.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS MutexWin32Impl {
+public:
+  INLINE MutexWin32Impl();
+  INLINE ~MutexWin32Impl();
+
+  INLINE void lock();
+  INLINE void release();
+
+private:
+  CRITICAL_SECTION _lock;
+  friend class ConditionVarWin32Impl;
+};
+
+#include "mutexWin32Impl.I"
+
+#endif  // THREAD_WIN32_IMPL
+
+#endif

+ 12 - 0
panda/src/express/pmutex.h

@@ -30,6 +30,18 @@ class Thread;
 //               thread can hold ("lock") a mutex at any given time;
 //               other threads trying to grab the mutex will block
 //               until the holding thread releases it.
+//
+//               The standard mutex is not reentrant: a thread may not
+//               attempt to lock it twice.  Although this may happen
+//               to work on some platforms (e.g. Win32), it will not
+//               work on all platforms; on some platforms, a thread
+//               can deadlock itself by attempting to lock the same
+//               mutex twice.  If your code requires a reentrant
+//               mutex, use the ReMutex class instead.  When this code
+//               is compiled with CHECK_REENTRANT_MUTEX true, then it
+//               will enable assertion checks to ensure that a
+//               particular thread doesn't try to lock the same mutex
+//               twice.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDAEXPRESS Mutex {
 public:

+ 103 - 64
panda/src/express/reMutex.I

@@ -17,14 +17,104 @@
 ////////////////////////////////////////////////////////////////////
 
 
-// Most of the methods in this class are stubbed out in the
-// THREAD_DUMMY_IMPL case, especially when CHECK_REENTRANT_MUTEX is
-// not defined.  In this case, we're not performing any actual locking
-// or verification, so there's no need to do anything at all here.
+#ifdef MUTEX_REENTRANT
+// In this branch, the ReMutex class is implemented as a thin wrapper
+// around the native MutexImpl class (which is already reentrant
+// anyway).
 
-#if !defined(THREAD_DUMMY_IMPL) || defined(CHECK_REENTRANT_MUTEX)
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutex::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ReMutex::
+ReMutex() {
+}
 
-// In this branch, the mutex is actually implemented.
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutex::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ReMutex::
+~ReMutex() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutex::Copy Constructor
+//       Access: Private
+//  Description: Do not attempt to copy mutexes.
+////////////////////////////////////////////////////////////////////
+INLINE ReMutex::
+ReMutex(const ReMutex &copy) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutex::Copy Assignment Operator
+//       Access: Private
+//  Description: Do not attempt to copy mutexes.
+////////////////////////////////////////////////////////////////////
+INLINE void ReMutex::
+operator = (const ReMutex &copy) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutex::lock
+//       Access: Public
+//  Description: Grabs the mutex if it is available.  If it is not
+//               available, blocks until it becomes available, then
+//               grabs it.  In either case, the function does not
+//               return until the mutex is held; you should then call
+//               unlock().
+//
+//               This method is considered const so that you can lock
+//               and unlock const mutexes, mainly to allow thread-safe
+//               access to otherwise const data.
+//
+//               Also see MutexHolder.
+////////////////////////////////////////////////////////////////////
+INLINE void ReMutex::
+lock() const {
+  ((MutexImpl &)_impl).lock();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutex::release
+//       Access: Public
+//  Description: Releases the mutex.  It is an error to call this if
+//               the mutex was not already locked.
+//
+//               This method is considered const so that you can lock
+//               and unlock const mutexes, mainly to allow thread-safe
+//               access to otherwise const data.
+////////////////////////////////////////////////////////////////////
+INLINE void ReMutex::
+release() const {
+  ((MutexImpl &)_impl).release();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ReMutex::debug_is_locked
+//       Access: Public
+//  Description: Returns true if the current thread has locked the
+//               Mutex, false otherwise.  This method is only
+//               meaningful if CHECK_REENTRANT_MUTEX is defined;
+//               otherwise, it always returns true.
+////////////////////////////////////////////////////////////////////
+INLINE bool ReMutex::
+debug_is_locked() const {
+  return true;
+}
+
+
+#elif !defined(THREAD_DUMMY_IMPL) || defined(CHECK_REENTRANT_MUTEX)
+
+// In this branch, the ReMutex object is implemented as a heavy
+// wrapper around the Mutex and ConditionVar classes, to impose
+// reentrant semantics where the underlying MutexImpl doesn't provide
+// them.
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ReMutex::Constructor
@@ -103,46 +193,18 @@ release() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ReMutex::is_locked
+//     Function: ReMutex::debug_is_locked
 //       Access: Public
 //  Description: Returns true if *this thread* already holds the lock,
 //               false if no one holds the lock or the lock is held by
 //               some other thread.
 ////////////////////////////////////////////////////////////////////
 INLINE bool ReMutex::
-is_locked() const {
+debug_is_locked() const {
   MutexHolder holder(_mutex);
   return (_locking_thread == Thread::get_current_thread());
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: ReMutex::get_lock_count
-//       Access: Public
-//  Description: Returns the number of times that *this thread* has
-//               grabbed the lock.  Returns 0 if some other thread is
-//               currently holding the lock.
-////////////////////////////////////////////////////////////////////
-INLINE int ReMutex::
-get_lock_count() const {
-  MutexHolder holder(_mutex);
-  if (_locking_thread == Thread::get_current_thread()) {
-    return _lock_count;
-  }
-  return 0;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ReMutex::debug_is_locked
-//       Access: Public
-//  Description: The same as is_locked().  This method name is
-//               provided just to maintain symmetry with Mutex (which
-//               doesn't provide an is_locked() method).
-////////////////////////////////////////////////////////////////////
-INLINE bool ReMutex::
-debug_is_locked() const {
-  return is_locked();
-}
-
 #else  // !THREAD_DUMMY_IMPL || CHECK_REENTRANT_MUTEX
 
 // In this branch, the mutex is stubbed out to do nothing.
@@ -218,37 +280,13 @@ INLINE void ReMutex::
 release() const {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: ReMutex::is_locked
-//       Access: Public
-//  Description: Returns true if *this thread* already holds the lock,
-//               false if no one holds the lock or the lock is held by
-//               some other thread.
-////////////////////////////////////////////////////////////////////
-INLINE bool ReMutex::
-is_locked() const {
-  // In the stub version, this method always returns true.
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ReMutex::get_lock_count
-//       Access: Public
-//  Description: Returns the number of times that *this thread* has
-//               grabbed the lock.  Returns 0 if some other thread is
-//               currently holding the lock.
-////////////////////////////////////////////////////////////////////
-INLINE int ReMutex::
-get_lock_count() const {
-  return 0;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: ReMutex::debug_is_locked
 //       Access: Public
-//  Description: The same as is_locked().  This method name is
-//               provided just to maintain symmetry with Mutex (which
-//               doesn't provide an is_locked() method).
+//  Description: Returns true if the current thread has locked the
+//               Mutex, false otherwise.  This method is only
+//               meaningful if CHECK_REENTRANT_MUTEX is defined;
+//               otherwise, it always returns true.
 ////////////////////////////////////////////////////////////////////
 INLINE bool ReMutex::
 debug_is_locked() const {
@@ -256,3 +294,4 @@ debug_is_locked() const {
 }
 
 #endif  // !THREAD_DUMMY_IMPL || CHECK_REENTRANT_MUTEX
+

+ 4 - 0
panda/src/express/reMutex.cxx

@@ -18,6 +18,8 @@
 
 #include "reMutex.h"
 
+#ifndef MUTEX_REENTRANT
+
 // Most of the methods in this class are stubbed out in the
 // THREAD_DUMMY_IMPL case, especially when CHECK_REENTRANT_MUTEX is
 // not defined.  In this case, we're not performing any actual locking
@@ -78,3 +80,5 @@ do_release() {
 }
 
 #endif  // !THREAD_DUMMY_IMPL || CHECK_REENTRANT_MUTEX
+
+#endif  // MUTEX_REENTRANT

+ 6 - 5
panda/src/express/reMutex.h

@@ -25,7 +25,6 @@
 #include "mutexHolder.h"
 #include "thread.h"
 
-
 ////////////////////////////////////////////////////////////////////
 //       Class : ReMutex
 // Description : A reentrant mutex.  This kind of mutex can be locked
@@ -45,13 +44,15 @@ public:
   INLINE void lock() const;
   INLINE void release() const;
 
-  INLINE bool is_locked() const;
-  INLINE int get_lock_count() const;
-
   INLINE bool debug_is_locked() const;
 
 private:
-#if !defined(THREAD_DUMMY_IMPL) || defined(CHECK_REENTRANT_MUTEX)
+#ifdef MUTEX_REENTRANT
+  // If the native Mutex implementation is already reentrant, just use
+  // that.
+  MutexImpl _impl;
+
+#elif !defined(THREAD_DUMMY_IMPL) || defined(CHECK_REENTRANT_MUTEX)
   void do_lock();
   void do_release();
 

+ 6 - 0
panda/src/express/selectThreadImpl.h

@@ -32,6 +32,12 @@
 // With threading disabled, use the do-nothing implementation.
 #define THREAD_DUMMY_IMPL 1
 
+#elif defined(WIN32)
+
+// In Windows, use the native threading library.
+#define THREAD_WIN32_IMPL 1
+#define THREAD_NSPR_IMPL 1  // Temp while developing.
+
 #elif defined(HAVE_NSPR)
 
 // If NSPR is available, use that.

+ 91 - 86
panda/src/express/test_diners.cxx

@@ -27,25 +27,28 @@
 #include "pointerTo.h"
 
 #ifdef WIN32_VC
+// Under Windows, the rand() function seems to return a sequence
+// per-thread, so we use this trick to set each thread to a different
+// seed.
 static int last_rand = 0;
 #endif /* __WIN32__ */
 
+Mutex print_mutex;
+
+#define PRINTMSG(x) { MutexHolder l(print_mutex); x; }
+
 Mutex rand_mutex;
 
 static double random_f(double max)
 {
-   MutexHolder l(rand_mutex);
-   int i = rand();
+  MutexHolder l(rand_mutex);
+  int i = rand();
 #ifdef WIN32_VC
-   last_rand = i;
+  last_rand = i;
 #endif /* __WIN32__ */
-   return max * (double)i / (double)RAND_MAX;
+  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
@@ -65,88 +68,90 @@ class philosopher;
 PT(philosopher) phils[N_DINERS];
 
 class philosopher : public Thread {
-   private:
-     int _id;
-     void thread_main() {
+private:
+  int _id;
+  void thread_main() {
 #ifdef WIN32_VC
-         rand_mutex.lock();
-         srand(last_rand);
-         rand_mutex.release();
+    rand_mutex.lock();
+    srand(last_rand);
+    rand_mutex.release();
+    random_f(1.0);
 #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 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", "a") {
+    _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;
-   }
+  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 told, no one has left the room!!!"
+               << endl);
+      PRINTMSG(cerr << "I give up!" << endl);
+      Thread::prepare_for_exit();
+      exit(1);
+    }
+    phils[i] = new philosopher(i);
+    phils[i]->start(TP_normal, false, false);
+    ++room_occupancy;
+  }
 }

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

@@ -115,6 +115,7 @@ private:
 
   friend class ThreadDummyImpl;
   friend class ThreadNsprImpl;
+  friend class ThreadWin32Impl;
 };
 
 INLINE ostream &operator << (ostream &out, const Thread &thread);

+ 5 - 0
panda/src/express/threadImpl.h

@@ -27,6 +27,11 @@
 #include "threadDummyImpl.h"
 typedef ThreadDummyImpl ThreadImpl;
 
+#elif defined(THREAD_WIN32_IMPL)
+
+#include "threadWin32Impl.h"
+typedef ThreadWin32Impl ThreadImpl;
+
 #elif defined(THREAD_NSPR_IMPL)
 
 #include "threadNsprImpl.h"

+ 8 - 2
panda/src/express/threadNsprImpl.cxx

@@ -150,7 +150,11 @@ start(ThreadPriority priority, bool global, bool joinable) {
 ////////////////////////////////////////////////////////////////////
 //     Function: ThreadNsprImpl::interrupt
 //       Access: Public
-//  Description: 
+//  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 ThreadNsprImpl::
 interrupt() {
@@ -162,7 +166,9 @@ interrupt() {
 ////////////////////////////////////////////////////////////////////
 //     Function: ThreadNsprImpl::join
 //       Access: Public
-//  Description: 
+//  Description: Blocks the calling process until the thread
+//               terminates.  If the thread has already terminated,
+//               this returns immediately.
 ////////////////////////////////////////////////////////////////////
 void ThreadNsprImpl::
 join() {

+ 91 - 0
panda/src/express/threadWin32Impl.I

@@ -0,0 +1,91 @@
+// Filename: threadWin32Impl.I
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE ThreadWin32Impl::
+ThreadWin32Impl(Thread *parent_obj) :
+  _cv(_mutex),
+  _parent_obj(parent_obj)
+{
+  _thread = 0;
+  _joinable = false;
+  _status = S_new;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::prepare_for_exit
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ThreadWin32Impl::
+prepare_for_exit() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::Constructor
+//       Access: Public, Static
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE Thread *ThreadWin32Impl::
+get_current_thread() {
+  if (!_got_pt_ptr_index) {
+    init_pt_ptr_index();
+  }
+  return (Thread *)TlsGetValue(_pt_ptr_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::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.
+////////////////////////////////////////////////////////////////////
+INLINE void ThreadWin32Impl::
+bind_thread(Thread *thread) {
+  if (!_got_pt_ptr_index) {
+    init_pt_ptr_index();
+  }
+  BOOL result = TlsSetValue(_pt_ptr_index, thread);
+  nassertv(result);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::is_threading_supported
+//       Access: Public, Static
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE bool ThreadWin32Impl::
+is_threading_supported() {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::sleep
+//       Access: Public, Static
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ThreadWin32Impl::
+sleep(double seconds) {
+  Sleep((int)(seconds * 1000));
+}

+ 202 - 0
panda/src/express/threadWin32Impl.cxx

@@ -0,0 +1,202 @@
+// Filename: threadWin32Impl.cxx
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "threadWin32Impl.h"
+#include "selectThreadImpl.h"
+
+#ifdef THREAD_WIN32_IMPL
+
+#include "pointerTo.h"
+#include "config_express.h"
+#include "mutexHolder.h"
+
+DWORD ThreadWin32Impl::_pt_ptr_index = 0;
+bool ThreadWin32Impl::_got_pt_ptr_index = false;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ThreadWin32Impl::
+~ThreadWin32Impl() {
+  if (thread_cat.is_debug()) {
+    thread_cat.debug() << "Deleting thread " << _parent_obj->get_name() << "\n";
+  }
+
+  CloseHandle(_thread);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::start
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool ThreadWin32Impl::
+start(ThreadPriority priority, bool global, bool joinable) {
+  MutexHolder holder(_mutex);
+  if (thread_cat.is_debug()) {
+    thread_cat.debug() << "Starting thread " << _parent_obj->get_name() << "\n";
+  }
+  nassertr(_status == S_new, false);
+  nassertr(_thread == 0, false);
+  _joinable = joinable;
+  _status = S_start_called;
+
+  if (!_got_pt_ptr_index) {
+    init_pt_ptr_index();
+  }
+
+  // Increment the parent object's reference count first.  The thread
+  // will eventually decrement it when it terminates.
+  _parent_obj->ref();
+  _thread = 
+    CreateThread(NULL, 0, &root_func, (void *)this, 0, &_thread_id);
+
+  if (_thread_id == 0) {
+    // Oops, we couldn't start the thread.  Be sure to decrement the
+    // reference count we incremented above, and return false to
+    // indicate failure.
+    unref_delete(_parent_obj);
+    return false;
+  }
+
+  // Thread was successfully started.  Set the priority as specified.
+  switch (priority) {
+  case TP_low:
+    SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL);
+    break;
+
+  case TP_normal:
+    SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL);
+    break;
+
+  case TP_high:
+    SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL);
+    break;
+
+  case TP_urgent:
+    SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST);
+    break;
+
+  default:
+    nassertr(false, false);
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::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 ThreadWin32Impl::
+interrupt() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::join
+//       Access: Public
+//  Description: Blocks the calling process until the thread
+//               terminates.  If the thread has already terminated,
+//               this returns immediately.
+////////////////////////////////////////////////////////////////////
+void ThreadWin32Impl::
+join() {
+  MutexHolder holder(_mutex);
+  nassertv(_joinable);
+  nassertv(_status != S_new);
+
+  while (_status != S_finished) {
+    _cv.wait();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::root_func
+//       Access: Private, Static
+//  Description: The entry point of each thread.
+////////////////////////////////////////////////////////////////////
+DWORD ThreadWin32Impl::
+root_func(LPVOID data) {
+  ThreadWin32Impl *self = (ThreadWin32Impl *)data;
+  BOOL result = TlsSetValue(_pt_ptr_index, self->_parent_obj);
+  nassertr(result, 1);
+
+  {
+    MutexHolder holder(self->_mutex);
+    nassertr(self->_status == S_start_called, 1);
+    self->_status = S_running;
+    self->_cv.signal();
+  }
+
+  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";
+  }
+
+  {
+    MutexHolder holder(self->_mutex);
+    nassertr(self->_status == S_running, 1);
+    self->_status = S_finished;
+    self->_cv.signal();
+  }
+
+  // Now drop the parent object reference that we grabbed in start().
+  // This might delete the parent object, and in turn, delete the
+  // ThreadWin32Impl object.
+  unref_delete(self->_parent_obj);
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ThreadWin32Impl::init_pt_ptr_index
+//       Access: Private, Static
+//  Description: Allocate a new index to store the Thread parent
+//               pointer as a piece of per-thread private data.
+////////////////////////////////////////////////////////////////////
+void ThreadWin32Impl::
+init_pt_ptr_index() {
+  nassertv(!_got_pt_ptr_index);
+
+  _pt_ptr_index = TlsAlloc();
+  if (_pt_ptr_index == TLS_OUT_OF_INDEXES) {
+    thread_cat.error()
+      << "Unable to associate Thread pointers with threads.\n";
+    return;
+  }
+
+  _got_pt_ptr_index = true;
+
+  // Assume that we must be in the main thread, since this method must
+  // be called before the first thread is spawned.
+  Thread *main_thread_obj = Thread::get_main_thread();
+  BOOL result = TlsSetValue(_pt_ptr_index, main_thread_obj);
+  nassertv(result);
+}
+
+#endif  // THREAD_WIN32_IMPL

+ 83 - 0
panda/src/express/threadWin32Impl.h

@@ -0,0 +1,83 @@
+// Filename: threadWin32Impl.h
+// Created by:  drose (07Feb06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef THREADWIN32IMPL_H
+#define THREADWIN32IMPL_H
+
+#include "pandabase.h"
+#include "selectThreadImpl.h"
+
+#ifdef THREAD_WIN32_IMPL
+
+#include "notify.h"
+#include "threadPriority.h"
+#include "pmutex.h"
+#include "conditionVar.h"
+
+#include <windows.h>
+
+class Thread;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ThreadWin32Impl
+// Description : Uses native Windows calls to implement a thread.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS ThreadWin32Impl {
+public:
+  INLINE ThreadWin32Impl(Thread *parent_obj);
+  ~ThreadWin32Impl();
+
+  bool start(ThreadPriority priority, bool global, bool joinable);
+  void interrupt();
+  void join();
+
+  INLINE static void prepare_for_exit();
+
+  INLINE static Thread *get_current_thread();
+  INLINE static void bind_thread(Thread *thread);
+  INLINE static bool is_threading_supported();
+  INLINE static void sleep(double seconds);
+
+private:
+  static DWORD WINAPI root_func(LPVOID data);
+  static void init_pt_ptr_index();
+
+  enum Status {
+    S_new,
+    S_start_called,
+    S_running,
+    S_finished
+  };
+
+  Mutex _mutex;
+  ConditionVar _cv;
+  Thread *_parent_obj;
+  HANDLE _thread;
+  DWORD _thread_id;
+  bool _joinable;
+  Status _status;
+
+  static DWORD _pt_ptr_index;
+  static bool _got_pt_ptr_index;
+};
+
+#include "threadWin32Impl.I"
+
+#endif  // THREAD_WIN32_IMPL
+
+#endif

+ 2 - 8
panda/src/putil/pipelineCyclerTrueImpl.I

@@ -191,10 +191,7 @@ cheat() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int PipelineCyclerTrueImpl::
 get_read_count() const {
-  int pipeline_stage = Thread::get_current_thread()->get_pipeline_stage();
-  nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, 0);
-  _lock.lock();
-  return _lock.get_lock_count();
+  return 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -207,10 +204,7 @@ get_read_count() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int PipelineCyclerTrueImpl::
 get_write_count() const {
-  int pipeline_stage = Thread::get_current_thread()->get_pipeline_stage();
-  nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, 0);
-  _lock.lock();
-  return _lock.get_lock_count();
+  return 0;
 }
 
 ////////////////////////////////////////////////////////////////////