diff options
author | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2001-12-08 14:51:37 +0000 |
---|---|---|
committer | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2001-12-08 14:51:37 +0000 |
commit | f12d711b8ff30cbb7e08bb32d88af46cc64c0769 (patch) | |
tree | 5fd6e5a28182f82c323032d9dce6aa32a60b622b /lib/libc_r/uthread | |
parent | 203c9a03b47df77947e1b30e3a939aa45a9a35e0 (diff) |
Partially sync with FreeBSD; mostly pthread_cancel(3) related changes.
make includes is needed in case you want to play.
Diffstat (limited to 'lib/libc_r/uthread')
-rw-r--r-- | lib/libc_r/uthread/pthread_private.h | 25 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_cancel.c | 139 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_cond.c | 13 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_create.c | 7 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_info_openbsd.c | 5 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_init.c | 6 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_kern.c | 36 |
7 files changed, 140 insertions, 91 deletions
diff --git a/lib/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h index 1fbe0dce592..a07ebaf431d 100644 --- a/lib/libc_r/uthread/pthread_private.h +++ b/lib/libc_r/uthread/pthread_private.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pthread_private.h,v 1.29 2001/09/04 23:28:31 fgsch Exp $ */ +/* $OpenBSD: pthread_private.h,v 1.30 2001/12/08 14:51:36 fgsch Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -588,12 +588,6 @@ struct pthread { int sig_saved; /* - * Cancelability state. - */ - int cancelstate; - int canceltype; - - /* * Cancelability flags - the lower 2 bits are used by cancel * definitions in pthread.h */ @@ -703,13 +697,16 @@ struct pthread { int flags; #define PTHREAD_FLAGS_PRIVATE 0x0001 #define PTHREAD_EXITING 0x0002 -#define PTHREAD_FLAGS_IN_CONDQ 0x0004 /* in condition queue using qe link*/ -#define PTHREAD_FLAGS_IN_WORKQ 0x0008 /* in work queue using qe link */ -#define PTHREAD_FLAGS_IN_WAITQ 0x0010 /* in waiting queue using pqe link*/ -#define PTHREAD_FLAGS_IN_PRIOQ 0x0020 /* in priority queue using pqe link*/ -#define PTHREAD_FLAGS_TRACE 0x0040 /* for debugging purposes */ -#define PTHREAD_FLAGS_CANCELED 0x1000 /* thread has been cancelled */ -#define PTHREAD_FLAGS_CANCELPT 0x2000 /* thread at cancel point */ +#define PTHREAD_FLAGS_IN_WAITQ 0x0004 /* in waiting queue using pqe link*/ +#define PTHREAD_FLAGS_IN_PRIOQ 0x0008 /* in priority queue using pqe link*/ +#define PTHREAD_FLAGS_IN_WORKQ 0x0010 /* in work queue using qe link */ +#define PTHREAD_FLAGS_IN_FILEQ 0x0020 /* in file lock queue using qe link */ +#define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */ +#define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/ +#define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link*/ +#define PTHREAD_FLAGS_TRACE 0x0200 /* for debugging purposes */ +#define PTHREAD_FLAGS_IN_SYNQ \ + (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ) /* * Base priority is the user setable and retrievable priority diff --git a/lib/libc_r/uthread/uthread_cancel.c b/lib/libc_r/uthread/uthread_cancel.c index 7f53aed66ce..b536acc4b8e 100644 --- a/lib/libc_r/uthread/uthread_cancel.c +++ b/lib/libc_r/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"); } } diff --git a/lib/libc_r/uthread/uthread_cond.c b/lib/libc_r/uthread/uthread_cond.c index 48ee72a6b2f..dea5d5ffa39 100644 --- a/lib/libc_r/uthread/uthread_cond.c +++ b/lib/libc_r/uthread/uthread_cond.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_cond.c,v 1.10 2001/08/21 19:24:53 fgsch Exp $ */ +/* $OpenBSD: uthread_cond.c,v 1.11 2001/12/08 14:51:36 fgsch Exp $ */ /* * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -159,7 +159,8 @@ int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) { struct pthread *curthread = _get_curthread(); - int rval = 0; + int rval = 0; + int interrupted = 0; /* This is a cancellation point: */ _thread_enter_cancellation_point(); @@ -252,6 +253,9 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) rval = EINVAL; break; } + + if ((interrupted != 0) && (curthread->continuation != NULL)) + curthread->continuation((void *) curthread); } /* No longer in a cancellation point: */ @@ -266,7 +270,8 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime) { struct pthread *curthread = _get_curthread(); - int rval = 0; + int rval = 0; + int interrupted = 0; /* This is a cancellation point: */ _thread_enter_cancellation_point(); @@ -396,6 +401,8 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, break; } + if ((interrupted != 0) && (curthread->continuation != NULL)) + curthread->continuation((void *) curthread); } /* No longer in a cancellation point: */ diff --git a/lib/libc_r/uthread/uthread_create.c b/lib/libc_r/uthread/uthread_create.c index 82606872c1d..5b1897b7ef4 100644 --- a/lib/libc_r/uthread/uthread_create.c +++ b/lib/libc_r/uthread/uthread_create.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_create.c,v 1.15 2001/08/21 19:24:53 fgsch Exp $ */ +/* $OpenBSD: uthread_create.c,v 1.16 2001/12/08 14:51:36 fgsch Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -93,8 +93,8 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr, new_thread->stack = stack; new_thread->start_routine = start_routine; new_thread->arg = arg; - new_thread->cancelstate = PTHREAD_CANCEL_ENABLE; - new_thread->canceltype = PTHREAD_CANCEL_DEFERRED; + new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | + PTHREAD_CANCEL_DEFERRED; /* * Write a magic value to the thread structure @@ -152,6 +152,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr, new_thread->flags = 0; new_thread->poll_data.nfds = 0; new_thread->poll_data.fds = NULL; + new_thread->continuation = NULL; /* * Defer signals to protect the scheduling queues diff --git a/lib/libc_r/uthread/uthread_info_openbsd.c b/lib/libc_r/uthread/uthread_info_openbsd.c index 6a5d24ddf3d..439bf6a7655 100644 --- a/lib/libc_r/uthread/uthread_info_openbsd.c +++ b/lib/libc_r/uthread/uthread_info_openbsd.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_info_openbsd.c,v 1.3 2000/02/26 13:32:01 d Exp $ + * $OpenBSD: uthread_info_openbsd.c,v 1.4 2001/12/08 14:51:36 fgsch Exp $ */ #include <stdio.h> #include <fcntl.h> @@ -129,8 +129,7 @@ _thread_dump_entry(pthread, fd, verbose) pthread->active_priority, (pthread->flags & PTHREAD_FLAGS_PRIVATE) ? 'p' : '-', (pthread->flags & PTHREAD_EXITING) ? 'E' : - (pthread->flags & PTHREAD_FLAGS_CANCELED) ? 'C' : - (pthread->flags & PTHREAD_FLAGS_CANCELPT) ? 'c' : '-', + (pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) ? 'c' : '-', (pthread->flags & PTHREAD_FLAGS_TRACE) ? 't' : '-', (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) ? 'C' : '-', (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) ? 'R' : '-', diff --git a/lib/libc_r/uthread/uthread_init.c b/lib/libc_r/uthread/uthread_init.c index caf5b9e9989..a0aaf8e8964 100644 --- a/lib/libc_r/uthread/uthread_init.c +++ b/lib/libc_r/uthread/uthread_init.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_init.c,v 1.16 2001/09/04 22:17:45 fgsch Exp $ */ +/* $OpenBSD: uthread_init.c,v 1.17 2001/12/08 14:51:36 fgsch Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -175,8 +175,8 @@ _thread_init(void) _thread_initial->magic = PTHREAD_MAGIC; /* Set the initial cancel state */ - _thread_initial->cancelstate = PTHREAD_CANCEL_ENABLE; - _thread_initial->canceltype = PTHREAD_CANCEL_DEFERRED; + _thread_initial->cancelflags = PTHREAD_CANCEL_ENABLE | + PTHREAD_CANCEL_DEFERRED; /* Default the priority of the initial thread: */ _thread_initial->base_priority = PTHREAD_DEFAULT_PRIORITY; diff --git a/lib/libc_r/uthread/uthread_kern.c b/lib/libc_r/uthread/uthread_kern.c index 7522b57b33b..d9a6108397b 100644 --- a/lib/libc_r/uthread/uthread_kern.c +++ b/lib/libc_r/uthread/uthread_kern.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_kern.c,v 1.16 2001/09/04 22:17:45 fgsch Exp $ */ +/* $OpenBSD: uthread_kern.c,v 1.17 2001/12/08 14:51:36 fgsch Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -60,18 +60,6 @@ dequeue_signals(void); static inline void thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in); -static void -_thread_check_cancel() -{ - if (!(_thread_run->flags & PTHREAD_FLAGS_CANCELPT) && - (_thread_run->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)) - /* - * Check if an async-cancellable thread - * has been cancelled. - */ - _thread_cancellation_point(); -} - void _thread_kern_sched(struct sigcontext * scp) { @@ -551,7 +539,13 @@ _thread_kern_sched(struct sigcontext * scp) thread_run_switch_hook(_last_user_thread, _thread_run); } - _thread_check_cancel(); + + if (((curthread->cancelflags & + PTHREAD_AT_CANCEL_POINT) == 0) && + ((curthread->cancelflags & + PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) + pthread_testcancel(); + _thread_sys_sigreturn(&_thread_run->saved_sigcontext); } else { /* @@ -565,7 +559,11 @@ _thread_kern_sched(struct sigcontext * scp) _thread_run); } - _thread_check_cancel(); + if (((curthread->cancelflags & + PTHREAD_AT_CANCEL_POINT) == 0) && + ((curthread->cancelflags & + PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) + pthread_testcancel(); return; } @@ -1064,6 +1062,14 @@ _thread_kern_sig_undefer(void) curthread->sig_defer_count = 0; } + /* + * Check for asynchronous cancellation before delivering any + * pending signals: + */ + if (((curthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0) && + ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) + pthread_testcancel(); + /* Yield the CPU if necessary: */ if (need_resched || curthread->yield_on_sig_undefer != 0) { curthread->yield_on_sig_undefer = 0; |