diff options
author | David Leonard <d@cvs.openbsd.org> | 1999-01-17 23:57:29 +0000 |
---|---|---|
committer | David Leonard <d@cvs.openbsd.org> | 1999-01-17 23:57:29 +0000 |
commit | 5ca1f71120ac2bc81b65a6cef298606b92242903 (patch) | |
tree | 82d901bf8097936d39c68cdb89cc598d1e1fccd6 | |
parent | 209640f64878cc32de9cf45178c9a0e979525bdd (diff) |
pthread_cancel() and cancellation points
33 files changed, 1130 insertions, 38 deletions
diff --git a/lib/libc_r/TEST/test_cancel.c b/lib/libc_r/TEST/test_cancel.c new file mode 100644 index 00000000000..74ecaf317d9 --- /dev/null +++ b/lib/libc_r/TEST/test_cancel.c @@ -0,0 +1,174 @@ +/* $OpenBSD: test_cancel.c,v 1.1 1999/01/17 23:57:26 d Exp $ */ +/* David Leonard <d@openbsd.org>, 1999. Public Domain. */ + +#include <pthread.h> +#include <pthread_np.h> +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include "test.h" + +static pthread_cond_t cond; +static pthread_mutex_t mutex; +static struct timespec expiretime; + +static int pv_state = 0; +void p() { + CHECKr(pthread_mutex_lock(&mutex)); + if (pv_state <= 0) { + CHECKr(pthread_cond_timedwait(&cond, &mutex, &expiretime)); + } + pv_state--; + CHECKr(pthread_mutex_unlock(&mutex)); +} + +void v() { + int needsignal; + + CHECKr(pthread_mutex_lock(&mutex)); + pv_state++; + needsignal = (pv_state == 1); + if (needsignal) + CHECKr(pthread_cond_signal(&cond)); + CHECKr(pthread_mutex_unlock(&mutex)); +} + +void +c1handler(void *fd) +{ + CHECKe(close((int)fd)); + v(); +} + +void * +child1fn(arg) + void *arg; +{ + int fd; + char buf[1024]; + int len; + + pthread_set_name_np(pthread_self(), "c1"); + CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); + /* something that will block */ + CHECKe(fd = open("/dev/tty", O_RDONLY)); + pthread_cleanup_push(c1handler, (void *)fd); + v(); + while (1) { + CHECKe(len = read(fd, &buf, sizeof buf)); + printf("child 1 read %d bytes\n", len); + } + PANIC("child 1"); +} + +static int c2_in_test = 0; + +void +c2handler(void *arg) +{ + ASSERT(c2_in_test); + v(); +} + +void * +child2fn(arg) + void *arg; +{ + pthread_set_name_np(pthread_self(), "c2"); + + CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)); + pthread_cleanup_push(c2handler, NULL); + v(); + + while (1) { + struct timespec now; + struct timespec end; + + /* + * XXX Be careful not to call any cancellation points + * until pthread_testcancel() + */ + + CHECKe(clock_gettime(CLOCK_REALTIME, &end)); + end.tv_sec ++; + + while (1) { + CHECKe(clock_gettime(CLOCK_REALTIME, &now)); + if (timespeccmp(&now, &end, >=)) + break; + pthread_yield(); + } + + /* XXX write() contains a cancellation point */ + /* printf("child 2 testing for cancel\n"); */ + + c2_in_test = 1; + pthread_testcancel(); + printf("you should see this message exactly once\n"); + c2_in_test = 0; + } + PANIC("child 2"); +} + +static int c3_cancel_survived; + +void +c3handler(void *arg) +{ + printf("(fyi, cancellation of self %s instantaneous)\n", + (c3_cancel_survived ? "was not" : "was")); + v(); +} + +void * +child3fn(arg) + void *arg; +{ + pthread_set_name_np(pthread_self(), "c3"); + pthread_cleanup_push(c3handler, NULL); + + /* Cancel myself */ + CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); + c3_cancel_survived = 0; + pthread_cancel(pthread_self()); + c3_cancel_survived = 1; + pthread_testcancel(); + + PANIC("child 3"); +} + +int +main() +{ + pthread_t child1, child2, child3; + + /* Set up our control flow */ + CHECKr(pthread_mutex_init(&mutex, NULL)); + CHECKr(pthread_cond_init(&cond, NULL)); + CHECKe(clock_gettime(CLOCK_REALTIME, &expiretime)); + expiretime.tv_sec += 5; /* this test shouldn't run over 5 seconds */ + + CHECKr(pthread_create(&child1, NULL, child1fn, NULL)); + CHECKr(pthread_create(&child2, NULL, child2fn, NULL)); + p(); + p(); + + CHECKr(pthread_cancel(child1)); + p(); + + /* Give thread 2 a change to go through its deferred loop once */ + sleep(2); + CHECKr(pthread_cancel(child2)); + p(); + + /* Child 3 cancels itself */ + CHECKr(pthread_create(&child3, NULL, child3fn, NULL)); + p(); + + /* Make sure they're all gone */ + CHECKr(pthread_join(child3, NULL)); + CHECKr(pthread_join(child2, NULL)); + CHECKr(pthread_join(child1, NULL)); + + exit(0); +} diff --git a/lib/libc_r/man/pthread_cancel.3 b/lib/libc_r/man/pthread_cancel.3 new file mode 100644 index 00000000000..8522098a34e --- /dev/null +++ b/lib/libc_r/man/pthread_cancel.3 @@ -0,0 +1,65 @@ +.Dd January 17, 1999 +.Dt PTHREAD_CANCEL 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cancel +.Nd cancel execution of a thread +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_cancel "pthread_t thread" +.Sh DESCRIPTION +The +.Fn pthread_cancel +function requests that +.Fa thread +be canceled. The target thread's cancelability state and type determines +when the cancellation takes effect. When the cancellation is acted on, +the cancellation cleanup handlers for +.Fa thread +are called. When the last cancellation cleanup handler returns, +the thread-specific data destructor functions will be called for +.Fa thread . +When the last destructor function returns, +.Fa thread +will be terminated. +.Pp +The cancellation processing in the target thread runs asynchronously with +respect to the calling thread returning from +.Fn pthread_cancel . +.Pp +A status of +.Dv PTHREAD_CANCELED +is made available to any threads joining with the target. The symbolic +constant +.Dv PTHREAD_CANCELED +expands to a constant expression of type +.Ft "(void *)" , +whose value matches no pointer to an object in memory nor the value +.Dv NULL . +.Sh RETURN VALUES +If successful, the +.Fn pthread_cancel +functions will return zero. Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_cancel +will fail if: +.Bl -tag -width Er +.It Bq Er ESRCH +No thread could be found corresponding to that specified by the given +thread ID. +.El +.Sh SEE ALSO +.Xr pthread_testcancel 3 , +.Xr pthread_setcancelstate 3 , +.Xr pthread_setcanceltype 3 , +.Xr pthread_cleanup_pop 3 , +.Xr pthread_cleanup_push 3 , +.Xr pthread_exit 3 , +.Xr pthread_join 3 +.Sh STANDARDS +.Fn pthread_cancel +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libc_r/man/pthread_testcancel.3 b/lib/libc_r/man/pthread_testcancel.3 new file mode 100644 index 00000000000..1cd02e8fe83 --- /dev/null +++ b/lib/libc_r/man/pthread_testcancel.3 @@ -0,0 +1,182 @@ +.Dd January 17, 1999 +.Dt PTHREAD_TESTCANCEL 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_setcancelstate , +.Nm pthread_setcanceltype , +.Nm pthread_testcancel +.Nd set cancelability state +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_setcancelstate "int state" "int *oldstate" +.Ft int +.Fn pthread_setcanceltype "int type" "int *oldtype" +.Ft void +.Fn pthread_testcancel "void" +.Sh DESCRIPTION +The +.Fn pthread_setcancelstate +function atomically both sets the calling thread's cancelability state +to the indicated +.Fa state +and returns the previous cancelability state at the location referenced by +.Fa oldstate . +Legal values for +.Fa state +are +.Dv PTHREAD_CANCEL_ENABLE +and +.Dv PTHREAD_CANCEL_DISABLE . +.Pp +The +.Fn pthread_setcanceltype +function atomically both sets the calling thread's cancelability type +to the indicated +.Fa type +and returns the previous cancelability type at the location referenced by +.Fa oldtype . +Legal values for +.Fa type +are +.Dv PTHREAD_CANCEL_DEFERRED +and +.Dv PTHREAD_CANCEL_ASYNCHRONOUS . +.Pp +The cancelability state and type of any newly created threads, including the +thread in which +.Fn main +was first invoked, are +.Dv PTHREAD_CANCEL_ENABLE +and +.Dv PTHREAD_CANCEL_DEFERRED +respectively. +.Pp +The +.Fn pthread_testcancel +function creates a cancellation point in the calling thread. The +.Fn pthread_testcancel +function has no effect if cancelability is disabled. +.Pp +.Ss Cancelability States +The cancelability state of a thread determines the action taken upon +receipt of a cancellation request. The thread may control cancellation in +a number of ways. +.Pp +Each thread maintains its own +.Dq cancelability state +which may be encoded in two bits: +.Bl -hang +.It Em Cancelability Enable +When cancelability is +.Dv PTHREAD_CANCEL_DISABLE , +cancellation requests against the target thread are held pending. +.It Em Cancelability Type +When cancelability is enabled and the cancelability type is +.Dv PTHREAD_CANCEL_ASYNCHRONOUS , +new or pending cancellation requests may be acted upon at any time. +When cancelability is enabled and the cancelability type is +.Dv PTHREAD_CANCEL_DEFERRED , +cancellation requests are held pending until a cancellation point (see +below) is reached. If cancelability is disabled, the setting of the +cancelability type has no immediate effect as all cancellation requests +are held pending, however, once cancelability is enabled again the new +type will be in effect. +.El +.Ss Cancellation Points +Cancellation points will occur when a thread is executing the following +functions: +.Fn close , +.Fn creat , +.Fn fcntl , +.Fn fsync , +.Fn msync , +.Fn nanosleep , +.Fn open , +.Fn pause , +.Fn pthread_cond_timedwait , +.Fn pthread_cond_wait , +.Fn pthread_join , +.Fn pthread_testcancel , +.Fn read , +.Fn sigwaitinfo , +.Fn sigsuspend , +.Fn sigwait , +.Fn sleep , +.Fn system , +.Fn tcdrain , +.Fn wait , +.Fn waitpid , +.Fn write . +.Sh RETURN VALUES +If successful, the +.Fn pthread_setcancelstate +and +.Fn pthread_setcanceltype +functions will return zero. Otherwise, an error number shall be returned to +indicate the error. +.Pp +The +.Fn pthread_setcancelstate +and +.Fn pthread_setcanceltype +functions are used to control the points at which a thread may be +asynchronously canceled. For cancellation control to be usable in modular +fashion, some rules must be followed. +.Pp +For purposes of this discussion, consider an object to be a generalization +of a procedure. It is a set of procedures and global variables written as +a unit and called by clients not known by the object. Objects may depend +on other objects. +.Pp +First, cancelability should only be disabled on entry to an object, never +explicitly enabled. On exit from an object, the cancelability state should +always be restored to its value on entry to the object. +.Pp +This follows from a modularity argument: if the client of an object (or the +client of an object that uses that object) has disabled cancelability, it is +because the client doesn't want to have to worry about how to clean up if the +thread is canceled while executing some sequence of actions. If an object +is called in such a state and it enables cancelability and a cancellation +request is pending for that thread, then the thread will be canceled, +contrary to the wish of the client that disabled. +.Pp +Second, the cancelability type may be explicitly set to either +.Em deferred +or +.Em asynchronous +upon entry to an object. But as with the cancelability state, on exit from +an object that cancelability type should always be restored to its value on +entry to the object. +.Pp +Finally, only functions that are cancel-safe may be called from a thread that +is asynchronously cancelable. +.Sh ERRORS +The function +.Fn pthread_setcancelstate +may fail with: +.Bl -tag -width Er +.It Bq Er EINVAL +The specified state is not +.Dv PTHREAD_CANCEL_ENABLE +or +.Dv PTHREAD_CANCEL_DISABLE . +.El +.Pp +The function +.Fn pthread_setcanceltype +may fail with: +.Bl -tag -width Er +.It Bq Er EINVAL +The specified state is not +.Dv PTHREAD_CANCEL_DEFERRED +or +.Dv PTHREAD_CANCEL_ASYNCHRONOUS . +.El +.Sh SEE ALSO +.Xr pthread_cancel 3 +.Sh STANDARDS +.Fn pthread_testcancel +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libc_r/uthread/uthread_cancel.c b/lib/libc_r/uthread/uthread_cancel.c new file mode 100644 index 00000000000..f3a205d1e9e --- /dev/null +++ b/lib/libc_r/uthread/uthread_cancel.c @@ -0,0 +1,164 @@ +/* + * David Leonard <d@openbsd.org>, 1999. Public domain. + */ +#include <sys/errno.h> +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_cancel(pthread) + pthread_t pthread; +{ + int ret; + + if ((ret = _find_thread(pthread))) { + } else if (pthread->state == PS_DEAD) + ret = 0; + else { + /* Set the threads's I've-been-cancelled flag: */ + pthread->flags |= PTHREAD_CANCELLING; + /* 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_AT_CANCEL_POINT))) + switch (pthread->state) { + case PS_RUNNING: + /* No need to resume: */ + break; + case PS_WAIT_WAIT: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_SLEEP_WAIT: + case PS_SELECT_WAIT: + case PS_SIGSUSPEND: + /* Interrupt and resume: */ + pthread->interrupted = 1; + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + break; + case PS_MUTEX_WAIT: + case PS_COND_WAIT: + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + case PS_SIGWAIT: + case PS_JOIN: + case PS_SUSPENDED: + case PS_SIGTHREAD: + /* Simply wake: */ + /* XXX may be incorrect */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + break; + case PS_DEAD: + case PS_STATE_MAX: + /* Ignore */ + break; + } + ret = 0; + } + return (ret); +} + +int +pthread_setcancelstate(state, oldstate) + int state; + int *oldstate; +{ + int ostate; + int ret; + + ostate = _thread_run->cancelstate; + + switch (state) { + case PTHREAD_CANCEL_ENABLE: + if (oldstate) + *oldstate = ostate; + _thread_run->cancelstate = PTHREAD_CANCEL_ENABLE; + if (_thread_run->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + _thread_cancellation_point(); + ret = 0; + break; + case PTHREAD_CANCEL_DISABLE: + if (oldstate) + *oldstate = ostate; + _thread_run->cancelstate = PTHREAD_CANCEL_DISABLE; + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + + +int +pthread_setcanceltype(type, oldtype) + int type; + int *oldtype; +{ + int otype; + int ret; + + otype = _thread_run->canceltype; + switch (type) { + case PTHREAD_CANCEL_ASYNCHRONOUS: + if (oldtype) + *oldtype = otype; + _thread_run->canceltype = PTHREAD_CANCEL_ASYNCHRONOUS; + _thread_cancellation_point(); + ret = 0; + break; + case PTHREAD_CANCEL_DEFERRED: + if (oldtype) + *oldtype = otype; + _thread_run->canceltype = PTHREAD_CANCEL_DEFERRED; + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + +void +pthread_testcancel() +{ + + _thread_cancellation_point(); +} + +void +_thread_enter_cancellation_point() +{ + + /* Look for a cancellation before we block: */ + _thread_cancellation_point(); + _thread_run->flags |= PTHREAD_AT_CANCEL_POINT; +} + +void +_thread_leave_cancellation_point() +{ + + _thread_run->flags &=~ PTHREAD_AT_CANCEL_POINT; + /* Look for a cancellation after we unblock: */ + _thread_cancellation_point(); +} + +/* + * Must only be called when in asynchronous cancel mode, or + * from pthread_testcancel(). + */ +void +_thread_cancellation_point() +{ + + if ((_thread_run->cancelstate == PTHREAD_CANCEL_ENABLE) && + ((_thread_run->flags & (PTHREAD_CANCELLING|PTHREAD_EXITING)) == + PTHREAD_CANCELLING)) { + _thread_run->flags &=~ PTHREAD_CANCELLING; + pthread_exit(PTHREAD_CANCELED); + PANIC("cancel"); + } +} diff --git a/lib/libc_r/uthread/uthread_close.c b/lib/libc_r/uthread/uthread_close.c index 7d95fbb3196..bc94d162b2a 100644 --- a/lib/libc_r/uthread/uthread_close.c +++ b/lib/libc_r/uthread/uthread_close.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_close.c,v 1.3 1999/01/06 05:29:22 d Exp $ + * $OpenBSD: uthread_close.c,v 1.4 1999/01/17 23:57:27 d Exp $ */ #include <stdlib.h> #include <unistd.h> @@ -46,6 +46,7 @@ close(int fd) int ret; struct stat sb; + _thread_enter_cancellation_point(); /* Lock the file descriptor while the file is closed: */ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { /* Get file descriptor status. */ @@ -84,6 +85,7 @@ close(int fd) free(_thread_fd_table[fd]); _thread_fd_table[fd] = NULL; } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libc_r/uthread/uthread_cond.c b/lib/libc_r/uthread/uthread_cond.c index b2ef3df1ac5..525f86049b0 100644 --- a/lib/libc_r/uthread/uthread_cond.c +++ b/lib/libc_r/uthread/uthread_cond.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_cond.c,v 1.4 1999/01/06 05:29:22 d Exp $ + * $OpenBSD: uthread_cond.c,v 1.5 1999/01/17 23:57:27 d Exp $ */ #include <stdlib.h> #include <errno.h> @@ -137,6 +137,8 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) */ else if (*cond != NULL || (rval = pthread_cond_init(cond,NULL)) == 0) { + _thread_enter_cancellation_point(); + /* Lock the condition variable structure: */ _SPINLOCK(&(*cond)->lock); @@ -185,6 +187,7 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) break; } + _thread_leave_cancellation_point(); } /* Return the completion status: */ @@ -206,6 +209,7 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, */ else if (*cond != NULL || (rval = pthread_cond_init(cond,NULL)) == 0) { + _thread_enter_cancellation_point(); /* Lock the condition variable structure: */ _SPINLOCK(&(*cond)->lock); @@ -263,7 +267,7 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, rval = EINVAL; break; } - + _thread_leave_cancellation_point(); } /* Return the completion status: */ diff --git a/lib/libc_r/uthread/uthread_create.c b/lib/libc_r/uthread/uthread_create.c index 178c35424b8..1ed287d2b1b 100644 --- a/lib/libc_r/uthread/uthread_create.c +++ b/lib/libc_r/uthread/uthread_create.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_create.c,v 1.5 1999/01/06 05:29:22 d Exp $ + * $OpenBSD: uthread_create.c,v 1.6 1999/01/17 23:57:27 d Exp $ */ #include <errno.h> #include <stdlib.h> @@ -93,6 +93,9 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr, timerclear(&new_thread->ru_stime); _SPINUNLOCK(&new_thread->lock); + new_thread->cancelstate = PTHREAD_CANCEL_ENABLE; + new_thread->canceltype = PTHREAD_CANCEL_DEFERRED; + /* * Write a magic value to the thread structure * to help identify valid ones: @@ -109,7 +112,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr, new_thread->sigmask = _thread_run->sigmask; /* Initialise the jump buffer: */ - setjmp(new_thread->saved_jmp_buf); + _thread_machdep_setjmp(new_thread->saved_jmp_buf); /* * Set up new stack frame so that it looks like it diff --git a/lib/libc_r/uthread/uthread_fcntl.c b/lib/libc_r/uthread/uthread_fcntl.c index e7e11a2e218..1a0a3e9548a 100644 --- a/lib/libc_r/uthread/uthread_fcntl.c +++ b/lib/libc_r/uthread/uthread_fcntl.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_fcntl.c,v 1.3 1999/01/06 05:29:23 d Exp $ + * $OpenBSD: uthread_fcntl.c,v 1.4 1999/01/17 23:57:27 d Exp $ */ #include <stdarg.h> #include <unistd.h> @@ -47,6 +47,8 @@ fcntl(int fd, int cmd,...) int ret; va_list ap; + _thread_enter_cancellation_point(); + /* Lock the file descriptor: */ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { /* Initialise the variable argument list: */ @@ -135,6 +137,7 @@ fcntl(int fd, int cmd,...) /* Unlock the file descriptor: */ _FD_UNLOCK(fd, FD_RDWR); } + _thread_leave_cancellation_point(); /* Return the completion status: */ return (ret); diff --git a/lib/libc_r/uthread/uthread_fsync.c b/lib/libc_r/uthread/uthread_fsync.c index 4c953443e95..9db34f5564c 100644 --- a/lib/libc_r/uthread/uthread_fsync.c +++ b/lib/libc_r/uthread/uthread_fsync.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_fsync.c,v 1.2 1999/01/06 05:29:24 d Exp $ + * $OpenBSD: uthread_fsync.c,v 1.3 1999/01/17 23:57:27 d Exp $ */ #include <unistd.h> #ifdef _THREAD_SAFE @@ -41,10 +41,12 @@ fsync(int fd) { int ret; + _thread_enter_cancellation_point(); if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { ret = _thread_sys_fsync(fd); _FD_UNLOCK(fd, FD_RDWR); } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libc_r/uthread/uthread_init.c b/lib/libc_r/uthread/uthread_init.c index ad56b9a670c..0cd5bd376c4 100644 --- a/lib/libc_r/uthread/uthread_init.c +++ b/lib/libc_r/uthread/uthread_init.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_init.c,v 1.7 1999/01/10 23:11:33 d Exp $ + * $OpenBSD: uthread_init.c,v 1.8 1999/01/17 23:57:27 d Exp $ */ #include <errno.h> @@ -224,6 +224,8 @@ _thread_init(void) _thread_initial->nxt = NULL; _thread_initial->flags = 0; _thread_initial->error = 0; + _thread_initial->cancelstate = PTHREAD_CANCEL_ENABLE; + _thread_initial->canceltype = PTHREAD_CANCEL_DEFERRED; _thread_initial->magic = PTHREAD_MAGIC; pthread_set_name_np(_thread_initial, "init"); _SPINUNLOCK(&_thread_initial->lock); diff --git a/lib/libc_r/uthread/uthread_join.c b/lib/libc_r/uthread/uthread_join.c index 9602ec52a25..52baee31c33 100644 --- a/lib/libc_r/uthread/uthread_join.c +++ b/lib/libc_r/uthread/uthread_join.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_join.c,v 1.2 1999/01/06 05:29:24 d Exp $ + * $OpenBSD: uthread_join.c,v 1.3 1999/01/17 23:57:27 d Exp $ */ #include <errno.h> #ifdef _THREAD_SAFE @@ -42,15 +42,21 @@ pthread_join(pthread_t pthread, void **thread_return) int ret = 0; pthread_t pthread1 = NULL; + _thread_enter_cancellation_point(); + /* Check if the caller has specified an invalid thread: */ - if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) { /* Invalid thread: */ + _thread_leave_cancellation_point(); return(EINVAL); + } /* Check if the caller has specified itself: */ - if (pthread == _thread_run) + if (pthread == _thread_run) { /* Avoid a deadlock condition: */ + _thread_leave_cancellation_point(); return(EDEADLK); + } /* * Find the thread in the list of active threads or in the @@ -93,6 +99,8 @@ pthread_join(pthread_t pthread, void **thread_return) /* Return the thread's return value: */ *thread_return = pthread->ret; + _thread_leave_cancellation_point(); + /* Return the completion status: */ return (ret); } diff --git a/lib/libc_r/uthread/uthread_nanosleep.c b/lib/libc_r/uthread/uthread_nanosleep.c index 450b505bf12..0f5c4c9c2ab 100644 --- a/lib/libc_r/uthread/uthread_nanosleep.c +++ b/lib/libc_r/uthread/uthread_nanosleep.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_nanosleep.c,v 1.2 1999/01/06 05:29:25 d Exp $ + * $OpenBSD: uthread_nanosleep.c,v 1.3 1999/01/17 23:57:27 d Exp $ */ #include <stdio.h> #include <errno.h> @@ -48,6 +48,7 @@ nanosleep(const struct timespec * time_to_sleep, struct timespec remaining_time; struct timeval tv; + _thread_enter_cancellation_point(); /* Check if the time to sleep is legal: */ if (time_to_sleep == NULL || time_to_sleep->tv_nsec < 0 || time_to_sleep->tv_nsec > 1000000000 || time_to_sleep->tv_sec < 0) { /* Return an EINVAL error : */ @@ -95,6 +96,7 @@ nanosleep(const struct timespec * time_to_sleep, ret = -1; } } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libc_r/uthread/uthread_open.c b/lib/libc_r/uthread/uthread_open.c index 52d0a6b06cf..9c03daa4f47 100644 --- a/lib/libc_r/uthread/uthread_open.c +++ b/lib/libc_r/uthread/uthread_open.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: uthread_open.c,v 1.4 1998/04/29 09:59:07 jb Exp $ - * $OpenBSD: uthread_open.c,v 1.2 1998/12/23 22:49:46 d Exp $ + * $OpenBSD: uthread_open.c,v 1.3 1999/01/17 23:57:27 d Exp $ * */ #include <stdarg.h> @@ -49,6 +49,8 @@ open(const char *path, int flags,...) int mode = 0; va_list ap; + _thread_enter_cancellation_point(); + /* Check if the file is being created: */ if (flags & O_CREAT) { /* Get the creation mode: */ @@ -68,6 +70,8 @@ open(const char *path, int flags,...) fd = -1; } + _thread_leave_cancellation_point(); + /* Return the file descriptor or -1 on error: */ return (fd); } diff --git a/lib/libc_r/uthread/uthread_read.c b/lib/libc_r/uthread/uthread_read.c index 37b0c9067bb..22d1d03f091 100644 --- a/lib/libc_r/uthread/uthread_read.c +++ b/lib/libc_r/uthread/uthread_read.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: uthread_read.c,v 1.6 1998/06/10 22:28:43 jb Exp $ - * $OpenBSD: uthread_read.c,v 1.2 1998/12/23 22:49:46 d Exp $ + * $OpenBSD: uthread_read.c,v 1.3 1999/01/17 23:57:27 d Exp $ * */ #include <sys/types.h> @@ -48,9 +48,13 @@ read(int fd, void *buf, size_t nbytes) int ret; int type; + _thread_enter_cancellation_point(); + /* POSIX says to do just this: */ - if (nbytes == 0) + if (nbytes == 0) { + _thread_leave_cancellation_point(); return (0); + } /* Lock the file descriptor for read: */ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { @@ -62,6 +66,7 @@ read(int fd, void *buf, size_t nbytes) /* File is not open for read: */ errno = EBADF; _FD_UNLOCK(fd, FD_READ); + _thread_leave_cancellation_point(); return (-1); } @@ -93,6 +98,7 @@ read(int fd, void *buf, size_t nbytes) } _FD_UNLOCK(fd, FD_READ); } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libc_r/uthread/uthread_sigwait.c b/lib/libc_r/uthread/uthread_sigwait.c index 8432e879646..3593b72853f 100644 --- a/lib/libc_r/uthread/uthread_sigwait.c +++ b/lib/libc_r/uthread/uthread_sigwait.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_sigwait.c,v 1.3 1999/01/06 05:29:28 d Exp $ + * $OpenBSD: uthread_sigwait.c,v 1.4 1999/01/17 23:57:27 d Exp $ */ #include <signal.h> #include <errno.h> @@ -45,6 +45,7 @@ sigwait(const sigset_t * set, int *sig) sigset_t tempset; struct sigaction act; + _thread_enter_cancellation_point(); /* * Specify the thread kernel signal handler. */ @@ -75,6 +76,7 @@ sigwait(const sigset_t * set, int *sig) /* Return the signal number to the caller: */ *sig = i; + _thread_leave_cancellation_point(); return (0); } @@ -127,6 +129,8 @@ sigwait(const sigset_t * set, int *sig) } } + _thread_leave_cancellation_point(); + /* Return the completion status: */ return (ret); } diff --git a/lib/libc_r/uthread/uthread_wait4.c b/lib/libc_r/uthread/uthread_wait4.c index 5017fe5c1ac..a4f44e1d405 100644 --- a/lib/libc_r/uthread/uthread_wait4.c +++ b/lib/libc_r/uthread/uthread_wait4.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_wait4.c,v 1.2 1999/01/06 05:29:29 d Exp $ + * $OpenBSD: uthread_wait4.c,v 1.3 1999/01/17 23:57:28 d Exp $ */ #include <errno.h> #include <sys/wait.h> @@ -42,6 +42,7 @@ wait4(pid_t pid, int *istat, int options, struct rusage * rusage) { pid_t ret; + _thread_enter_cancellation_point(); /* Perform a non-blocking wait4 syscall: */ while ((ret = _thread_sys_wait4(pid, istat, options | WNOHANG, rusage)) == 0 && (options & WNOHANG) == 0) { /* Reset the interrupted operation flag: */ @@ -57,6 +58,7 @@ wait4(pid_t pid, int *istat, int options, struct rusage * rusage) break; } } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libc_r/uthread/uthread_write.c b/lib/libc_r/uthread/uthread_write.c index ba8585ec8b2..b7c974ee289 100644 --- a/lib/libc_r/uthread/uthread_write.c +++ b/lib/libc_r/uthread/uthread_write.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: uthread_write.c,v 1.10 1998/09/07 21:55:01 alex Exp $ - * $OpenBSD: uthread_write.c,v 1.2 1998/12/23 22:49:47 d Exp $ + * $OpenBSD: uthread_write.c,v 1.3 1999/01/17 23:57:28 d Exp $ * */ #include <sys/types.h> @@ -51,9 +51,13 @@ write(int fd, const void *buf, size_t nbytes) ssize_t num = 0; ssize_t ret; + _thread_enter_cancellation_point(); + /* POSIX says to do just this: */ - if (nbytes == 0) + if (nbytes == 0) { + _thread_leave_cancellation_point(); return (0); + } /* Lock the file descriptor for write: */ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { @@ -65,6 +69,7 @@ write(int fd, const void *buf, size_t nbytes) /* File is not open for write: */ errno = EBADF; _FD_UNLOCK(fd, FD_WRITE); + _thread_leave_cancellation_point(); return (-1); } @@ -130,6 +135,7 @@ write(int fd, const void *buf, size_t nbytes) } _FD_UNLOCK(fd, FD_RDWR); } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libpthread/man/pthread_cancel.3 b/lib/libpthread/man/pthread_cancel.3 new file mode 100644 index 00000000000..8522098a34e --- /dev/null +++ b/lib/libpthread/man/pthread_cancel.3 @@ -0,0 +1,65 @@ +.Dd January 17, 1999 +.Dt PTHREAD_CANCEL 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cancel +.Nd cancel execution of a thread +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_cancel "pthread_t thread" +.Sh DESCRIPTION +The +.Fn pthread_cancel +function requests that +.Fa thread +be canceled. The target thread's cancelability state and type determines +when the cancellation takes effect. When the cancellation is acted on, +the cancellation cleanup handlers for +.Fa thread +are called. When the last cancellation cleanup handler returns, +the thread-specific data destructor functions will be called for +.Fa thread . +When the last destructor function returns, +.Fa thread +will be terminated. +.Pp +The cancellation processing in the target thread runs asynchronously with +respect to the calling thread returning from +.Fn pthread_cancel . +.Pp +A status of +.Dv PTHREAD_CANCELED +is made available to any threads joining with the target. The symbolic +constant +.Dv PTHREAD_CANCELED +expands to a constant expression of type +.Ft "(void *)" , +whose value matches no pointer to an object in memory nor the value +.Dv NULL . +.Sh RETURN VALUES +If successful, the +.Fn pthread_cancel +functions will return zero. Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_cancel +will fail if: +.Bl -tag -width Er +.It Bq Er ESRCH +No thread could be found corresponding to that specified by the given +thread ID. +.El +.Sh SEE ALSO +.Xr pthread_testcancel 3 , +.Xr pthread_setcancelstate 3 , +.Xr pthread_setcanceltype 3 , +.Xr pthread_cleanup_pop 3 , +.Xr pthread_cleanup_push 3 , +.Xr pthread_exit 3 , +.Xr pthread_join 3 +.Sh STANDARDS +.Fn pthread_cancel +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_testcancel.3 b/lib/libpthread/man/pthread_testcancel.3 new file mode 100644 index 00000000000..1cd02e8fe83 --- /dev/null +++ b/lib/libpthread/man/pthread_testcancel.3 @@ -0,0 +1,182 @@ +.Dd January 17, 1999 +.Dt PTHREAD_TESTCANCEL 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_setcancelstate , +.Nm pthread_setcanceltype , +.Nm pthread_testcancel +.Nd set cancelability state +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_setcancelstate "int state" "int *oldstate" +.Ft int +.Fn pthread_setcanceltype "int type" "int *oldtype" +.Ft void +.Fn pthread_testcancel "void" +.Sh DESCRIPTION +The +.Fn pthread_setcancelstate +function atomically both sets the calling thread's cancelability state +to the indicated +.Fa state +and returns the previous cancelability state at the location referenced by +.Fa oldstate . +Legal values for +.Fa state +are +.Dv PTHREAD_CANCEL_ENABLE +and +.Dv PTHREAD_CANCEL_DISABLE . +.Pp +The +.Fn pthread_setcanceltype +function atomically both sets the calling thread's cancelability type +to the indicated +.Fa type +and returns the previous cancelability type at the location referenced by +.Fa oldtype . +Legal values for +.Fa type +are +.Dv PTHREAD_CANCEL_DEFERRED +and +.Dv PTHREAD_CANCEL_ASYNCHRONOUS . +.Pp +The cancelability state and type of any newly created threads, including the +thread in which +.Fn main +was first invoked, are +.Dv PTHREAD_CANCEL_ENABLE +and +.Dv PTHREAD_CANCEL_DEFERRED +respectively. +.Pp +The +.Fn pthread_testcancel +function creates a cancellation point in the calling thread. The +.Fn pthread_testcancel +function has no effect if cancelability is disabled. +.Pp +.Ss Cancelability States +The cancelability state of a thread determines the action taken upon +receipt of a cancellation request. The thread may control cancellation in +a number of ways. +.Pp +Each thread maintains its own +.Dq cancelability state +which may be encoded in two bits: +.Bl -hang +.It Em Cancelability Enable +When cancelability is +.Dv PTHREAD_CANCEL_DISABLE , +cancellation requests against the target thread are held pending. +.It Em Cancelability Type +When cancelability is enabled and the cancelability type is +.Dv PTHREAD_CANCEL_ASYNCHRONOUS , +new or pending cancellation requests may be acted upon at any time. +When cancelability is enabled and the cancelability type is +.Dv PTHREAD_CANCEL_DEFERRED , +cancellation requests are held pending until a cancellation point (see +below) is reached. If cancelability is disabled, the setting of the +cancelability type has no immediate effect as all cancellation requests +are held pending, however, once cancelability is enabled again the new +type will be in effect. +.El +.Ss Cancellation Points +Cancellation points will occur when a thread is executing the following +functions: +.Fn close , +.Fn creat , +.Fn fcntl , +.Fn fsync , +.Fn msync , +.Fn nanosleep , +.Fn open , +.Fn pause , +.Fn pthread_cond_timedwait , +.Fn pthread_cond_wait , +.Fn pthread_join , +.Fn pthread_testcancel , +.Fn read , +.Fn sigwaitinfo , +.Fn sigsuspend , +.Fn sigwait , +.Fn sleep , +.Fn system , +.Fn tcdrain , +.Fn wait , +.Fn waitpid , +.Fn write . +.Sh RETURN VALUES +If successful, the +.Fn pthread_setcancelstate +and +.Fn pthread_setcanceltype +functions will return zero. Otherwise, an error number shall be returned to +indicate the error. +.Pp +The +.Fn pthread_setcancelstate +and +.Fn pthread_setcanceltype +functions are used to control the points at which a thread may be +asynchronously canceled. For cancellation control to be usable in modular +fashion, some rules must be followed. +.Pp +For purposes of this discussion, consider an object to be a generalization +of a procedure. It is a set of procedures and global variables written as +a unit and called by clients not known by the object. Objects may depend +on other objects. +.Pp +First, cancelability should only be disabled on entry to an object, never +explicitly enabled. On exit from an object, the cancelability state should +always be restored to its value on entry to the object. +.Pp +This follows from a modularity argument: if the client of an object (or the +client of an object that uses that object) has disabled cancelability, it is +because the client doesn't want to have to worry about how to clean up if the +thread is canceled while executing some sequence of actions. If an object +is called in such a state and it enables cancelability and a cancellation +request is pending for that thread, then the thread will be canceled, +contrary to the wish of the client that disabled. +.Pp +Second, the cancelability type may be explicitly set to either +.Em deferred +or +.Em asynchronous +upon entry to an object. But as with the cancelability state, on exit from +an object that cancelability type should always be restored to its value on +entry to the object. +.Pp +Finally, only functions that are cancel-safe may be called from a thread that +is asynchronously cancelable. +.Sh ERRORS +The function +.Fn pthread_setcancelstate +may fail with: +.Bl -tag -width Er +.It Bq Er EINVAL +The specified state is not +.Dv PTHREAD_CANCEL_ENABLE +or +.Dv PTHREAD_CANCEL_DISABLE . +.El +.Pp +The function +.Fn pthread_setcanceltype +may fail with: +.Bl -tag -width Er +.It Bq Er EINVAL +The specified state is not +.Dv PTHREAD_CANCEL_DEFERRED +or +.Dv PTHREAD_CANCEL_ASYNCHRONOUS . +.El +.Sh SEE ALSO +.Xr pthread_cancel 3 +.Sh STANDARDS +.Fn pthread_testcancel +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/uthread/uthread_cancel.c b/lib/libpthread/uthread/uthread_cancel.c new file mode 100644 index 00000000000..f3a205d1e9e --- /dev/null +++ b/lib/libpthread/uthread/uthread_cancel.c @@ -0,0 +1,164 @@ +/* + * David Leonard <d@openbsd.org>, 1999. Public domain. + */ +#include <sys/errno.h> +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_cancel(pthread) + pthread_t pthread; +{ + int ret; + + if ((ret = _find_thread(pthread))) { + } else if (pthread->state == PS_DEAD) + ret = 0; + else { + /* Set the threads's I've-been-cancelled flag: */ + pthread->flags |= PTHREAD_CANCELLING; + /* 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_AT_CANCEL_POINT))) + switch (pthread->state) { + case PS_RUNNING: + /* No need to resume: */ + break; + case PS_WAIT_WAIT: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_SLEEP_WAIT: + case PS_SELECT_WAIT: + case PS_SIGSUSPEND: + /* Interrupt and resume: */ + pthread->interrupted = 1; + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + break; + case PS_MUTEX_WAIT: + case PS_COND_WAIT: + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + case PS_SIGWAIT: + case PS_JOIN: + case PS_SUSPENDED: + case PS_SIGTHREAD: + /* Simply wake: */ + /* XXX may be incorrect */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + break; + case PS_DEAD: + case PS_STATE_MAX: + /* Ignore */ + break; + } + ret = 0; + } + return (ret); +} + +int +pthread_setcancelstate(state, oldstate) + int state; + int *oldstate; +{ + int ostate; + int ret; + + ostate = _thread_run->cancelstate; + + switch (state) { + case PTHREAD_CANCEL_ENABLE: + if (oldstate) + *oldstate = ostate; + _thread_run->cancelstate = PTHREAD_CANCEL_ENABLE; + if (_thread_run->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + _thread_cancellation_point(); + ret = 0; + break; + case PTHREAD_CANCEL_DISABLE: + if (oldstate) + *oldstate = ostate; + _thread_run->cancelstate = PTHREAD_CANCEL_DISABLE; + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + + +int +pthread_setcanceltype(type, oldtype) + int type; + int *oldtype; +{ + int otype; + int ret; + + otype = _thread_run->canceltype; + switch (type) { + case PTHREAD_CANCEL_ASYNCHRONOUS: + if (oldtype) + *oldtype = otype; + _thread_run->canceltype = PTHREAD_CANCEL_ASYNCHRONOUS; + _thread_cancellation_point(); + ret = 0; + break; + case PTHREAD_CANCEL_DEFERRED: + if (oldtype) + *oldtype = otype; + _thread_run->canceltype = PTHREAD_CANCEL_DEFERRED; + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + +void +pthread_testcancel() +{ + + _thread_cancellation_point(); +} + +void +_thread_enter_cancellation_point() +{ + + /* Look for a cancellation before we block: */ + _thread_cancellation_point(); + _thread_run->flags |= PTHREAD_AT_CANCEL_POINT; +} + +void +_thread_leave_cancellation_point() +{ + + _thread_run->flags &=~ PTHREAD_AT_CANCEL_POINT; + /* Look for a cancellation after we unblock: */ + _thread_cancellation_point(); +} + +/* + * Must only be called when in asynchronous cancel mode, or + * from pthread_testcancel(). + */ +void +_thread_cancellation_point() +{ + + if ((_thread_run->cancelstate == PTHREAD_CANCEL_ENABLE) && + ((_thread_run->flags & (PTHREAD_CANCELLING|PTHREAD_EXITING)) == + PTHREAD_CANCELLING)) { + _thread_run->flags &=~ PTHREAD_CANCELLING; + pthread_exit(PTHREAD_CANCELED); + PANIC("cancel"); + } +} diff --git a/lib/libpthread/uthread/uthread_close.c b/lib/libpthread/uthread/uthread_close.c index 7d95fbb3196..bc94d162b2a 100644 --- a/lib/libpthread/uthread/uthread_close.c +++ b/lib/libpthread/uthread/uthread_close.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_close.c,v 1.3 1999/01/06 05:29:22 d Exp $ + * $OpenBSD: uthread_close.c,v 1.4 1999/01/17 23:57:27 d Exp $ */ #include <stdlib.h> #include <unistd.h> @@ -46,6 +46,7 @@ close(int fd) int ret; struct stat sb; + _thread_enter_cancellation_point(); /* Lock the file descriptor while the file is closed: */ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { /* Get file descriptor status. */ @@ -84,6 +85,7 @@ close(int fd) free(_thread_fd_table[fd]); _thread_fd_table[fd] = NULL; } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libpthread/uthread/uthread_cond.c b/lib/libpthread/uthread/uthread_cond.c index b2ef3df1ac5..525f86049b0 100644 --- a/lib/libpthread/uthread/uthread_cond.c +++ b/lib/libpthread/uthread/uthread_cond.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_cond.c,v 1.4 1999/01/06 05:29:22 d Exp $ + * $OpenBSD: uthread_cond.c,v 1.5 1999/01/17 23:57:27 d Exp $ */ #include <stdlib.h> #include <errno.h> @@ -137,6 +137,8 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) */ else if (*cond != NULL || (rval = pthread_cond_init(cond,NULL)) == 0) { + _thread_enter_cancellation_point(); + /* Lock the condition variable structure: */ _SPINLOCK(&(*cond)->lock); @@ -185,6 +187,7 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) break; } + _thread_leave_cancellation_point(); } /* Return the completion status: */ @@ -206,6 +209,7 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, */ else if (*cond != NULL || (rval = pthread_cond_init(cond,NULL)) == 0) { + _thread_enter_cancellation_point(); /* Lock the condition variable structure: */ _SPINLOCK(&(*cond)->lock); @@ -263,7 +267,7 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, rval = EINVAL; break; } - + _thread_leave_cancellation_point(); } /* Return the completion status: */ diff --git a/lib/libpthread/uthread/uthread_create.c b/lib/libpthread/uthread/uthread_create.c index 178c35424b8..1ed287d2b1b 100644 --- a/lib/libpthread/uthread/uthread_create.c +++ b/lib/libpthread/uthread/uthread_create.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_create.c,v 1.5 1999/01/06 05:29:22 d Exp $ + * $OpenBSD: uthread_create.c,v 1.6 1999/01/17 23:57:27 d Exp $ */ #include <errno.h> #include <stdlib.h> @@ -93,6 +93,9 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr, timerclear(&new_thread->ru_stime); _SPINUNLOCK(&new_thread->lock); + new_thread->cancelstate = PTHREAD_CANCEL_ENABLE; + new_thread->canceltype = PTHREAD_CANCEL_DEFERRED; + /* * Write a magic value to the thread structure * to help identify valid ones: @@ -109,7 +112,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr, new_thread->sigmask = _thread_run->sigmask; /* Initialise the jump buffer: */ - setjmp(new_thread->saved_jmp_buf); + _thread_machdep_setjmp(new_thread->saved_jmp_buf); /* * Set up new stack frame so that it looks like it diff --git a/lib/libpthread/uthread/uthread_fcntl.c b/lib/libpthread/uthread/uthread_fcntl.c index e7e11a2e218..1a0a3e9548a 100644 --- a/lib/libpthread/uthread/uthread_fcntl.c +++ b/lib/libpthread/uthread/uthread_fcntl.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_fcntl.c,v 1.3 1999/01/06 05:29:23 d Exp $ + * $OpenBSD: uthread_fcntl.c,v 1.4 1999/01/17 23:57:27 d Exp $ */ #include <stdarg.h> #include <unistd.h> @@ -47,6 +47,8 @@ fcntl(int fd, int cmd,...) int ret; va_list ap; + _thread_enter_cancellation_point(); + /* Lock the file descriptor: */ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { /* Initialise the variable argument list: */ @@ -135,6 +137,7 @@ fcntl(int fd, int cmd,...) /* Unlock the file descriptor: */ _FD_UNLOCK(fd, FD_RDWR); } + _thread_leave_cancellation_point(); /* Return the completion status: */ return (ret); diff --git a/lib/libpthread/uthread/uthread_fsync.c b/lib/libpthread/uthread/uthread_fsync.c index 4c953443e95..9db34f5564c 100644 --- a/lib/libpthread/uthread/uthread_fsync.c +++ b/lib/libpthread/uthread/uthread_fsync.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_fsync.c,v 1.2 1999/01/06 05:29:24 d Exp $ + * $OpenBSD: uthread_fsync.c,v 1.3 1999/01/17 23:57:27 d Exp $ */ #include <unistd.h> #ifdef _THREAD_SAFE @@ -41,10 +41,12 @@ fsync(int fd) { int ret; + _thread_enter_cancellation_point(); if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { ret = _thread_sys_fsync(fd); _FD_UNLOCK(fd, FD_RDWR); } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libpthread/uthread/uthread_init.c b/lib/libpthread/uthread/uthread_init.c index ad56b9a670c..0cd5bd376c4 100644 --- a/lib/libpthread/uthread/uthread_init.c +++ b/lib/libpthread/uthread/uthread_init.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_init.c,v 1.7 1999/01/10 23:11:33 d Exp $ + * $OpenBSD: uthread_init.c,v 1.8 1999/01/17 23:57:27 d Exp $ */ #include <errno.h> @@ -224,6 +224,8 @@ _thread_init(void) _thread_initial->nxt = NULL; _thread_initial->flags = 0; _thread_initial->error = 0; + _thread_initial->cancelstate = PTHREAD_CANCEL_ENABLE; + _thread_initial->canceltype = PTHREAD_CANCEL_DEFERRED; _thread_initial->magic = PTHREAD_MAGIC; pthread_set_name_np(_thread_initial, "init"); _SPINUNLOCK(&_thread_initial->lock); diff --git a/lib/libpthread/uthread/uthread_join.c b/lib/libpthread/uthread/uthread_join.c index 9602ec52a25..52baee31c33 100644 --- a/lib/libpthread/uthread/uthread_join.c +++ b/lib/libpthread/uthread/uthread_join.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_join.c,v 1.2 1999/01/06 05:29:24 d Exp $ + * $OpenBSD: uthread_join.c,v 1.3 1999/01/17 23:57:27 d Exp $ */ #include <errno.h> #ifdef _THREAD_SAFE @@ -42,15 +42,21 @@ pthread_join(pthread_t pthread, void **thread_return) int ret = 0; pthread_t pthread1 = NULL; + _thread_enter_cancellation_point(); + /* Check if the caller has specified an invalid thread: */ - if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) { /* Invalid thread: */ + _thread_leave_cancellation_point(); return(EINVAL); + } /* Check if the caller has specified itself: */ - if (pthread == _thread_run) + if (pthread == _thread_run) { /* Avoid a deadlock condition: */ + _thread_leave_cancellation_point(); return(EDEADLK); + } /* * Find the thread in the list of active threads or in the @@ -93,6 +99,8 @@ pthread_join(pthread_t pthread, void **thread_return) /* Return the thread's return value: */ *thread_return = pthread->ret; + _thread_leave_cancellation_point(); + /* Return the completion status: */ return (ret); } diff --git a/lib/libpthread/uthread/uthread_nanosleep.c b/lib/libpthread/uthread/uthread_nanosleep.c index 450b505bf12..0f5c4c9c2ab 100644 --- a/lib/libpthread/uthread/uthread_nanosleep.c +++ b/lib/libpthread/uthread/uthread_nanosleep.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_nanosleep.c,v 1.2 1999/01/06 05:29:25 d Exp $ + * $OpenBSD: uthread_nanosleep.c,v 1.3 1999/01/17 23:57:27 d Exp $ */ #include <stdio.h> #include <errno.h> @@ -48,6 +48,7 @@ nanosleep(const struct timespec * time_to_sleep, struct timespec remaining_time; struct timeval tv; + _thread_enter_cancellation_point(); /* Check if the time to sleep is legal: */ if (time_to_sleep == NULL || time_to_sleep->tv_nsec < 0 || time_to_sleep->tv_nsec > 1000000000 || time_to_sleep->tv_sec < 0) { /* Return an EINVAL error : */ @@ -95,6 +96,7 @@ nanosleep(const struct timespec * time_to_sleep, ret = -1; } } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libpthread/uthread/uthread_open.c b/lib/libpthread/uthread/uthread_open.c index 52d0a6b06cf..9c03daa4f47 100644 --- a/lib/libpthread/uthread/uthread_open.c +++ b/lib/libpthread/uthread/uthread_open.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: uthread_open.c,v 1.4 1998/04/29 09:59:07 jb Exp $ - * $OpenBSD: uthread_open.c,v 1.2 1998/12/23 22:49:46 d Exp $ + * $OpenBSD: uthread_open.c,v 1.3 1999/01/17 23:57:27 d Exp $ * */ #include <stdarg.h> @@ -49,6 +49,8 @@ open(const char *path, int flags,...) int mode = 0; va_list ap; + _thread_enter_cancellation_point(); + /* Check if the file is being created: */ if (flags & O_CREAT) { /* Get the creation mode: */ @@ -68,6 +70,8 @@ open(const char *path, int flags,...) fd = -1; } + _thread_leave_cancellation_point(); + /* Return the file descriptor or -1 on error: */ return (fd); } diff --git a/lib/libpthread/uthread/uthread_read.c b/lib/libpthread/uthread/uthread_read.c index 37b0c9067bb..22d1d03f091 100644 --- a/lib/libpthread/uthread/uthread_read.c +++ b/lib/libpthread/uthread/uthread_read.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: uthread_read.c,v 1.6 1998/06/10 22:28:43 jb Exp $ - * $OpenBSD: uthread_read.c,v 1.2 1998/12/23 22:49:46 d Exp $ + * $OpenBSD: uthread_read.c,v 1.3 1999/01/17 23:57:27 d Exp $ * */ #include <sys/types.h> @@ -48,9 +48,13 @@ read(int fd, void *buf, size_t nbytes) int ret; int type; + _thread_enter_cancellation_point(); + /* POSIX says to do just this: */ - if (nbytes == 0) + if (nbytes == 0) { + _thread_leave_cancellation_point(); return (0); + } /* Lock the file descriptor for read: */ if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { @@ -62,6 +66,7 @@ read(int fd, void *buf, size_t nbytes) /* File is not open for read: */ errno = EBADF; _FD_UNLOCK(fd, FD_READ); + _thread_leave_cancellation_point(); return (-1); } @@ -93,6 +98,7 @@ read(int fd, void *buf, size_t nbytes) } _FD_UNLOCK(fd, FD_READ); } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libpthread/uthread/uthread_sigwait.c b/lib/libpthread/uthread/uthread_sigwait.c index 8432e879646..3593b72853f 100644 --- a/lib/libpthread/uthread/uthread_sigwait.c +++ b/lib/libpthread/uthread/uthread_sigwait.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_sigwait.c,v 1.3 1999/01/06 05:29:28 d Exp $ + * $OpenBSD: uthread_sigwait.c,v 1.4 1999/01/17 23:57:27 d Exp $ */ #include <signal.h> #include <errno.h> @@ -45,6 +45,7 @@ sigwait(const sigset_t * set, int *sig) sigset_t tempset; struct sigaction act; + _thread_enter_cancellation_point(); /* * Specify the thread kernel signal handler. */ @@ -75,6 +76,7 @@ sigwait(const sigset_t * set, int *sig) /* Return the signal number to the caller: */ *sig = i; + _thread_leave_cancellation_point(); return (0); } @@ -127,6 +129,8 @@ sigwait(const sigset_t * set, int *sig) } } + _thread_leave_cancellation_point(); + /* Return the completion status: */ return (ret); } diff --git a/lib/libpthread/uthread/uthread_wait4.c b/lib/libpthread/uthread/uthread_wait4.c index 5017fe5c1ac..a4f44e1d405 100644 --- a/lib/libpthread/uthread/uthread_wait4.c +++ b/lib/libpthread/uthread/uthread_wait4.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_wait4.c,v 1.2 1999/01/06 05:29:29 d Exp $ + * $OpenBSD: uthread_wait4.c,v 1.3 1999/01/17 23:57:28 d Exp $ */ #include <errno.h> #include <sys/wait.h> @@ -42,6 +42,7 @@ wait4(pid_t pid, int *istat, int options, struct rusage * rusage) { pid_t ret; + _thread_enter_cancellation_point(); /* Perform a non-blocking wait4 syscall: */ while ((ret = _thread_sys_wait4(pid, istat, options | WNOHANG, rusage)) == 0 && (options & WNOHANG) == 0) { /* Reset the interrupted operation flag: */ @@ -57,6 +58,7 @@ wait4(pid_t pid, int *istat, int options, struct rusage * rusage) break; } } + _thread_leave_cancellation_point(); return (ret); } #endif diff --git a/lib/libpthread/uthread/uthread_write.c b/lib/libpthread/uthread/uthread_write.c index ba8585ec8b2..b7c974ee289 100644 --- a/lib/libpthread/uthread/uthread_write.c +++ b/lib/libpthread/uthread/uthread_write.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: uthread_write.c,v 1.10 1998/09/07 21:55:01 alex Exp $ - * $OpenBSD: uthread_write.c,v 1.2 1998/12/23 22:49:47 d Exp $ + * $OpenBSD: uthread_write.c,v 1.3 1999/01/17 23:57:28 d Exp $ * */ #include <sys/types.h> @@ -51,9 +51,13 @@ write(int fd, const void *buf, size_t nbytes) ssize_t num = 0; ssize_t ret; + _thread_enter_cancellation_point(); + /* POSIX says to do just this: */ - if (nbytes == 0) + if (nbytes == 0) { + _thread_leave_cancellation_point(); return (0); + } /* Lock the file descriptor for write: */ if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { @@ -65,6 +69,7 @@ write(int fd, const void *buf, size_t nbytes) /* File is not open for write: */ errno = EBADF; _FD_UNLOCK(fd, FD_WRITE); + _thread_leave_cancellation_point(); return (-1); } @@ -130,6 +135,7 @@ write(int fd, const void *buf, size_t nbytes) } _FD_UNLOCK(fd, FD_RDWR); } + _thread_leave_cancellation_point(); return (ret); } #endif |