From 1abb2a28b3947feaf38a85b59e3f3a8c03804ceb Mon Sep 17 00:00:00 2001
From: rpj <rpj>
Date: Thu, 28 Apr 2005 04:41:25 +0000
Subject: ''

---
 ChangeLog                 |  8 +++++++-
 NEWS                      |  6 +++---
 global.c                  |  5 -----
 implement.h               |  1 -
 pthread_once.c            | 15 +++------------
 ptw32_processInitialize.c |  1 -
 ptw32_processTerminate.c  |  1 -
 sem_timedwait.c           |  2 +-
 sem_wait.c                | 28 ++++++++++++++++++----------
 tests/test.h              |  9 +++++++++
 10 files changed, 41 insertions(+), 35 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 80230a7..baa6a14 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2005-04-27  Ross Johnson  <ross at callisto.canberra.edu.au>
+
+	* sem_wait.c (ptw32_sem_wait_cleanup): after cancellation re-attempt
+	to acquire the semaphore to avoid a race with a late sem_post.
+	* sem_timedwait.c: Modify comments.
+
 2005-04-25  Ross Johnson  <ross at callisto.canberra.edu.au>
 
 	* ptw32_relmillisecs.c: New module; converts future abstime to 
@@ -7,7 +13,7 @@
 	implemented for builds that define NEED_SEM (WinCE etc)
 	* sem_timedwait.c: Likewise; after timeout or cancellation,
 	re-attempt to acquire the semaphore in case one has been posted since
-	the timeout/cancel occurred. Thanks to 
+	the timeout/cancel occurred. Thanks to Stefan Mueller.
 	* Makefile: Add ptw32_relmillisecs.c module; remove
 	ptw32_{in,de}crease_semaphore.c modules.
 	* GNUmakefile: Likewise.
diff --git a/NEWS b/NEWS
index ee10e9b..1f8be3a 100644
--- a/NEWS
+++ b/NEWS
@@ -26,8 +26,8 @@ All tests passed.
 Some minor speed improvements were also done.
 
 * Fix integer overrun error in pthread_mutex_timedlock() - missed when
-sem_timedwait() was fixed in release 2.2.0. This rouitne no longer returns
-ENOSUP when NEED_SEM is defined - it is supported (NEED_SEM is only
+sem_timedwait() was fixed in release 2.2.0. This routine no longer returns
+ENOTSUP when NEED_SEM is defined - it is supported (NEED_SEM is only
 required for WinCE versions prior to 3.0).
 
 * Fix timeout bug in sem_timedwait().
@@ -61,7 +61,7 @@ Known issues in this release
 determine..
 
 * The Borland version of the dll fails some of the tests with a memory read
-exception. The cause is not yet known but a compiler bug has not been rules
+exception. The cause is not yet known but a compiler bug has not been ruled
 out.
 
 
diff --git a/global.c b/global.c
index 59cb56f..2b55422 100644
--- a/global.c
+++ b/global.c
@@ -107,11 +107,6 @@ CRITICAL_SECTION ptw32_spinlock_test_init_lock;
  */
 CRITICAL_SECTION ptw32_cond_list_lock;
 
-/*
- * Global lock to serialise once_control event management.
- */
-CRITICAL_SECTION ptw32_once_event_lock;
-
 #ifdef _UWIN
 /*
  * Keep a count of the number of threads.
diff --git a/implement.h b/implement.h
index 7504dd0..b723ef3 100644
--- a/implement.h
+++ b/implement.h
@@ -488,7 +488,6 @@ extern CRITICAL_SECTION ptw32_cond_list_lock;
 extern CRITICAL_SECTION ptw32_cond_test_init_lock;
 extern CRITICAL_SECTION ptw32_rwlock_test_init_lock;
 extern CRITICAL_SECTION ptw32_spinlock_test_init_lock;
-extern CRITICAL_SECTION ptw32_once_event_lock;
 
 #ifdef _UWIN
 extern int pthread_count;
diff --git a/pthread_once.c b/pthread_once.c
index eb355dd..0ee063a 100644
--- a/pthread_once.c
+++ b/pthread_once.c
@@ -69,10 +69,9 @@
  * to be a cancelation point. A cancelation meant that at least some waiting threads
  * if any had to be woken so that one might become the new initter thread.
  * Waiters could no longer simply assume that, if the event was not null, it did
- * not need to create an event. Some real critical sections were needed, and in the
- * current library, a global CRITICAL_SECTION is probably more efficient than a per
- * once_control PTHREAD_MUTEX_INITIALIZER that should be somehow destroyed on exit from
- * pthread_once(). Also, the cancelled init thread needed to set the event, and the
+ * not need to create an event.
+ *
+ * Also, the cancelled init thread needed to set the event, and the
  * new init thread (the winner of the race between any newly arriving threads and
  * waking waiters) would need to reset it again. In the meantime, threads could be
  * happily looping around until they either suspended on the reset event, or exited
@@ -114,7 +113,6 @@ ptw32_once_init_routine_cleanup(void * arg)
   (void) PTW32_INTERLOCKED_EXCHANGE((LPLONG)&once_control->state, (LONG)PTW32_ONCE_CANCELLED);
   (void) PTW32_INTERLOCKED_EXCHANGE((LPLONG)&once_control->started, (LONG)PTW32_FALSE);
 
-//  EnterCriticalSection(&ptw32_once_event_lock);
   if (InterlockedExchangeAdd((LPLONG)&once_control->event, 0L)) /* MBR fence */
     {
       int lasterror = GetLastError ();
@@ -129,7 +127,6 @@ ptw32_once_init_routine_cleanup(void * arg)
 	  WSASetLastError (lastWSAerror);
 	}
     }
