aboutsummaryrefslogtreecommitdiff
path: root/linuxthreads/semaphore.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2000-07-26 02:18:41 +0000
committerUlrich Drepper <drepper@redhat.com>2000-07-26 02:18:41 +0000
commit9ec9e34ee301ccfa4216939639be5498831f9d37 (patch)
treee61a7957abfbeb4816cb6dc545c116b8e18159b5 /linuxthreads/semaphore.c
parenta956d04575bbd053a1ff61a05a5526867633d0d0 (diff)
downloadglibc-9ec9e34ee301ccfa4216939639be5498831f9d37.tar
glibc-9ec9e34ee301ccfa4216939639be5498831f9d37.tar.gz
glibc-9ec9e34ee301ccfa4216939639be5498831f9d37.tar.bz2
glibc-9ec9e34ee301ccfa4216939639be5498831f9d37.zip
Update.
* internals.h (strict __pthread_descr_struct): Add p_sem_avail. * semaphore.c: Handle spurious wakeups. * sysdeps/pthread/pthread.h: Add back PTHREAD_MUTX_FAST_NP as an alias for PTHREAD_MUTEX_ADAPTIVE_NP for source code compatibility. * pthread.c (__pthread_set_own_extricate): Use THREAD_GETMEM. (__pthread_wait_for_restart): Likewise. * condvar.c (pthread_cond_wait): Also check whether thread is cancelable before aborting loop. (pthread_cond_timedwait): Likewise.
Diffstat (limited to 'linuxthreads/semaphore.c')
-rw-r--r--linuxthreads/semaphore.c62
1 files changed, 48 insertions, 14 deletions
diff --git a/linuxthreads/semaphore.c b/linuxthreads/semaphore.c
index a772ea5091..e5afce43eb 100644
--- a/linuxthreads/semaphore.c
+++ b/linuxthreads/semaphore.c
@@ -60,6 +60,7 @@ int __new_sem_wait(sem_t * sem)
volatile pthread_descr self = thread_self();
pthread_extricate_if extr;
int already_canceled = 0;
+ int spurious_wakeup_count;
/* Set up extrication interface */
extr.pu_object = sem;
@@ -72,6 +73,7 @@ int __new_sem_wait(sem_t * sem)
return 0;
}
/* Register extrication interface */
+ THREAD_SETMEM(self, p_sem_avail, 0);
__pthread_set_own_extricate_if(self, &extr);
/* Enqueue only if not already cancelled. */
if (!(THREAD_GETMEM(self, p_canceled)
@@ -87,7 +89,20 @@ int __new_sem_wait(sem_t * sem)
}
/* Wait for sem_post or cancellation, or fall through if already canceled */
- suspend(self);
+ spurious_wakeup_count = 0;
+ while (1)
+ {
+ suspend(self);
+ if (THREAD_GETMEM(self, p_sem_avail) == 0
+ && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
+ || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
+ {
+ /* Count resumes that don't belong to us. */
+ spurious_wakeup_count++;
+ continue;
+ }
+ break;
+ }
__pthread_set_own_extricate_if(self, 0);
/* Terminate only if the wakeup came from cancellation. */
@@ -138,6 +153,8 @@ int __new_sem_post(sem_t * sem)
} else {
th = dequeue(&sem->__sem_waiting);
__pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
+ th->p_sem_avail = 1;
+ WRITE_MEMORY_BARRIER();
restart(th);
}
} else {
@@ -195,6 +212,7 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)
pthread_descr self = thread_self();
pthread_extricate_if extr;
int already_canceled = 0;
+ int spurious_wakeup_count;
__pthread_lock((struct _pthread_fastlock *) &sem->__sem_lock, self);
if (sem->__sem_value > 0) {
@@ -215,6 +233,7 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)
extr.pu_extricate_func = new_sem_extricate_func;
/* Register extrication interface */
+ THREAD_SETMEM(self, p_sem_avail, 0);
__pthread_set_own_extricate_if(self, &extr);
/* Enqueue only if not already cancelled. */
if (!(THREAD_GETMEM(self, p_canceled)
@@ -229,24 +248,39 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)
pthread_exit(PTHREAD_CANCELED);
}
- if (timedsuspend(self, abstime) == 0) {
- int was_on_queue;
+ spurious_wakeup_count = 0;
+ while (1)
+ {
+ if (timedsuspend(self, abstime) == 0) {
+ int was_on_queue;
+
+ /* __pthread_lock will queue back any spurious restarts that
+ may happen to it. */
- /* __pthread_lock will queue back any spurious restarts that
- may happen to it. */
+ __pthread_lock((struct _pthread_fastlock *)&sem->__sem_lock, self);
+ was_on_queue = remove_from_queue(&sem->__sem_waiting, self);
+ __pthread_unlock((struct _pthread_fastlock *)&sem->__sem_lock);
- __pthread_lock((struct _pthread_fastlock *)&sem->__sem_lock, self);
- was_on_queue = remove_from_queue(&sem->__sem_waiting, self);
- __pthread_unlock((struct _pthread_fastlock *)&sem->__sem_lock);
+ if (was_on_queue) {
+ __pthread_set_own_extricate_if(self, 0);
+ return ETIMEDOUT;
+ }
- if (was_on_queue) {
- __pthread_set_own_extricate_if(self, 0);
- return ETIMEDOUT;
+ /* Eat the outstanding restart() from the signaller */
+ suspend(self);
+ }
+
+ if (THREAD_GETMEM(self, p_sem_avail) == 0
+ && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
+ || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
+ {
+ /* Count resumes that don't belong to us. */
+ spurious_wakeup_count++;
+ continue;
+ }
+ break;
}
- /* Eat the outstanding restart() from the signaller */
- suspend(self);
- }
__pthread_set_own_extricate_if(self, 0);
/* Terminate only if the wakeup came from cancellation. */