1251881Speter/* $OpenBSD: cancel.c,v 1.9 2016/09/20 17:25:06 otto Exp $ */ 2251881Speter/* David Leonard <d@openbsd.org>, 1999. Public Domain. */ 3251881Speter 4251881Speter#include <pthread.h> 5251881Speter#include <pthread_np.h> 6251881Speter#include <unistd.h> 7251881Speter#include <util.h> 8251881Speter#include <stdio.h> 9251881Speter#include <fcntl.h> 10251881Speter#include <stdlib.h> 11251881Speter#include "test.h" 12251881Speter 13251881Speterstatic pthread_cond_t cond; 14251881Speterstatic pthread_mutex_t mutex; 15251881Speterstatic struct timespec expiretime; 16251881Speter 17251881Speterstatic volatile int pv_state = 0; 18251881Speter 19251881Speterstatic void 20251881Speterp(void) 21251881Speter{ 22251881Speter CHECKr(pthread_mutex_lock(&mutex)); 23251881Speter if (pv_state <= 0) { 24251881Speter CHECKr(pthread_cond_timedwait(&cond, &mutex, &expiretime)); 25251881Speter } 26251881Speter pv_state--; 27251881Speter CHECKr(pthread_mutex_unlock(&mutex)); 28251881Speter} 29251881Speter 30251881Speterstatic void 31251881Speterv(void) 32251881Speter{ 33251881Speter int needsignal; 34251881Speter 35251881Speter CHECKr(pthread_mutex_lock(&mutex)); 36251881Speter pv_state++; 37251881Speter needsignal = (pv_state == 1); 38251881Speter if (needsignal) 39251881Speter CHECKr(pthread_cond_signal(&cond)); 40251881Speter CHECKr(pthread_mutex_unlock(&mutex)); 41251881Speter} 42251881Speter 43251881Speterstatic void 44251881Speterc1handler(void *arg) 45251881Speter{ 46251881Speter CHECKe(close(*(int *)arg)); 47251881Speter v(); 48251881Speter} 49251881Speter 50251881Speterstatic void * 51251881Speterchild1fn(void *arg) 52251881Speter{ 53251881Speter int fd, dummy; 54251881Speter char buf[1024]; 55251881Speter int len; 56251881Speter 57251881Speter SET_NAME("c1"); 58251881Speter CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); 59251881Speter /* something that will block */ 60251881Speter CHECKe(openpty(&dummy, &fd, NULL, NULL, NULL)); 61251881Speter pthread_cleanup_push(c1handler, (void *)&fd); 62251881Speter v(); 63251881Speter while (1) { 64251881Speter CHECKe(len = read(fd, &buf, sizeof buf)); 65251881Speter printf("child 1 read %d bytes\n", len); 66251881Speter } 67251881Speter pthread_cleanup_pop(0); 68251881Speter PANIC("child 1"); 69251881Speter} 70251881Speter 71251881Speterstatic int c2_in_test = 0; 72251881Speter 73251881Speterstatic void 74251881Speterc2handler(void *arg) 75251881Speter{ 76251881Speter ASSERT(c2_in_test); 77251881Speter v(); 78251881Speter} 79251881Speter 80251881Speterstatic int message_seen = 0; 81251881Speterstatic void * 82251881Speterchild2fn(void *arg) 83251881Speter{ 84251881Speter SET_NAME("c2"); 85251881Speter 86251881Speter CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)); 87251881Speter pthread_cleanup_push(c2handler, NULL); 88251881Speter v(); 89251881Speter 90251881Speter while (1) { 91251881Speter struct timespec now; 92251881Speter struct timespec end; 93251881Speter 94251881Speter /* 95251881Speter * XXX Be careful not to call any cancellation points 96251881Speter * until pthread_testcancel() 97251881Speter */ 98251881Speter 99251881Speter CHECKe(clock_gettime(CLOCK_REALTIME, &end)); 100251881Speter end.tv_sec ++; 101251881Speter 102251881Speter while (1) { 103251881Speter CHECKe(clock_gettime(CLOCK_REALTIME, &now)); 104251881Speter if (timespeccmp(&now, &end, >=)) 105251881Speter break; 106251881Speter pthread_yield(); 107251881Speter } 108251881Speter 109251881Speter /* XXX write() contains a cancellation point */ 110251881Speter /* printf("child 2 testing for cancel\n"); */ 111251881Speter 112251881Speter c2_in_test = 1; 113251881Speter pthread_testcancel(); 114251881Speter printf("you should see this message exactly once\n"); 115251881Speter message_seen++; 116251881Speter c2_in_test = 0; 117251881Speter ASSERT(message_seen == 1); 118251881Speter v(); 119251881Speter } 120251881Speter pthread_cleanup_pop(0); 121251881Speter PANIC("child 2"); 122251881Speter} 123251881Speter 124251881Speterstatic int c3_cancel_survived; 125251881Speter 126251881Speterstatic void 127251881Speterc3handler(void *arg) 128251881Speter{ 129251881Speter printf("(fyi, cancellation of self %s instantaneous)\n", 130251881Speter (c3_cancel_survived ? "was not" : "was")); 131251881Speter v(); 132251881Speter} 133251881Speter 134251881Speterstatic void * 135251881Speterchild3fn(void *arg) 136251881Speter{ 137251881Speter SET_NAME("c3"); 138251881Speter pthread_cleanup_push(c3handler, NULL); 139251881Speter 140251881Speter /* Cancel myself */ 141251881Speter CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); 142251881Speter c3_cancel_survived = 0; 143251881Speter pthread_cancel(pthread_self()); 144251881Speter c3_cancel_survived = 1; 145251881Speter pthread_testcancel(); 146251881Speter pthread_cleanup_pop(0); 147251881Speter 148251881Speter PANIC("child 3"); 149251881Speter} 150251881Speter 151251881Speterstatic int c4_cancel_early; 152251881Speter 153251881Speterstatic void 154251881Speterc4handler(void *arg) 155251881Speter{ 156251881Speter printf("early = %d\n", c4_cancel_early); 157251881Speter ASSERT(c4_cancel_early == 0); 158251881Speter v(); 159251881Speter} 160251881Speter 161251881Speterstatic void * 162251881Speterchild4fn(void *arg) 163251881Speter{ 164251881Speter SET_NAME("c4"); 165251881Speter pthread_cleanup_push(c4handler, NULL); 166251881Speter 167251881Speter /* Cancel myself */ 168251881Speter CHECKr(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)); 169251881Speter 170251881Speter c4_cancel_early = 3; 171251881Speter pthread_cancel(pthread_self()); 172251881Speter 173251881Speter c4_cancel_early = 2; 174251881Speter pthread_testcancel(); 175251881Speter 176251881Speter c4_cancel_early = 1; 177251881Speter CHECKr(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); 178251881Speter 179251881Speter c4_cancel_early = 0; 180251881Speter pthread_testcancel(); 181251881Speter 182251881Speter pthread_cleanup_pop(0); 183251881Speter 184251881Speter PANIC("child 4"); 185251881Speter} 186251881Speter 187251881Speterint 188251881Spetermain(int argc, char *argv[]) 189251881Speter{ 190251881Speter pthread_t child1, child2, child3, child4; 191251881Speter 192251881Speter /* Set up our control flow */ 193251881Speter CHECKr(pthread_mutex_init(&mutex, NULL)); 194251881Speter CHECKr(pthread_cond_init(&cond, NULL)); 195251881Speter CHECKe(clock_gettime(CLOCK_REALTIME, &expiretime)); 196251881Speter expiretime.tv_sec += 5; /* this test shouldn't run over 5 seconds */ 197251881Speter 198251881Speter CHECKr(pthread_create(&child1, NULL, child1fn, NULL)); 199251881Speter CHECKr(pthread_create(&child2, NULL, child2fn, NULL)); 200251881Speter p(); 201251881Speter p(); 202251881Speter 203251881Speter CHECKr(pthread_cancel(child1)); 204251881Speter p(); 205251881Speter 206251881Speter /* Give thread 2 a chance to go through its deferred loop once */ 207251881Speter p(); 208251881Speter CHECKr(pthread_cancel(child2)); 209251881Speter p(); 210251881Speter 211251881Speter /* Child 3 cancels itself */ 212251881Speter CHECKr(pthread_create(&child3, NULL, child3fn, NULL)); 213251881Speter p(); 214251881Speter 215251881Speter /* Child 4 also cancels itself */ 216251881Speter CHECKr(pthread_create(&child4, NULL, child4fn, NULL)); 217251881Speter p(); 218251881Speter 219251881Speter /* Make sure they're all gone */ 220251881Speter CHECKr(pthread_join(child4, NULL)); 221251881Speter CHECKr(pthread_join(child3, NULL)); 222251881Speter CHECKr(pthread_join(child2, NULL)); 223251881Speter CHECKr(pthread_join(child1, NULL)); 224251881Speter 225251881Speter exit(0); 226251881Speter} 227251881Speter