summaryrefslogtreecommitdiff
path: root/sem_destroy.c
diff options
context:
space:
mode:
Diffstat (limited to 'sem_destroy.c')
-rw-r--r--sem_destroy.c62
1 files changed, 30 insertions, 32 deletions
diff --git a/sem_destroy.c b/sem_destroy.c
index 96734d1..6c98e80 100644
--- a/sem_destroy.c
+++ b/sem_destroy.c
@@ -82,54 +82,52 @@ sem_destroy (sem_t * sem)
else
{
s = *sem;
- *sem = NULL;
- if ((result = pthread_mutex_trylock (&s->lock)) == 0)
+ if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
- if (s->value >= 0)
+ if (s->value < 0)
{
(void) pthread_mutex_unlock (&s->lock);
+ result = EBUSY;
+ }
+ else
+ {
+ /* There are no threads currently blocked on this semaphore. */
if (!CloseHandle (s->sem))
{
- *sem = s;
+ (void) pthread_mutex_unlock (&s->lock);
result = EINVAL;
}
- else if ((result = pthread_mutex_destroy (&s->lock)) != 0)
- {
+ else
+ {
+ /*
+ * Invalidate the semaphore handle when we have the lock.
+ * Other sema operations should test this after acquiring the lock
+ * to check that the sema is still valid, i.e. before performing any
+ * operations. This may only be necessary before the sema op routine
+ * returns so that the routine can return EINVAL - e.g. if setting
+ * s->value to SEM_VALUE_MAX below does force a fall-through.
+ */
+ *sem = NULL;
+
+ /* Prevent anyone else actually waiting on or posting this sema.
+ */
+ s->value = SEM_VALUE_MAX;
-#ifdef NEED_SEM
- s->sem = CreateEvent (NULL,
- PTW32_FALSE, /* manual reset is false */
- PTW32_FALSE, /* initial state is unset */
- NULL);
-#else
- s->sem = CreateSemaphore (NULL, /* Always NULL */
- (long) 0, /* Force threads to wait */
- (long) _POSIX_SEM_VALUE_MAX, /* Maximum value */
- NULL); /* Name */
-#endif
+ (void) pthread_mutex_unlock (&s->lock);
- if (s->sem == 0)
+ do
{
- /* We just have to pretend that we've destroyed the semaphore
- * even though we're leaving a mutex around.
+ /* Give other threads a chance to run and exit any sema op
+ * routines. Due to the SEM_VALUE_MAX value, if sem_post or
+ * sem_wait were blocked by us they should fall through.
*/
- result = 0;
- }
- else
- {
- *sem = s;
- if (result != EBUSY)
- result = EINVAL;
+ Sleep(0);
}
+ while (pthread_mutex_destroy (&s->lock) == EBUSY);
}
}
- else
- {
- (void) pthread_mutex_unlock (&s->lock);
- result = EBUSY;
- }
}
}