aboutsummaryrefslogtreecommitdiff
path: root/linuxthreads/condvar.c
diff options
context:
space:
mode:
Diffstat (limited to 'linuxthreads/condvar.c')
-rw-r--r--linuxthreads/condvar.c210
1 files changed, 3 insertions, 207 deletions
diff --git a/linuxthreads/condvar.c b/linuxthreads/condvar.c
index e1c8119..a06517c 100644
--- a/linuxthreads/condvar.c
+++ b/linuxthreads/condvar.c
@@ -25,22 +25,6 @@
#include "queue.h"
#include "restart.h"
-static int pthread_cond_timedwait_relative_old(pthread_cond_t *,
- pthread_mutex_t *, const struct timespec *);
-
-static int pthread_cond_timedwait_relative_new(pthread_cond_t *,
- pthread_mutex_t *, const struct timespec *);
-
-static int (*pthread_cond_tw_rel)(pthread_cond_t *, pthread_mutex_t *,
- const struct timespec *) = pthread_cond_timedwait_relative_old;
-
-/* initialize this module */
-void __pthread_init_condvar(int rt_sig_available)
-{
- if (rt_sig_available)
- pthread_cond_tw_rel = pthread_cond_timedwait_relative_new;
-}
-
int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *cond_attr)
{
@@ -127,151 +111,13 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
return 0;
}
-/* The following function is used on kernels that don't have rt signals.
- SIGUSR1 is used as the restart signal. The different code is needed
- because that ordinary signal does not queue. */
-
static int
-pthread_cond_timedwait_relative_old(pthread_cond_t *cond,
+pthread_cond_timedwait_relative(pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec * abstime)
{
volatile pthread_descr self = thread_self();
- sigset_t unblock, initial_mask;
int already_canceled = 0;
- int was_signalled = 0;
- sigjmp_buf jmpbuf;
- pthread_extricate_if extr;
-
- /* Check whether the mutex is locked and owned by this thread. */
- if (mutex->__m_kind != PTHREAD_MUTEX_FAST_NP && mutex->__m_owner != self)
- return EINVAL;
-
- /* Set up extrication interface */
- extr.pu_object = cond;
- extr.pu_extricate_func = cond_extricate_func;
-
- /* Register extrication interface */
- __pthread_set_own_extricate_if(self, &extr);
-
- /* Enqueue to wait on the condition and check for cancellation. */
- __pthread_lock(&cond->__c_lock, self);
- if (!(THREAD_GETMEM(self, p_canceled)
- && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
- enqueue(&cond->__c_waiting, self);
- else
- already_canceled = 1;
- __pthread_spin_unlock(&cond->__c_lock);
-
- if (already_canceled) {
- __pthread_set_own_extricate_if(self, 0);
- pthread_exit(PTHREAD_CANCELED);
- }
-
- pthread_mutex_unlock(mutex);
-
- if (atomic_decrement(&self->p_resume_count) == 0) {
- /* Set up a longjmp handler for the restart signal, unblock
- the signal and sleep. */
-
- if (sigsetjmp(jmpbuf, 1) == 0) {
- THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
- THREAD_SETMEM(self, p_signal, 0);
- /* Unblock the restart signal */
- sigemptyset(&unblock);
- sigaddset(&unblock, __pthread_sig_restart);
- sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
-
- while (1) {
- struct timeval now;
- struct timespec reltime;
-
- /* Compute a time offset relative to now. */
- __gettimeofday (&now, NULL);
- reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
- reltime.tv_sec = abstime->tv_sec - now.tv_sec;
- if (reltime.tv_nsec < 0) {
- reltime.tv_nsec += 1000000000;
- reltime.tv_sec -= 1;
- }
-
- /* Sleep for the required duration. If woken by a signal,
- resume waiting as required by Single Unix Specification. */
- if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
- break;
- }
-
- /* Block the restart signal again */
- sigprocmask(SIG_SETMASK, &initial_mask, NULL);
- was_signalled = 0;
- } else {
- was_signalled = 1;
- }
- THREAD_SETMEM(self, p_signal_jmp, NULL);
- }
-
- /* Now was_signalled is true if we exited the above code
- due to the delivery of a restart signal. In that case,
- we know we have been dequeued and resumed and that the
- resume count is balanced. Otherwise, there are some
- cases to consider. First, try to bump up the resume count
- back to zero. If it goes to 1, it means restart() was
- invoked on this thread. The signal must be consumed
- and the count bumped down and everything is cool.
- Otherwise, no restart was delivered yet, so we remove
- the thread from the queue. If this succeeds, it's a clear
- case of timeout. If we fail to remove from the queue, then we
- must wait for a restart. */
-
- if (!was_signalled) {
- if (atomic_increment(&self->p_resume_count) != -1) {
- __pthread_wait_for_restart_signal(self);
- atomic_decrement(&self->p_resume_count); /* should be zero now! */
- } else {
- int was_on_queue;
- __pthread_lock(&cond->__c_lock, self);
- was_on_queue = remove_from_queue(&cond->__c_waiting, self);
- __pthread_spin_unlock(&cond->__c_lock);
-
- if (was_on_queue) {
- __pthread_set_own_extricate_if(self, 0);
- pthread_mutex_lock(mutex);
- return ETIMEDOUT;
- }
-
- suspend(self);
- }
- }
-
- __pthread_set_own_extricate_if(self, 0);
-
- /* The remaining logic is the same as in other cancellable waits,
- such as pthread_join sem_wait or pthread_cond wait. */
-
- if (THREAD_GETMEM(self, p_woken_by_cancel)
- && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
- THREAD_SETMEM(self, p_woken_by_cancel, 0);
- pthread_mutex_lock(mutex);
- pthread_exit(PTHREAD_CANCELED);
- }
-
- pthread_mutex_lock(mutex);
- return 0;
-}
-
-/* The following function is used on new (late 2.1 and 2.2 and higher) kernels
- that have rt signals which queue. */
-
-static int
-pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
- pthread_mutex_t *mutex,
- const struct timespec * abstime)
-{
- volatile pthread_descr self = thread_self();
- sigset_t unblock, initial_mask;
- int already_canceled = 0;
- int was_signalled = 0;
- sigjmp_buf jmpbuf;
pthread_extricate_if extr;
/* Check whether the mutex is locked and owned by this thread. */
@@ -279,7 +125,6 @@ pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
return EINVAL;
already_canceled = 0;
- was_signalled = 0;
/* Set up extrication interface */
extr.pu_object = cond;
@@ -304,56 +149,7 @@ pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
pthread_mutex_unlock(mutex);
- /* Set up a longjmp handler for the restart signal, unblock
- the signal and sleep. */
-
- if (sigsetjmp(jmpbuf, 1) == 0) {
- THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
- THREAD_SETMEM(self, p_signal, 0);
- /* Unblock the restart signal */
- sigemptyset(&unblock);
- sigaddset(&unblock, __pthread_sig_restart);
- sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
-
- while (1) {
- struct timeval now;
- struct timespec reltime;
-
- /* Compute a time offset relative to now. */
- __gettimeofday (&now, NULL);
- reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
- reltime.tv_sec = abstime->tv_sec - now.tv_sec;
- if (reltime.tv_nsec < 0) {
- reltime.tv_nsec += 1000000000;
- reltime.tv_sec -= 1;
- }
-
- /* Sleep for the required duration. If woken by a signal,
- resume waiting as required by Single Unix Specification. */
- if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
- break;
- }
-
- /* Block the restart signal again */
- sigprocmask(SIG_SETMASK, &initial_mask, NULL);
- was_signalled = 0;
- } else {
- was_signalled = 1;
- }
- THREAD_SETMEM(self, p_signal_jmp, NULL);
-
- /* Now was_signalled is true if we exited the above code
- due to the delivery of a restart signal. In that case,
- everything is cool. We have been removed from the queue
- by the other thread, and consumed its signal.
-
- Otherwise we this thread woke up spontaneously, or due to a signal other
- than restart. The next thing to do is to try to remove the thread
- from the queue. This may fail due to a race against another thread
- trying to do the same. In the failed case, we know we were signalled,
- and we may also have to consume a restart signal. */
-
- if (!was_signalled) {
+ if (!timedsuspend(self, abstime) == 0) {
int was_on_queue;
/* __pthread_lock will queue back any spurious restarts that
@@ -393,7 +189,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec * abstime)
{
/* Indirect call through pointer! */
- return pthread_cond_tw_rel(cond, mutex, abstime);
+ return pthread_cond_timedwait_relative(cond, mutex, abstime);
}
int pthread_cond_signal(pthread_cond_t *cond)