summaryrefslogtreecommitdiff
path: root/sysdeps/mach
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2013-02-15 01:51:28 +0100
committerRichard Braun <rbraun@sceen.net>2013-02-15 01:51:28 +0100
commite7f324f243f776b2729403c55c508d7ceb7b6a01 (patch)
tree8d141fa8c4448c1e7c55938c29bcb3a09f90d515 /sysdeps/mach
parent5ab516af0779a7fd74ad893c7c67960df6ede065 (diff)
Add pthread_hurd_cond_timedwait_np
This new Hurd-specific function is meant to allow Hurd servers to wait for events during a bounded period of time. * Makefile (libpthread-routines): Add pt-hurd-cond-timedwait. * Versions: Include pthread_hurd_cond_timedwait_np in version GLIBC_2.17 of libpthread. * sysdeps/mach/hurd/bits/pthread-np.h (pthread_hurd_cond_timedwait_np): New declaration. * sysdeps/mach/hurd/pt-hurd-cond-timedwait.c: New file that provides __pthread_hurd_cond_timedwait_internal and __pthread_hurd_cond_timedwait_np. * sysdeps/mach/hurd/pt-hurd-cond-wait.c (__pthread_hurd_cond_wait_np): Rewrite as a call to __pthread_hurd_cond_timedwait_internal with no timeout.
Diffstat (limited to 'sysdeps/mach')
-rw-r--r--sysdeps/mach/hurd/bits/pthread-np.h6
-rw-r--r--sysdeps/mach/hurd/pt-hurd-cond-timedwait.c169
-rw-r--r--sysdeps/mach/hurd/pt-hurd-cond-wait.c76
3 files changed, 187 insertions, 64 deletions
diff --git a/sysdeps/mach/hurd/bits/pthread-np.h b/sysdeps/mach/hurd/bits/pthread-np.h
index 9817a06..5f75e06 100644
--- a/sysdeps/mach/hurd/bits/pthread-np.h
+++ b/sysdeps/mach/hurd/bits/pthread-np.h
@@ -29,4 +29,10 @@
extern int pthread_hurd_cond_wait_np (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex);
+/* Same as pthread_cond_timedwait, but for Hurd-specific cancellation.
+ See hurd_thread_cancel. */
+extern int pthread_hurd_cond_timedwait_np (pthread_cond_t *__restrict __cond,
+ pthread_mutex_t *__restrict __mutex,
+ const struct timespec *abstime);
+
#endif /* bits/pthread-np.h */
diff --git a/sysdeps/mach/hurd/pt-hurd-cond-timedwait.c b/sysdeps/mach/hurd/pt-hurd-cond-timedwait.c
new file mode 100644
index 0000000..7491e0e
--- /dev/null
+++ b/sysdeps/mach/hurd/pt-hurd-cond-timedwait.c
@@ -0,0 +1,169 @@
+/* pthread_hurd_cond_timedwait_np. Hurd-specific wait on a condition.
+ Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <pthread.h>
+#include <assert.h>
+#include <hurd/signal.h>
+
+#include <pt-internal.h>
+
+extern int __pthread_hurd_cond_timedwait_internal (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+
+int
+__pthread_hurd_cond_timedwait_np (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ return __pthread_hurd_cond_timedwait_internal (cond, mutex, abstime);
+}
+
+strong_alias (__pthread_hurd_cond_timedwait_np, pthread_hurd_cond_timedwait_np);
+
+int
+__pthread_hurd_cond_timedwait_internal (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ struct hurd_sigstate *ss = _hurd_self_sigstate ();
+ struct __pthread *self = _pthread_self ();
+ error_t err;
+ int cancel, drain;
+ clockid_t clock_id = __pthread_default_condattr.clock;
+
+ /* This function will be called by hurd_thread_cancel while we are blocked
+ We wake up our thread if it's still blocking or about to block, so it will
+ progress and notice the cancellation flag. */
+ void cancel_me (void)
+ {
+ int unblock;
+
+ __pthread_spin_lock (&cond->__lock);
+ /* The thread only needs to be awaken if it's blocking or about to block.
+ If it was already unblocked, it's not queued any more. */
+ unblock = self->prevp != NULL;
+ if (unblock)
+ __pthread_dequeue (self);
+ __pthread_spin_unlock (&cond->__lock);
+
+ if (unblock)
+ __pthread_wakeup (self);
+ }
+
+ assert (ss->intr_port == MACH_PORT_NULL); /* Sanity check for signal bugs. */
+
+ if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000))
+ return EINVAL;
+
+ /* Atomically enqueue our thread on the condition variable's queue of
+ waiters, and mark our sigstate to indicate that `cancel_me' must be
+ called to wake us up. We must hold the sigstate lock while acquiring
+ the condition variable's lock and tweaking it, so that
+ hurd_thread_cancel can never suspend us and then deadlock waiting for
+ the condition variable's lock. */
+
+ __spin_lock (&ss->lock);
+ __pthread_spin_lock (&cond->__lock);
+ cancel = ss->cancel;
+ if (cancel)
+ /* We were cancelled before doing anything. Don't block at all. */
+ ss->cancel = 0;
+ else
+ {
+ /* Put us on the queue so that pthread_cond_broadcast will know to wake
+ us up. */
+ __pthread_enqueue (&cond->__queue, self);
+ if (cond->__attr)
+ clock_id = cond->__attr->clock;
+ /* Tell hurd_thread_cancel how to unblock us. */
+ ss->cancel_hook = &cancel_me;
+ }
+ __pthread_spin_unlock (&cond->__lock);
+ __spin_unlock (&ss->lock);
+
+ if (cancel)
+ {
+ /* Cancelled on entry. Just leave the mutex locked. */
+ mutex = NULL;
+
+ __spin_lock (&ss->lock);
+ }
+ else
+ {
+ /* Release MUTEX before blocking. */
+ __pthread_mutex_unlock (mutex);
+
+ /* Block the thread. */
+ if (abstime)
+ err = __pthread_timedblock (self, abstime, clock_id);
+ else
+ {
+ err = 0;
+ __pthread_block (self);
+ }
+
+ /* As it was done when enqueueing, prevent hurd_thread_cancel from
+ suspending us while the condition lock is held. */
+ __spin_lock (&ss->lock);
+ __pthread_spin_lock (&cond->__lock);
+ if (! self->prevp)
+ /* Another thread removed us from the list of waiters, which means
+ a wakeup message has been sent. It was either consumed while
+ we were blocking, or queued after we timed out and before we
+ acquired the condition lock, in which case the message queue
+ must be drained. */
+ drain = err ? 1 : 0;
+ else
+ {
+ /* We're still in the list of waiters. Noone attempted to wake us
+ up, i.e. we timed out. */
+ __pthread_dequeue (self);
+ drain = 0;
+ }
+ __pthread_spin_unlock (&cond->__lock);
+
+ if (drain)
+ __pthread_block (self);
+ }
+
+ /* Clear the hook, now that we are done blocking. */
+ ss->cancel_hook = NULL;
+ /* Check the cancellation flag; we might have unblocked due to
+ cancellation rather than a normal pthread_cond_signal or
+ pthread_cond_broadcast (or we might have just happened to get cancelled
+ right after waking up). */
+ cancel |= ss->cancel;
+ ss->cancel = 0;
+ __spin_unlock (&ss->lock);
+
+ if (mutex)
+ /* Reacquire the mutex and return. */
+ __pthread_mutex_lock (mutex);
+
+ if (cancel)
+ return EINTR;
+ else if (err)
+ {
+ assert (err == ETIMEDOUT);
+ return err;
+ }
+
+ return 0;
+}
diff --git a/sysdeps/mach/hurd/pt-hurd-cond-wait.c b/sysdeps/mach/hurd/pt-hurd-cond-wait.c
index d2b5847..5e7c007 100644
--- a/sysdeps/mach/hurd/pt-hurd-cond-wait.c
+++ b/sysdeps/mach/hurd/pt-hurd-cond-wait.c
@@ -23,71 +23,19 @@
#include <pt-internal.h>
+/* Implemented in pt-hurd-cond-timedwait.c. */
+extern int __pthread_hurd_cond_timedwait_internal (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+
int
-pthread_hurd_cond_wait_np (pthread_cond_t *cond, pthread_mutex_t *mutex)
+__pthread_hurd_cond_wait_np (pthread_cond_t *cond,
+ pthread_mutex_t *mutex)
{
- /* This function will be called by hurd_thread_cancel while we are blocked
- We wake up all threads blocked on COND, so our thread will wake up and
- notice the cancellation flag. */
- void cancel_me (void)
- {
- pthread_cond_broadcast (cond);
- }
- struct hurd_sigstate *ss = _hurd_self_sigstate ();
- struct __pthread *self = _pthread_self ();
- int cancel;
-
- assert (ss->intr_port == MACH_PORT_NULL); /* Sanity check for signal bugs. */
-
- /* Atomically enqueue our thread on the condition variable's queue of
- waiters, and mark our sigstate to indicate that `cancel_me' must be
- called to wake us up. We must hold the sigstate lock while acquiring
- the condition variable's lock and tweaking it, so that
- hurd_thread_cancel can never suspend us and then deadlock in
- pthread_cond_broadcast waiting for the condition variable's lock. */
-
- __spin_lock (&ss->lock);
- __pthread_spin_lock (&cond->__lock);
- cancel = ss->cancel;
- if (cancel)
- /* We were cancelled before doing anything. Don't block at all. */
- ss->cancel = 0;
- else
- {
- /* Put us on the queue so that pthread_cond_broadcast will know to wake
- us up. */
- __pthread_enqueue (&cond->__queue, self);
- /* Tell hurd_thread_cancel how to unblock us. */
- ss->cancel_hook = &cancel_me;
- }
- __pthread_spin_unlock (&cond->__lock);
- __spin_unlock (&ss->lock);
-
+ error_t err;
- if (cancel)
- /* Cancelled on entry. Just leave the mutex locked. */
- mutex = NULL;
- else
- {
- /* Now unlock the mutex and block until woken. */
- __pthread_mutex_unlock (mutex);
- __pthread_block (self);
- }
-
- __spin_lock (&ss->lock);
- /* Clear the hook, now that we are done blocking. */
- ss->cancel_hook = NULL;
- /* Check the cancellation flag; we might have unblocked due to
- cancellation rather than a normal pthread_cond_signal or
- pthread_cond_broadcast (or we might have just happened to get cancelled
- right after waking up). */
- cancel |= ss->cancel;
- ss->cancel = 0;
- __spin_unlock (&ss->lock);
-
- if (mutex)
- /* Reacquire the mutex and return. */
- __pthread_mutex_lock (mutex);
-
- return cancel;
+ err = __pthread_hurd_cond_timedwait_internal (cond, mutex, NULL);
+ return (err == EINTR);
}
+
+strong_alias (__pthread_hurd_cond_wait_np, pthread_hurd_cond_wait_np);