-//  LeaveCriticalSection(&ptw32_once_event_lock);
 }
 
 
@@ -228,7 +225,6 @@ pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
 	       * so we will not be starved by any other threads that may now be looping
 	       * around.
 	       */
-//	      EnterCriticalSection(&ptw32_once_event_lock);
 	      if (InterlockedExchangeAdd((LPLONG)&once_control->event, 0L)) /* MBR fence */
 		{
 		  if (!ResetEvent(once_control->event))
@@ -236,7 +232,6 @@ pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
 		      restoreLastError = PTW32_TRUE;
 		    }
 		}
-//	      LeaveCriticalSection(&ptw32_once_event_lock);
 
 	      /*
 	       * Any threads entering the wait section and getting out again before
@@ -302,7 +297,6 @@ pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
 	   * while waiting, create an event to wait on
 	   */
 
-//	  EnterCriticalSection(&ptw32_once_event_lock);
 	  if (1 == InterlockedIncrement((LPLONG)&once_control->eventUsers))
 	    {
 	      /*
@@ -332,7 +326,6 @@ pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
 		  CloseHandle(tmpEvent);
 		}
 	    }
-//	  LeaveCriticalSection(&ptw32_once_event_lock);
 
 	  /*
 	   * Check 'state' again in case the initting thread has finished or cancelled
@@ -371,7 +364,6 @@ pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
 	    }
 
 	  /* last one out shut off the lights */
-//	  EnterCriticalSection(&ptw32_once_event_lock);
 	  if (0 == InterlockedDecrement((LPLONG)&once_control->eventUsers))
 	    {
 	      /* we were last */
@@ -382,7 +374,6 @@ pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
 		  CloseHandle(tmpEvent);
 		}
 	    }
-//	  LeaveCriticalSection(&ptw32_once_event_lock);
 	}
     }
 
diff --git a/ptw32_processInitialize.c b/ptw32_processInitialize.c
index d56cd66..d13b022 100644
--- a/ptw32_processInitialize.c
+++ b/ptw32_processInitialize.c
@@ -96,7 +96,6 @@ ptw32_processInitialize (void)
   InitializeCriticalSection (&ptw32_cond_test_init_lock);
   InitializeCriticalSection (&ptw32_rwlock_test_init_lock);
   InitializeCriticalSection (&ptw32_spinlock_test_init_lock);
-  InitializeCriticalSection (&ptw32_once_event_lock);
 
   return (ptw32_processInitialized);
 
diff --git a/ptw32_processTerminate.c b/ptw32_processTerminate.c
index f80b99b..d2dfa7a 100644
--- a/ptw32_processTerminate.c
+++ b/ptw32_processTerminate.c
@@ -101,7 +101,6 @@ ptw32_processTerminate (void)
       /* 
        * Destroy the global locks and other objects.
        */
-      DeleteCriticalSection (&ptw32_once_event_lock);
       DeleteCriticalSection (&ptw32_spinlock_test_init_lock);
       DeleteCriticalSection (&ptw32_rwlock_test_init_lock);
       DeleteCriticalSection (&ptw32_cond_test_init_lock);
diff --git a/sem_timedwait.c b/sem_timedwait.c
index 186c123..deefa6e 100644
--- a/sem_timedwait.c
+++ b/sem_timedwait.c
@@ -62,7 +62,7 @@ ptw32_sem_timedwait_cleanup (void * args)
     {
       /*
        * We either timed out or were cancelled.
-       * If someone posted since then we try to take the semaphore.
+       * If someone has posted between then and now we try to take the semaphore.
        * Otherwise the semaphore count may be wrong after we
        * return. In the case of a cancellation, it is as if we
        * were cancelled just before we return (after taking the semaphore)
diff --git a/sem_wait.c b/sem_wait.c
index bcb17e8..05d7326 100644
--- a/sem_wait.c
+++ b/sem_wait.c
@@ -53,19 +53,27 @@ ptw32_sem_wait_cleanup(void * sem)
 
   if (pthread_mutex_lock (&s->lock) == 0)
     {
-      ++s->value;
-#ifdef NEED_SEM
-          
-      if (s->value > 0)
-	{
-	  s->leftToUnblock = 0;
-	}   
-#else 
       /*
-       * Don't release the W32 sema, it doesn't need adjustment
-       * because it doesn't record the number of waiters.
+       * If the sema is posted between us being cancelled and us locking
+       * the sema again above then we need to consume that post but cancel
+       * anyway. If we don't get the semaphore we indicate that we're no
+       * longer waiting.
        */
+      if (!(WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0))
+	{
+	  ++s->value;
+#ifdef NEED_SEM
+	  if (s->value > 0)
+	    {
+	      s->leftToUnblock = 0;
+	    }
+#else
+	  /*
+	   * Don't release the W32 sema, it doesn't need adjustment
+	   * because it doesn't record the number of waiters.
+	   */
 #endif /* NEED_SEM */
+	}
       (void) pthread_mutex_unlock (&s->lock);
     }
 }
diff --git a/tests/test.h b/tests/test.h
index a664bb6..3132c69 100644
--- a/tests/test.h
+++ b/tests/test.h
@@ -47,6 +47,15 @@
 
 #define PTW32_THREAD_NULL_ID {NULL,0}
 
+#if defined(__MINGW32__)
+#include <stdint.h>
+#elif defined(__BORLANDC__)
+#define int64_t ULONGLONG
+#else
+#define int64_t _int64
+#endif
+
+
 char * error_string[] = {
   "ZERO_or_EOK",
   "EPERM",
-- 
cgit v1.2.3