diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | sem_timedwait.c | 2 | ||||
-rw-r--r-- | sem_wait.c | 28 |
3 files changed, 26 insertions, 12 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 Stephan Mueller. * Makefile: Add ptw32_relmillisecs.c module; remove ptw32_{in,de}crease_semaphore.c modules. * GNUmakefile: Likewise. 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); } } |