Index: thread.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/thread.cc,v
retrieving revision 1.50
diff -u -p -r1.50 thread.cc
--- thread.cc	2001/09/25 11:45:25	1.50
+++ thread.cc	2001/09/28 07:36:57
@@ -303,6 +303,9 @@ MTinterface::Init (int forked)
   if (forked)
     return;
 
+  /* maybe this should be elsewhere and fixed up explicitly? */
+  shm_head = NULL;
+
   mutexs = NULL;
   conds  = NULL;
   semaphores = NULL;
@@ -459,6 +462,7 @@ pthread_cond::~pthread_cond ()
 void
 pthread_cond::BroadCast ()
 {
+  /* TODO: implement the same race fix as Signal has */
   if (pthread_mutex_lock (&cond_access))
     system_printf ("Failed to lock condition variable access mutex, this %0p\n", this);
   int count = waiting;
@@ -490,7 +494,32 @@ pthread_cond::Signal ()
 		       this);
       return;
     }
+  int temp = waiting;
+  if (!temp)
+    /* nothing to signal */
+    {
+      if (pthread_mutex_unlock (&cond_access))
+	system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this);
+      return;
+    }
   PulseEvent (win32_obj_id);
+  /* No one can start waiting until we release the condition access mutex */
+  /* The released thread will decrement waiting when it gets a time slice...
+     without waiting for the access mutex
+   */
+  int spins = 10;
+  while (InterlockedIncrement (&waiting) != (temp - 1) && spins)
+    {
+      InterlockedDecrement (&waiting);
+      /* give up the cpu to force a context switch. */
+      Sleep (0);
+      if (spins == 5)
+	/* we've had 5 timeslices, and the woekn thread still hasn't done it's
+	 * thing - maybe we raced it with the event? */
+	PulseEvent (win32_obj_id);
+      spins--;
+    }
+  InterlockedDecrement (&waiting);
   if (pthread_mutex_unlock (&cond_access))
     system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this);
 }
@@ -804,9 +833,9 @@ verifyable_object::~verifyable_object ()
 
 /*Generic memory acccess routine - where should it live ? */
 int __stdcall
-check_valid_pointer (void *pointer)
+check_valid_pointer (void const *pointer)
 {
-  if (!pointer || IsBadWritePtr (pointer, sizeof (verifyable_object)))
+  if (!pointer || IsBadWritePtr ((void *) pointer, sizeof (verifyable_object)))
     return EFAULT;
   return 0;
 }
@@ -1697,14 +1726,12 @@ __pthread_cond_signal (pthread_cond_t *c
 }
 
 int
-__pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
-			  const struct timespec *abstime)
+__pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex,
+		       long waitlength)
 {
 // and yes cond_access here is still open to a race. (we increment, context swap,
 // broadcast occurs -  we miss the broadcast. the functions aren't split properly.
   int rv;
-  if (!abstime)
-    return EINVAL;
   pthread_mutex **themutex = NULL;
   if (*mutex == PTHREAD_MUTEX_INITIALIZER)
     __pthread_mutex_init (mutex, NULL);
@@ -1714,12 +1741,6 @@ __pthread_cond_timedwait (pthread_cond_t
     return EINVAL;
   if (!verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC))
     return EINVAL;
-  struct timeb currSysTime;
-  long waitlength;
-  ftime(&currSysTime);
-  waitlength = (abstime->tv_sec - currSysTime.time) *1000;
-  if (waitlength < 0)
-    return ETIMEDOUT;
 
   /*if the cond variable is blocked, then the above timer test maybe wrong. *shrug**/
   if (pthread_mutex_lock (&(*cond)->cond_access))
@@ -1739,11 +1760,17 @@ __pthread_cond_timedwait (pthread_cond_t
   if (pthread_mutex_unlock (&(*cond)->cond_access))
     system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond);
   rv = (*cond)->TimedWait (waitlength);
+  /* this may allow a race on the mutex acquisition and waits.. 
+   * But doing this within the cond access mutex creates a different race
+   */
+  bool last = false;
+  if (InterlockedDecrement (&((*cond)->waiting)) == 0)
+    last = true;
   (*cond)->mutex->Lock ();
+  if (last)
+    (*cond)->mutex = NULL;
   if (pthread_mutex_lock (&(*cond)->cond_access))
     system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond);
-  if (InterlockedDecrement (&((*cond)->waiting)) == 0)
-    (*cond)->mutex = NULL;
   InterlockedDecrement (&((*themutex)->condwaits));
   if (pthread_mutex_unlock (&(*cond)->cond_access))
     system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond);
@@ -1752,45 +1779,24 @@ __pthread_cond_timedwait (pthread_cond_t
 }
 
 int
-__pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
+__pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
+			  const struct timespec *abstime)
 {
-// see cond_timedwait for notes
-  int rv;
-  pthread_mutex_t *themutex = mutex;
-  if (*mutex == PTHREAD_MUTEX_INITIALIZER)
-    __pthread_mutex_init (mutex, NULL);
-  themutex = mutex;
-  if (!verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC))
-    return EINVAL;
-  if (!verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC))
+  if (check_valid_pointer(abstime))
     return EINVAL;
-
-  if (pthread_mutex_lock (&(*cond)->cond_access))
-    system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond);
-
-  if ((*cond)->waiting)
-    if ((*cond)->mutex && ((*cond)->mutex != (*themutex)))
-      {
-	if (pthread_mutex_unlock (&(*cond)->cond_access))
-	  system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond);
-	return EINVAL;
-      }
-  InterlockedIncrement (&((*cond)->waiting));
+  struct timeb currSysTime;
+  long waitlength;
+  ftime(&currSysTime);
+  waitlength = (abstime->tv_sec - currSysTime.time) *1000;
+  if (waitlength < 0)
+    return ETIMEDOUT;
+  return __pthread_cond_dowait (cond, mutex, waitlength);
+}
 
-  (*cond)->mutex = (*themutex);
-  InterlockedIncrement (&((*themutex)->condwaits));
-  if (pthread_mutex_unlock (&(*cond)->cond_access))
-    system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond);
-  rv = (*cond)->TimedWait (INFINITE);
-  (*cond)->mutex->Lock ();
-  if (pthread_mutex_lock (&(*cond)->cond_access))
-    system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond);
-  if (InterlockedDecrement (&((*cond)->waiting)) == 0)
-    (*cond)->mutex = NULL;
-  InterlockedDecrement (&((*themutex)->condwaits));
-  if (pthread_mutex_unlock (&(*cond)->cond_access))
-    system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond);
-  return rv;
+int
+__pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+  return __pthread_cond_dowait (cond, mutex, INFINITE);
 }
 
 int
