diff options
author | 2001-12-08 14:51:36 +0000 | |
---|---|---|
committer | 2001-12-08 14:51:36 +0000 | |
commit | 6ac0f2e9f3ee24fce17e680ea1180cafb1eb927f (patch) | |
tree | 2065bacd309ad7857cf9e749ef1ef895538d91be /lib/libpthread/uthread/uthread_cancel.c | |
parent | style: Use queue.h macro's for list traversal, convert several (&thing)->foo (diff) | |
download | wireguard-openbsd-6ac0f2e9f3ee24fce17e680ea1180cafb1eb927f.tar.xz wireguard-openbsd-6ac0f2e9f3ee24fce17e680ea1180cafb1eb927f.zip |
Partially sync with FreeBSD; mostly pthread_cancel(3) related changes.
make includes is needed in case you want to play.
Diffstat (limited to 'lib/libpthread/uthread/uthread_cancel.c')
-rw-r--r-- | lib/libpthread/uthread/uthread_cancel.c | 139 |
1 files changed, 89 insertions, 50 deletions
diff --git a/lib/libpthread/uthread/uthread_cancel.c b/lib/libpthread/uthread/uthread_cancel.c index 7f53aed66ce..b536acc4b8e 100644 --- a/lib/libpthread/uthread/uthread_cancel.c +++ b/lib/libpthread/uthread/uthread_cancel.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_cancel.c,v 1.6 2001/09/04 22:17:45 fgsch Exp $ */ +/* $OpenBSD: uthread_cancel.c,v 1.7 2001/12/08 14:51:36 fgsch Exp $ */ /* * David Leonard <d@openbsd.org>, 1999. Public domain. */ @@ -6,6 +6,9 @@ #include <pthread.h> #include "pthread_private.h" + +static void finish_cancellation(void *arg); + int pthread_cancel(pthread) pthread_t pthread; @@ -16,47 +19,75 @@ pthread_cancel(pthread) /* NOTHING */ } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) { ret = 0; - } else if ((pthread->flags & PTHREAD_FLAGS_CANCELED) == 0) { - /* Set the thread's I've-been-cancelled flag: */ - pthread->flags |= PTHREAD_FLAGS_CANCELED; - /* Check if we need to kick it back into the run queue: */ - if ((pthread->cancelstate == PTHREAD_CANCEL_ENABLE) && - ((pthread->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) || - (pthread->flags & PTHREAD_FLAGS_CANCELPT))) + } else { + /* Protect the scheduling queues: */ + _thread_kern_sig_defer(); + + if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || + (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && + ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) + /* Just mark it for cancellation: */ + pthread->cancelflags |= PTHREAD_CANCELLING; + else { + /* + * Check if we need to kick it back into the + * run queue: + */ switch (pthread->state) { - case PS_WAIT_WAIT: + case PS_RUNNING: + /* No need to resume: */ + pthread->cancelflags |= PTHREAD_CANCELLING; + break; + + case PS_SPINBLOCK: case PS_FDR_WAIT: case PS_FDW_WAIT: - case PS_SLEEP_WAIT: - case PS_SELECT_WAIT: case PS_POLL_WAIT: + case PS_SELECT_WAIT: + if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) + != 0) + PTHREAD_WORKQ_REMOVE(pthread); + /* Fall through: */ + case PS_SIGTHREAD: + case PS_SLEEP_WAIT: + case PS_WAIT_WAIT: case PS_SIGSUSPEND: + case PS_SIGWAIT: /* Interrupt and resume: */ pthread->interrupted = 1; - if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) - PTHREAD_WORKQ_REMOVE(pthread); + pthread->cancelflags |= PTHREAD_CANCELLING; PTHREAD_NEW_STATE(pthread,PS_RUNNING); break; + case PS_MUTEX_WAIT: case PS_COND_WAIT: - case PS_SIGWAIT: case PS_FDLR_WAIT: case PS_FDLW_WAIT: case PS_FILE_WAIT: + pthread->interrupted = 1; + pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + pthread->continuation = finish_cancellation; + break; + case PS_JOIN: case PS_SUSPENDED: - case PS_SIGTHREAD: /* Simply wake: */ /* XXX may be incorrect */ PTHREAD_NEW_STATE(pthread,PS_RUNNING); break; - case PS_RUNNING: - case PS_DEADLOCK: - case PS_SPINBLOCK: + case PS_DEAD: - /* Ignore */ + case PS_DEADLOCK: + case PS_STATE_MAX: + /* Ignore - only here to silence -Wall: */ break; + } } + + /* Unprotect the scheduling queues: */ + _thread_kern_sig_undefer(); + ret = 0; } return (ret); @@ -71,21 +102,21 @@ pthread_setcancelstate(state, oldstate) int ostate; int ret; - ostate = curthread->cancelstate; + ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; switch (state) { case PTHREAD_CANCEL_ENABLE: - if (oldstate) + if (oldstate != NULL) *oldstate = ostate; - curthread->cancelstate = PTHREAD_CANCEL_ENABLE; - if (curthread->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) - _thread_cancellation_point(); + curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; + if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0) + pthread_testcancel(); ret = 0; break; case PTHREAD_CANCEL_DISABLE: - if (oldstate) + if (oldstate != NULL) *oldstate = ostate; - curthread->cancelstate = PTHREAD_CANCEL_DISABLE; + curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; ret = 0; break; default: @@ -105,19 +136,19 @@ pthread_setcanceltype(type, oldtype) int otype; int ret; - otype = curthread->canceltype; + otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; switch (type) { case PTHREAD_CANCEL_ASYNCHRONOUS: - if (oldtype) + if (oldtype != NULL) *oldtype = otype; - curthread->canceltype = PTHREAD_CANCEL_ASYNCHRONOUS; - _thread_cancellation_point(); + curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; + pthread_testcancel(); ret = 0; break; case PTHREAD_CANCEL_DEFERRED: - if (oldtype) + if (oldtype != NULL) *oldtype = otype; - curthread->canceltype = PTHREAD_CANCEL_DEFERRED; + curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; ret = 0; break; default: @@ -130,44 +161,52 @@ pthread_setcanceltype(type, oldtype) void pthread_testcancel() { + struct pthread *curthread = _get_curthread(); - _thread_cancellation_point(); + if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && + ((curthread->cancelflags & PTHREAD_CANCELLING) != 0)) { + curthread->cancelflags &= ~PTHREAD_CANCELLING; +#ifdef notyet + _thread_exit_cleanup(); +#endif + pthread_exit(PTHREAD_CANCELED); + PANIC("cancel"); + } } void -_thread_enter_cancellation_point() +_thread_enter_cancellation_point(void) { struct pthread *curthread = _get_curthread(); /* Look for a cancellation before we block: */ - _thread_cancellation_point(); - curthread->flags |= PTHREAD_FLAGS_CANCELPT; + pthread_testcancel(); + curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; } void -_thread_leave_cancellation_point() +_thread_leave_cancellation_point(void) { struct pthread *curthread = _get_curthread(); - curthread->flags &=~ PTHREAD_FLAGS_CANCELPT; + curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; /* Look for a cancellation after we unblock: */ - _thread_cancellation_point(); + pthread_testcancel(); } -/* - * Must only be called when in asynchronous cancel mode, or - * from pthread_testcancel(). - */ -void -_thread_cancellation_point() +static void +finish_cancellation(void *arg) { struct pthread *curthread = _get_curthread(); - if ((curthread->cancelstate == PTHREAD_CANCEL_ENABLE) && - ((curthread->flags & (PTHREAD_FLAGS_CANCELED|PTHREAD_EXITING)) == - PTHREAD_FLAGS_CANCELED)) { - curthread->flags &=~ PTHREAD_FLAGS_CANCELED; + curthread->continuation = NULL; + curthread->interrupted = 0; + + if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) { + curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED; +#ifdef notyet + _thread_exit_cleanup(); +#endif pthread_exit(PTHREAD_CANCELED); - PANIC("cancel"); } } |