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 /lib/libc_r/TEST | |
parent | 209640f64878cc32de9cf45178c9a0e979525bdd (diff) |
pthread_cancel() and cancellation points
Diffstat (limited to 'lib/libc_r/TEST')
-rw-r--r-- | lib/libc_r/TEST/test_cancel.c | 174 |
1 files changed, 174 insertions, 0 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); +} |