1 /* $OpenBSD: cancel.c,v 1.1.1.1 2001/08/15 14:37:10 fgsch Exp $ */ 2 /* David Leonard <d@openbsd.org>, 1999. Public Domain. */ 3 4 #include <pthread.h> 5 #include <pthread_np.h> 6 #include <unistd.h> 7 #include <stdio.h> 8 #include <fcntl.h> 9 #include "test.h" 10 11 static pthread_cond_t cond; 12 static pthread_mutex_t mutex; 13 static struct timespec expiretime; 14 15 static int pv_state = 0; 16 void p() { 17 CHECKr(pthread_mutex_lock(&mutex)); 18 if (pv_state <= 0) { 19 CHECKr(pthread_cond_timedwait(&cond, &mutex, &expiretime)); 20 } 21 pv_state--; 22 CHECKr(pthread_mutex_unlock(&mutex)); 23 } 24 25 void v() { 26 int needsignal; 27 28 CHECKr(pthread_mutex_lock(&mutex)); 29 pv_state++; 30 needsignal = (pv_state == 1); 31 if (needsignal) 32 CHECKr(pthread_cond_signal(&cond)); 33 CHECKr(pthread_mutex_unlock(&mutex)); 34 } 35 36 void 37 c1handler(void *fd) 38 { 39 CHECKe(close((int)fd)); 40 v(); 41 } 42 43 void * 44 child1fn(arg) 45 void *arg; 46 { 47 int fd; 48 char buf[1024]; 49 int len; 50 51 SET_NAME("c1"); 52 CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); 53 /* something that will block */ 54 CHECKe(fd = open("/dev/tty", O_RDONLY)); 55 pthread_cleanup_push(c1handler, (void *)fd); 56 v(); 57 while (1) { 58 CHECKe(len = read(fd, &buf, sizeof buf)); 59 printf("child 1 read %d bytes\n", len); 60 } 61 PANIC("child 1"); 62 } 63 64 static int c2_in_test = 0; 65 66 void 67 c2handler(void *arg) 68 { 69 ASSERT(c2_in_test); 70 v(); 71 } 72 73 static int message_seen = 0; 74 void * 75 child2fn(arg) 76 void *arg; 77 { 78 SET_NAME("c2"); 79 80 CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)); 81 pthread_cleanup_push(c2handler, NULL); 82 v(); 83 84 while (1) { 85 struct timespec now; 86 struct timespec end; 87 88 /* 89 * XXX Be careful not to call any cancellation points 90 * until pthread_testcancel() 91 */ 92 93 CHECKe(clock_gettime(CLOCK_REALTIME, &end)); 94 end.tv_sec ++; 95 96 while (1) { 97 CHECKe(clock_gettime(CLOCK_REALTIME, &now)); 98 if (timespeccmp(&now, &end, >=)) 99 break; 100 pthread_yield(); 101 } 102 103 /* XXX write() contains a cancellation point */ 104 /* printf("child 2 testing for cancel\n"); */ 105 106 c2_in_test = 1; 107 pthread_testcancel(); 108 printf("you should see this message exactly once\n"); 109 message_seen++; 110 c2_in_test = 0; 111 ASSERT(message_seen == 1); 112 } 113 PANIC("child 2"); 114 } 115 116 static int c3_cancel_survived; 117 118 void 119 c3handler(void *arg) 120 { 121 printf("(fyi, cancellation of self %s instantaneous)\n", 122 (c3_cancel_survived ? "was not" : "was")); 123 v(); 124 } 125 126 void * 127 child3fn(arg) 128 void *arg; 129 { 130 SET_NAME("c3"); 131 pthread_cleanup_push(c3handler, NULL); 132 133 /* Cancel myself */ 134 CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); 135 c3_cancel_survived = 0; 136 pthread_cancel(pthread_self()); 137 c3_cancel_survived = 1; 138 pthread_testcancel(); 139 140 PANIC("child 3"); 141 } 142 143 int 144 main() 145 { 146 pthread_t child1, child2, child3; 147 148 /* Set up our control flow */ 149 CHECKr(pthread_mutex_init(&mutex, NULL)); 150 CHECKr(pthread_cond_init(&cond, NULL)); 151 CHECKe(clock_gettime(CLOCK_REALTIME, &expiretime)); 152 expiretime.tv_sec += 5; /* this test shouldn't run over 5 seconds */ 153 154 CHECKr(pthread_create(&child1, NULL, child1fn, NULL)); 155 CHECKr(pthread_create(&child2, NULL, child2fn, NULL)); 156 p(); 157 p(); 158 159 CHECKr(pthread_cancel(child1)); 160 p(); 161 162 /* Give thread 2 a chance to go through its deferred loop once */ 163 sleep(2); 164 CHECKr(pthread_cancel(child2)); 165 p(); 166 167 /* Child 3 cancels itself */ 168 CHECKr(pthread_create(&child3, NULL, child3fn, NULL)); 169 p(); 170 171 /* Make sure they're all gone */ 172 CHECKr(pthread_join(child3, NULL)); 173 CHECKr(pthread_join(child2, NULL)); 174 CHECKr(pthread_join(child1, NULL)); 175 176 exit(0); 177 } 178