summaryrefslogtreecommitdiff
path: root/pthread/pt-setcanceltype.c
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2013-02-03 16:06:51 +0100
committerRichard Braun <rbraun@sceen.net>2013-02-04 00:07:13 +0100
commit5ab516af0779a7fd74ad893c7c67960df6ede065 (patch)
tree568a297810b4ba52c351c3f79276205b0b87f20e /pthread/pt-setcanceltype.c
parent14eeff65f732d77bc8d93bd5e1979fa6083b66d8 (diff)
Fix pthread timeout handling and cancellation issues
This patch solves two issues. The first one is cancellation handling when a cancellation request is sent before reaching a cancellation point (namely, pthread_cond_{timed,}wait). Cancellation is implemented by pushing an appropriate cleanup handler and switching to PTHREAD_CANCEL_ASYNCHRONOUS type. The main problem is that it doesn't handle pending requests, only a cancellation that occurs while blocking. Other problems occur when trying to correctly handle a timeout and a cancellation request through the cleanup routine. The other issue is correctly handling timeouts. This problem was already well known, as explained by the following comment : "FIXME: What do we do if we get a wakeup message before we disconnect ourself? It may remain until the next time we block." In addition, the prevp thread member is inconsistently used. It is sometimes accessed while protected by the appropriate queue lock to determine whether a thread is still queued, while at times, threads are unqueued without holding a lock, as in pthread_cond_broadcast : /* We can safely walk the list of waiting threads without holding the lock since it is now decoupled from the condition. */ __pthread_dequeuing_iterate (wakeup, wakeup) __pthread_wakeup (wakeup); This is the root cause that triggers some assertion failures. The solution brought by this patch is to consistently use the prevp link to determine if both a thread has been unqueued and if a wakeup message has been sent (both are needed to wake up a thread). A thread unblocked because of a timeout can now accurately determine if it needs to drain its message queue. A direct improvement is that the message queue size can be limited to one message, and wakeups are guaranteed to be non-blocking, which allows safely calling __pthread_wakeup from critical sections. As it now affects the cleanup cancellation routine of __pthread_cond_timedwait_internal, cancellation is reworked as well. Cancellation type is forced to PTHREAD_CANCEL_DEFERRED during the call, and actually checked on both entry and return. A hook is set by the blocking thread so that the waker doesn't need to know about the call implementation. Cancellation members are now protected with a mutex for truely safe access. * pthread/pt-alloc.c (initialize_pthread): Initialize the new `cancel_lock', `cancel_hook' and `cancel_hook_args' fields. * pthread/pt-cancel.c (pthread_cancel): Rework cancellation handling. * pthread/pt-internal.h (struct __pthread): Add `cancel_lock', `cancel_hook' and `cancel_hook_args' fields. (__pthread_dequeue): Assert thread->prevp isn't NULL. * pthread/pt-join.c (pthread_join): Describe how the cancellation point is implemented. * pthread/pt-setcancelstate.c (__pthread_setcancelstate): Lock the given thread cancellation lock when switching state. * pthread/pt-setcanceltype.c (__pthread_setcanceltype): Likewise for cancellation type. * pthread/pt-testcancel.c (pthread_testcancel): Likewise for pending cancellations. * sysdeps/generic/pt-cond-brdcast.c (__pthread_cond_broadcast): Dequeue and wake up threads with condition locked. * sysdeps/generic/pt-cond-signal.c (cond_signal): Remove function, move implementation to ... (__pthread_cond_signal): ... this function. Remove unused `unblocked' variable. * sysdeps/generic/pt-cond-timedwait.c (struct cancel_ctx): New structure. (cancel_hook): New static function. (__pthread_cond_timedwait_internal): Fix cancellation and timeout handling. * sysdeps/generic/pt-mutex-timedlock.c (__pthread_mutex_timedlock_internal): Fix timeout handling. * sysdeps/generic/pt-rwlock-timedrdlock.c (__pthread_rwlock_timedrdlock_internal): Likewise. * sysdeps/generic/pt-rwlock-timedwrlock.c (__pthread_rwlock_timedwrlock_internal): Likewise. * sysdeps/generic/pt-rwlock-unlock.c (pthread_rwlock_unlock): Dequeue and wake up threads with rwlock internal lock held. * sysdeps/generic/sem-timedwait.c (__sem_timedwait_internal): Fix timeout handling. * sysdeps/mach/hurd/pt-docancel.c (__pthread_do_cancel): Unlock the given thread cancellation lock. * sysdeps/mach/pt-thread-alloc.c (create_wakeupmsg): Limit the message queue size of the wakeup port to 1. * sysdeps/mach/pt-wakeup.c (__pthread_wakeup): Call __mach_msg in a non-blocking way.
Diffstat (limited to 'pthread/pt-setcanceltype.c')
-rw-r--r--pthread/pt-setcanceltype.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/pthread/pt-setcanceltype.c b/pthread/pt-setcanceltype.c
index 7226a3a..3cfbe9c 100644
--- a/pthread/pt-setcanceltype.c
+++ b/pthread/pt-setcanceltype.c
@@ -35,9 +35,11 @@ __pthread_setcanceltype (int type, int *oldtype)
break;
}
+ __pthread_mutex_lock (&p->cancel_lock);
if (oldtype)
*oldtype = p->cancel_type;
p->cancel_type = type;
+ __pthread_mutex_unlock (&p->cancel_lock);
return 0;
}