summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--sem_timedwait.c2
-rw-r--r--sem_wait.c28
3 files changed, 26 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 3ba012b..d812aa5 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 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)
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);
}
}