--- a
+++ b/condvar_wait.c
@@ -0,0 +1,527 @@
+/*
+ * condvar_wait.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ *      Pthreads-win32 - POSIX Threads Library for Win32
+ *      Copyright(C) 1998 John E. Bossom
+ *      Copyright(C) 1999,2002 Pthreads-win32 contributors
+ * 
+ *      Contact Email: rpj@ise.canberra.edu.au
+ * 
+ *      The current list of contributors is contained
+ *      in the file CONTRIBUTORS included with the source
+ *      code distribution. The list can also be seen at the
+ *      following World Wide Web location:
+ *      http://sources.redhat.com/pthreads-win32/contributors.html
+ * 
+ *      This library is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU Lesser General Public
+ *      License as published by the Free Software Foundation; either
+ *      version 2 of the License, or (at your option) any later version.
+ * 
+ *      This library is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *      Lesser General Public License for more details.
+ * 
+ *      You should have received a copy of the GNU Lesser General Public
+ *      License along with this library in the file COPYING.LIB;
+ *      if not, write to the Free Software Foundation, Inc.,
+ *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * -------------------------------------------------------------
+ * Algorithm:
+ * The algorithm used in this implementation is that developed by
+ * Alexander Terekhov in colaboration with Louis Thomas. The bulk
+ * of the discussion is recorded in the file README.CV, which contains
+ * several generations of both colaborators original algorithms. The final
+ * algorithm used here is the one referred to as
+ *
+ *     Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
+ * 
+ * presented below in pseudo-code as it appeared:
+ *
+ *
+ * given:
+ * semBlockLock - bin.semaphore
+ * semBlockQueue - semaphore
+ * mtxExternal - mutex or CS
+ * mtxUnblockLock - mutex or CS
+ * nWaitersGone - int
+ * nWaitersBlocked - int
+ * nWaitersToUnblock - int
+ * 
+ * wait( timeout ) {
+ * 
+ *   [auto: register int result          ]     // error checking omitted
+ *   [auto: register int nSignalsWasLeft ]
+ *   [auto: register int nWaitersWasGone ]
+ * 
+ *   sem_wait( semBlockLock );
+ *   nWaitersBlocked++;
+ *   sem_post( semBlockLock );
+ * 
+ *   unlock( mtxExternal );
+ *   bTimedOut = sem_wait( semBlockQueue,timeout );
+ * 
+ *   lock( mtxUnblockLock );
+ *   if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
+ *     if ( bTimeout ) {                       // timeout (or canceled)
+ *       if ( 0 != nWaitersBlocked ) {
+ *         nWaitersBlocked--;
+ *       }
+ *       else {
+ *         nWaitersGone++;                     // count spurious wakeups.
+ *       }
+ *     }
+ *     if ( 0 == --nWaitersToUnblock ) {
+ *       if ( 0 != nWaitersBlocked ) {
+ *         sem_post( semBlockLock );           // open the gate.
+ *         nSignalsWasLeft = 0;                // do not open the gate
+ *                                             // below again.
+ *       }
+ *       else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
+ *         nWaitersGone = 0;
+ *       }
+ *     }
+ *   }
+ *   else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
+ *                                             // spurious semaphore :-)
+ *     sem_wait( semBlockLock );
+ *     nWaitersBlocked -= nWaitersGone;     // something is going on here
+ *                                          //  - test of timeouts? :-)
+ *     sem_post( semBlockLock );
+ *     nWaitersGone = 0;
+ *   }
+ *   unlock( mtxUnblockLock );
+ * 
+ *   if ( 1 == nSignalsWasLeft ) {
+ *     if ( 0 != nWaitersWasGone ) {
+ *       // sem_adjust( semBlockQueue,-nWaitersWasGone );
+ *       while ( nWaitersWasGone-- ) {
+ *         sem_wait( semBlockQueue );       // better now than spurious later
+ *       }
+ *     } sem_post( semBlockLock );          // open the gate
+ *   }
+ * 
+ *   lock( mtxExternal );
+ * 
+ *   return ( bTimedOut ) ? ETIMEOUT : 0;
+ * }
+ * 
+ * signal(bAll) {
+ * 
+ *   [auto: register int result         ]
+ *   [auto: register int nSignalsToIssue]
+ * 
+ *   lock( mtxUnblockLock );
+ * 
+ *   if ( 0 != nWaitersToUnblock ) {        // the gate is closed!!!
+ *     if ( 0 == nWaitersBlocked ) {        // NO-OP
+ *       return unlock( mtxUnblockLock );
+ *     }
+ *     if (bAll) {
+ *       nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
+ *       nWaitersBlocked = 0;
+ *     }
+ *     else {
+ *       nSignalsToIssue = 1;
+ *       nWaitersToUnblock++;
+ *       nWaitersBlocked--;
+ *     }
+ *   }
+ *   else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
+ *     sem_wait( semBlockLock );                  // close the gate
+ *     if ( 0 != nWaitersGone ) {
+ *       nWaitersBlocked -= nWaitersGone;
+ *       nWaitersGone = 0;
+ *     }
+ *     if (bAll) {
+ *       nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
+ *       nWaitersBlocked = 0;
+ *     }
+ *     else {
+ *       nSignalsToIssue = nWaitersToUnblock = 1;
+ *       nWaitersBlocked--;
+ *     }
+ *   }
+ *   else { // NO-OP
+ *     return unlock( mtxUnblockLock );
+ *   }
+ * 
+ *   unlock( mtxUnblockLock );
+ *   sem_post( semBlockQueue,nSignalsToIssue );
+ *   return result;
+ * }
+ * -------------------------------------------------------------
+ *
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+/*
+ * Arguments for cond_wait_cleanup, since we can only pass a
+ * single void * to it.
+ */
+typedef struct {
+  pthread_mutex_t * mutexPtr;
+  pthread_cond_t cv;
+  int * resultPtr;
+  int signaled;
+} ptw32_cond_wait_cleanup_args_t;
+
+static void
+ptw32_cond_wait_cleanup(void * args)
+{
+  ptw32_cond_wait_cleanup_args_t * cleanup_args = (ptw32_cond_wait_cleanup_args_t *) args;
+  pthread_cond_t cv = cleanup_args->cv;
+  int * resultPtr = cleanup_args->resultPtr;
+  int nSignalsWasLeft;
+  int nWaitersWasGone = 0; /* Initialised to quell warnings. */
+  int result;
+
+  /*
+   * Whether we got here as a result of signal/broadcast or because of
+   * timeout on wait or thread cancellation we indicate that we are no
+   * longer waiting. The waiter is responsible for adjusting waiters
+   * (to)unblock(ed) counts (protected by unblock lock).
+   */
+  if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
+    {
+      *resultPtr = result;
+      return;
+    }
+
+  if ( 0 != (nSignalsWasLeft = cv->nWaitersToUnblock) )
+    {
+      if ( !cleanup_args->signaled )
+        {
+          if ( 0 != cv->nWaitersBlocked )
+            {
+              (cv->nWaitersBlocked)--;
+            }
+          else
+            {
+              (cv->nWaitersGone)++;
+            }
+        }
+      if ( 0 == --(cv->nWaitersToUnblock) )
+        {
+          if ( 0 != cv->nWaitersBlocked )
+            {
+              if (sem_post( &(cv->semBlockLock) ) != 0)
+                {
+                  *resultPtr = errno;
+                  /*
+                   * This is a fatal error for this CV,
+                   * so we deliberately don't unlock
+                   * cv->mtxUnblockLock before returning.
+                   */
+                  return;
+                }
+              nSignalsWasLeft = 0;
+            }
+          else if ( 0 != (nWaitersWasGone = cv->nWaitersGone) )
+            {
+              cv->nWaitersGone = 0;
+            }
+        }
+    }
+  else if ( INT_MAX/2 == ++(cv->nWaitersGone) )
+    {
+      if (sem_wait( &(cv->semBlockLock) ) != 0)
+        {
+          *resultPtr = errno;
+          /*
+           * This is a fatal error for this CV,
+           * so we deliberately don't unlock
+           * cv->mtxUnblockLock before returning.
+           */
+          return;
+        }
+      cv->nWaitersBlocked -= cv->nWaitersGone;
+      if (sem_post( &(cv->semBlockLock) ) != 0)
+        {
+          *resultPtr = errno;
+          /*
+           * This is a fatal error for this CV,
+           * so we deliberately don't unlock
+           * cv->mtxUnblockLock before returning.
+           */
+          return;
+        }
+      cv->nWaitersGone = 0;
+    }
+
+  if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0) 
+    {
+      *resultPtr = result;
+      return;
+    }
+
+  if ( 1 == nSignalsWasLeft )
+    {
+      if ( 0 != nWaitersWasGone )
+        {
+          // sem_adjust( &(cv->semBlockQueue), -nWaitersWasGone );
+          while ( nWaitersWasGone-- ) 
+            {
+              if (sem_wait( &(cv->semBlockQueue)) != 0 )
+                {
+                  *resultPtr = errno;
+                  return;
+                }
+            }
+        }
+      if (sem_post(&(cv->semBlockLock)) != 0)
+        {
+          *resultPtr = errno;
+          return;
+        }
+    }
+
+  /*
+   * XSH: Upon successful return, the mutex has been locked and is owned
+   * by the calling thread
+   */
+  if ((result = pthread_mutex_lock(cleanup_args->mutexPtr)) != 0)
+    {
+      *resultPtr = result;
+    }
+
+}                               /* ptw32_cond_wait_cleanup */
+
+static INLINE int
+ptw32_cond_timedwait (pthread_cond_t * cond, 
+                      pthread_mutex_t * mutex,
+                      const struct timespec *abstime)
+{
+  int result = 0;
+  pthread_cond_t cv;
+  ptw32_cond_wait_cleanup_args_t cleanup_args;
+
+  if (cond == NULL || *cond == NULL)
+    {
+      return EINVAL;
+    }
+
+  /*
+   * We do a quick check to see if we need to do more work
+   * to initialise a static condition variable. We check
+   * again inside the guarded section of ptw32_cond_check_need_init()
+   * to avoid race conditions.
+   */
+  if (*cond == PTHREAD_COND_INITIALIZER)
+    {
+      result = ptw32_cond_check_need_init(cond);
+    }
+
+  if (result != 0 && result != EBUSY)
+    {
+      return result;
+    }
+
+  cv = *cond;
+
+  if (sem_wait(&(cv->semBlockLock)) != 0)
+    {
+      return errno;
+    }
+
+  cv->nWaitersBlocked++;
+
+  if (sem_post(&(cv->semBlockLock)) != 0)
+    {
+      return errno;
+    }
+
+  /*
+   * Setup this waiter cleanup handler
+   */
+  cleanup_args.mutexPtr = mutex;
+  cleanup_args.cv = cv;
+  cleanup_args.resultPtr = &result;
+  /*
+   * If we're canceled, or the cancelable wait fails for any reason,
+   * including a timeout, then tell the cleanup routine that we
+   * have not been signaled.
+   */
+  cleanup_args.signaled = 0;
+
+#ifdef _MSC_VER
+#pragma inline_depth(0)
+#endif
+  pthread_cleanup_push(ptw32_cond_wait_cleanup, (void *) &cleanup_args);
+
+  /*
+   * Now we can release 'mutex' and...
+   */
+  if ((result = pthread_mutex_unlock(mutex)) == 0)
+    {
+
+      /*
+       * ...wait to be awakened by
+       *              pthread_cond_signal, or
+       *              pthread_cond_broadcast, or
+       *              timeout, or
+       *              thread cancellation
+       *
+       * Note:
+       *
+       *      sem_timedwait is a cancellation point,
+       *      hence providing the mechanism for making
+       *      pthread_cond_wait a cancellation point.
+       *      We use the cleanup mechanism to ensure we
+       *      re-lock the mutex and adjust (to)unblock(ed) waiters
+       *      counts if we are cancelled, timed out or signalled.
+       */
+      if (sem_timedwait(&(cv->semBlockQueue), abstime) != 0)
+        {
+          result = errno;
+        }
+    }
+
+  /*
+   * Not executed if we're canceled. Signaled is false if we timed out.
+   */
+  cleanup_args.signaled = (result == 0);
+
+  /*
+   * Always cleanup
+   */
+  pthread_cleanup_pop(1);
+#ifdef _MSC_VER
+#pragma inline_depth()
+#endif
+
+  /*
+   * "result" can be modified by the cleanup handler.
+   */
+  return result;
+
+}                               /* ptw32_cond_timedwait */
+
+
+int
+pthread_cond_wait (pthread_cond_t * cond,
+                   pthread_mutex_t * mutex)
+     /*
+      * ------------------------------------------------------
+      * DOCPUBLIC
+      *      This function waits on a condition variable until
+      *      awakened by a signal or broadcast.
+      *
+      *      Caller MUST be holding the mutex lock; the
+      *      lock is released and the caller is blocked waiting
+      *      on 'cond'. When 'cond' is signaled, the mutex
+      *      is re-acquired before returning to the caller.
+      *
+      * PARAMETERS
+      *      cond
+      *              pointer to an instance of pthread_cond_t
+      *
+      *      mutex
+      *              pointer to an instance of pthread_mutex_t
+      *
+      *
+      * DESCRIPTION
+      *      This function waits on a condition variable until
+      *      awakened by a signal or broadcast.
+      *
+      *      NOTES:
+      *
+      *      1)      The function must be called with 'mutex' LOCKED
+      *              by the calling thread, or undefined behaviour
+      *              will result.
+      *
+      *      2)      This routine atomically releases 'mutex' and causes
+      *              the calling thread to block on the condition variable.
+      *              The blocked thread may be awakened by 
+      *                      pthread_cond_signal or 
+      *                      pthread_cond_broadcast.
+      *
+      * Upon successful completion, the 'mutex' has been locked and 
+      * is owned by the calling thread.
+      *
+      *
+      * RESULTS
+      *              0               caught condition; mutex released,
+      *              EINVAL          'cond' or 'mutex' is invalid,
+      *              EINVAL          different mutexes for concurrent waits,
+      *              EINVAL          mutex is not held by the calling thread,
+      *
+      * ------------------------------------------------------
+      */
+{
+  /*
+   * The NULL abstime arg means INFINITE waiting.
+   */
+  return (ptw32_cond_timedwait(cond, mutex, NULL));
+
+}                               /* pthread_cond_wait */
+
+
+int
+pthread_cond_timedwait (pthread_cond_t * cond, 
+                        pthread_mutex_t * mutex,
+                        const struct timespec *abstime)
+     /*
+      * ------------------------------------------------------
+      * DOCPUBLIC
+      *      This function waits on a condition variable either until
+      *      awakened by a signal or broadcast; or until the time
+      *      specified by abstime passes.
+      *
+      * PARAMETERS
+      *      cond
+      *              pointer to an instance of pthread_cond_t
+      *
+      *      mutex
+      *              pointer to an instance of pthread_mutex_t
+      *
+      *      abstime
+      *              pointer to an instance of (const struct timespec)
+      *
+      *
+      * DESCRIPTION
+      *      This function waits on a condition variable either until
+      *      awakened by a signal or broadcast; or until the time
+      *      specified by abstime passes.
+      *
+      *      NOTES:
+      *      1)      The function must be called with 'mutex' LOCKED
+      *              by the calling thread, or undefined behaviour
+      *              will result.
+      *
+      *      2)      This routine atomically releases 'mutex' and causes
+      *              the calling thread to block on the condition variable.
+      *              The blocked thread may be awakened by 
+      *                      pthread_cond_signal or 
+      *                      pthread_cond_broadcast.
+      *
+      *
+      * RESULTS
+      *              0               caught condition; mutex released,
+      *              EINVAL          'cond', 'mutex', or abstime is invalid,
+      *              EINVAL          different mutexes for concurrent waits,
+      *              EINVAL          mutex is not held by the calling thread,
+      *              ETIMEDOUT       abstime ellapsed before cond was signaled.
+      *
+      * ------------------------------------------------------
+      */
+{
+  if (abstime == NULL)
+    {
+      return EINVAL;
+    }
+
+  return (ptw32_cond_timedwait(cond, mutex, abstime));
+
+}                               /* pthread_cond_timedwait */