diff options
Diffstat (limited to 'nptl/pthread_setcanceltype.c')
-rw-r--r-- | nptl/pthread_setcanceltype.c | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/nptl/pthread_setcanceltype.c b/nptl/pthread_setcanceltype.c index 94e56466de..1307d355c1 100644 --- a/nptl/pthread_setcanceltype.c +++ b/nptl/pthread_setcanceltype.c @@ -28,11 +28,32 @@ __pthread_setcanceltype (int type, int *oldtype) volatile struct pthread *self = THREAD_SELF; - if (oldtype != NULL) - *oldtype = self->canceltype; - self->canceltype = type; - if (type == PTHREAD_CANCEL_ASYNCHRONOUS) - __pthread_testcancel (); + int oldval = atomic_load_relaxed (&self->cancelhandling); + while (1) + { + int newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS + ? oldval | CANCELTYPE_BITMASK + : oldval & ~CANCELTYPE_BITMASK); + + if (oldtype != NULL) + *oldtype = ((oldval & CANCELTYPE_BITMASK) + ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED); + + if (oldval == newval) + break; + + if (atomic_compare_exchange_weak_acquire (&self->cancelhandling, + &oldval, newval)) + { + if (cancel_enabled_and_canceled_and_async (newval)) + { + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + __do_cancel (); + } + + break; + } + } return 0; } |