diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | global.c | 5 | ||||
-rw-r--r-- | implement.h | 1 | ||||
-rw-r--r-- | pthread_once.c | 15 | ||||
-rw-r--r-- | ptw32_processInitialize.c | 1 | ||||
-rw-r--r-- | ptw32_processTerminate.c | 1 | ||||
-rw-r--r-- | sem_timedwait.c | 2 | ||||
-rw-r--r-- | sem_wait.c | 28 | ||||
-rw-r--r-- | tests/test.h | 9 |
10 files changed, 41 insertions, 35 deletions
@@ -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. @@ -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. @@ -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) @@ -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", |