1 /* $OpenBSD: cancel.c,v 1.7 2013/10/06 21:46:10 guenther 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 <stdlib.h> 10 #include "test.h" 11 12 static pthread_cond_t cond; 13 static pthread_mutex_t mutex; 14 static struct timespec expiretime; 15 16 static volatile int pv_state = 0; 17 18 static void 19 p(void) 20 { 21 CHECKr(pthread_mutex_lock(&mutex)); 22 if (pv_state <= 0) { 23 CHECKr(pthread_cond_timedwait(&cond, &mutex, &expiretime)); 24 } 25 pv_state--; 26 CHECKr(pthread_mutex_unlock(&mutex)); 27 } 28 29 static void 30 v(void) 31 { 32 int needsignal; 33 34 CHECKr(pthread_mutex_lock(&mutex)); 35 pv_state++; 36 needsignal = (pv_state == 1); 37 if (needsignal) 38 CHECKr(pthread_cond_signal(&cond)); 39 CHECKr(pthread_mutex_unlock(&mutex)); 40 } 41 42 static void 43 c1handler(void *arg) 44 { 45 CHECKe(close(*(int *)arg)); 46 v(); 47 } 48 49 static void * 50 child1fn(void *arg) 51 { 52 int fd; 53 char buf[1024]; 54 int len; 55 56 SET_NAME("c1"); 57 CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); 58 /* something that will block */ 59 CHECKe(fd = open("/dev/tty", O_RDONLY)); 60 pthread_cleanup_push(c1handler, (void *)&fd); 61 v(); 62 while (1) { 63 CHECKe(len = read(fd, &buf, sizeof buf)); 64 printf("child 1 read %d bytes\n", len); 65 } 66 pthread_cleanup_pop(0); 67 PANIC("child 1"); 68 } 69 70 static int c2_in_test = 0; 71 72 static void 73 c2handler(void *arg) 74 { 75 ASSERT(c2_in_test); 76 v(); 77 } 78 79 static int message_seen = 0; 80 static void * 81 child2fn(void *arg) 82 { 83 SET_NAME("c2"); 84 85 CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)); 86 pthread_cleanup_push(c2handler, NULL); 87 v(); 88 89 while (1) { 90 struct timespec now; 91 struct timespec end; 92 93 /* 94 * XXX Be careful not to call any cancellation points 95 * until pthread_testcancel() 96 */ 97 98 CHECKe(clock_gettime(CLOCK_REALTIME, &end)); 99 end.tv_sec ++; 100 101 while (1) { 102 CHECKe(clock_gettime(CLOCK_REALTIME, &now)); 103 if (timespeccmp(&now, &end, >=)) 104 break; 105 pthread_yield(); 106 } 107 108 /* XXX write() contains a cancellation point */ 109 /* printf("child 2 testing for cancel\n"); */ 110 111 c2_in_test = 1; 112 pthread_testcancel(); 113 printf("you should see this message exactly once\n"); 114 message_seen++; 115 c2_in_test = 0; 116 ASSERT(message_seen == 1); 117 v(); 118 } 119 pthread_cleanup_pop(0); 120 PANIC("child 2"); 121 } 122 123 static int c3_cancel_survived; 124 125 static void 126 c3handler(void *arg) 127 { 128 printf("(fyi, cancellation of self %s instantaneous)\n", 129 (c3_cancel_survived ? "was not" : "was")); 130 v(); 131 } 132 133 static void * 134 child3fn(void *arg) 135 { 136 SET_NAME("c3"); 137 pthread_cleanup_push(c3handler, NULL); 138 139 /* Cancel myself */ 140 CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); 141 c3_cancel_survived = 0; 142 pthread_cancel(pthread_self()); 143 c3_cancel_survived = 1; 144 pthread_testcancel(); 145 pthread_cleanup_pop(0); 146 147 PANIC("child 3"); 148 } 149 150 static int c4_cancel_early; 151 152 static void 153 c4handler(void *arg) 154 { 155 printf("early = %d\n", c4_cancel_early); 156 ASSERT(c4_cancel_early == 0); 157 v(); 158 } 159 160 static void * 161 child4fn(void *arg) 162 { 163 SET_NAME("c4"); 164 pthread_cleanup_push(c4handler, NULL); 165 166 /* Cancel myself */ 167 CHECKr(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)); 168 169 c4_cancel_early = 3; 170 pthread_cancel(pthread_self()); 171 172 c4_cancel_early = 2; 173 pthread_testcancel(); 174 175 c4_cancel_early = 1; 176 CHECKr(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); 177 178 c4_cancel_early = 0; 179 pthread_testcancel(); 180 181 pthread_cleanup_pop(0); 182 183 PANIC("child 4"); 184 } 185 186 int 187 main(int argc, char *argv[]) 188 { 189 pthread_t child1, child2, child3, child4; 190 191 /* Set up our control flow */ 192 CHECKr(pthread_mutex_init(&mutex, NULL)); 193 CHECKr(pthread_cond_init(&cond, NULL)); 194 CHECKe(clock_gettime(CLOCK_REALTIME, &expiretime)); 195 expiretime.tv_sec += 5; /* this test shouldn't run over 5 seconds */ 196 197 CHECKr(pthread_create(&child1, NULL, child1fn, NULL)); 198 CHECKr(pthread_create(&child2, NULL, child2fn, NULL)); 199 p(); 200 p(); 201 202 CHECKr(pthread_cancel(child1)); 203 p(); 204 205 /* Give thread 2 a chance to go through its deferred loop once */ 206 p(); 207 CHECKr(pthread_cancel(child2)); 208 p(); 209 210 /* Child 3 cancels itself */ 211 CHECKr(pthread_create(&child3, NULL, child3fn, NULL)); 212 p(); 213 214 /* Child 4 also cancels itself */ 215 CHECKr(pthread_create(&child4, NULL, child4fn, NULL)); 216 p(); 217 218 /* Make sure they're all gone */ 219 CHECKr(pthread_join(child4, NULL)); 220 CHECKr(pthread_join(child3, NULL)); 221 CHECKr(pthread_join(child2, NULL)); 222 CHECKr(pthread_join(child1, NULL)); 223 224 exit(0); 225 } 226