1bb535300SJeff Roberson /* 2bb535300SJeff Roberson * David Leonard <d@openbsd.org>, 1999. Public domain. 3bb535300SJeff Roberson * $FreeBSD$ 4bb535300SJeff Roberson */ 5bb535300SJeff Roberson #include <sys/errno.h> 6bb535300SJeff Roberson #include <pthread.h> 77d9d7ca2SMike Makonnen #include <stdlib.h> 8bb535300SJeff Roberson #include "thr_private.h" 9bb535300SJeff Roberson 106da7f493SMike Makonnen /* 116da7f493SMike Makonnen * Static prototypes 126da7f493SMike Makonnen */ 136da7f493SMike Makonnen static void testcancel(void); 146da7f493SMike Makonnen 15bb535300SJeff Roberson __weak_reference(_pthread_cancel, pthread_cancel); 16bb535300SJeff Roberson __weak_reference(_pthread_setcancelstate, pthread_setcancelstate); 17bb535300SJeff Roberson __weak_reference(_pthread_setcanceltype, pthread_setcanceltype); 18bb535300SJeff Roberson __weak_reference(_pthread_testcancel, pthread_testcancel); 19bb535300SJeff Roberson 204cd18a22SMike Makonnen /* 214cd18a22SMike Makonnen * Posix requires this function to be async-cancel-safe, so it 224cd18a22SMike Makonnen * may not aquire any type of resource or call any functions 234cd18a22SMike Makonnen * that might do so. 244cd18a22SMike Makonnen */ 25bb535300SJeff Roberson int 26bb535300SJeff Roberson _pthread_cancel(pthread_t pthread) 27bb535300SJeff Roberson { 284cd18a22SMike Makonnen /* Don't continue if cancellation has already been set. */ 294cd18a22SMike Makonnen if (atomic_cmpset_int(&pthread->cancellation, (int)CS_NULL, 304cd18a22SMike Makonnen (int)CS_PENDING) != 1) 314cd18a22SMike Makonnen return (0); 32bb535300SJeff Roberson 33d39d6512SMike Makonnen /* 344cd18a22SMike Makonnen * Only wakeup threads that are in cancellation points or 354cd18a22SMike Makonnen * have set async cancel. 364cd18a22SMike Makonnen * XXX - access to pthread->flags is not safe. We should just 374cd18a22SMike Makonnen * unconditionally wake the thread and make sure that 384cd18a22SMike Makonnen * the the library correctly handles spurious wakeups. 39d39d6512SMike Makonnen */ 404cd18a22SMike Makonnen if ((pthread->cancellationpoint || pthread->cancelmode == M_ASYNC) && 414cd18a22SMike Makonnen (pthread->flags & PTHREAD_FLAGS_NOT_RUNNING) != 0) 424cd18a22SMike Makonnen PTHREAD_WAKE(pthread); 434cd18a22SMike Makonnen return (0); 446da7f493SMike Makonnen } 456da7f493SMike Makonnen 466da7f493SMike Makonnen /* 474cd18a22SMike Makonnen * Posix requires this function to be async-cancel-safe, so it 484cd18a22SMike Makonnen * may not aquire any type of resource or call any functions 494cd18a22SMike Makonnen * that might do so. 506da7f493SMike Makonnen */ 51bb535300SJeff Roberson int 52bb535300SJeff Roberson _pthread_setcancelstate(int state, int *oldstate) 53bb535300SJeff Roberson { 544cd18a22SMike Makonnen int ostate; 55bb535300SJeff Roberson 564cd18a22SMike Makonnen ostate = (curthread->cancelmode == M_OFF) ? PTHREAD_CANCEL_DISABLE : 574cd18a22SMike Makonnen PTHREAD_CANCEL_ENABLE; 58bb535300SJeff Roberson switch (state) { 59bb535300SJeff Roberson case PTHREAD_CANCEL_ENABLE: 604cd18a22SMike Makonnen curthread->cancelmode = curthread->cancelstate; 61bb535300SJeff Roberson break; 62bb535300SJeff Roberson case PTHREAD_CANCEL_DISABLE: 634cd18a22SMike Makonnen if (curthread->cancelmode != M_OFF) { 644cd18a22SMike Makonnen curthread->cancelstate = curthread->cancelmode; 654cd18a22SMike Makonnen curthread->cancelmode = M_OFF; 66bb535300SJeff Roberson } 67bb535300SJeff Roberson break; 68bb535300SJeff Roberson default: 69bb535300SJeff Roberson return (EINVAL); 70bb535300SJeff Roberson } 714cd18a22SMike Makonnen if (oldstate != NULL) 724cd18a22SMike Makonnen *oldstate = ostate; 734cd18a22SMike Makonnen return (0); 744cd18a22SMike Makonnen } 75bb535300SJeff Roberson 764cd18a22SMike Makonnen /* 774cd18a22SMike Makonnen * Posix requires this function to be async-cancel-safe, so it 784cd18a22SMike Makonnen * may not aquire any type of resource or call any functions that 794cd18a22SMike Makonnen * might do so. 804cd18a22SMike Makonnen */ 814cd18a22SMike Makonnen int 824cd18a22SMike Makonnen _pthread_setcanceltype(int type, int *oldtype) 834cd18a22SMike Makonnen { 844cd18a22SMike Makonnen enum cancel_mode omode; 854cd18a22SMike Makonnen 864cd18a22SMike Makonnen omode = curthread->cancelstate; 874cd18a22SMike Makonnen switch (type) { 884cd18a22SMike Makonnen case PTHREAD_CANCEL_ASYNCHRONOUS: 894cd18a22SMike Makonnen if (curthread->cancelmode != M_OFF) 904cd18a22SMike Makonnen curthread->cancelmode = M_ASYNC; 914cd18a22SMike Makonnen curthread->cancelstate = M_ASYNC; 924cd18a22SMike Makonnen break; 934cd18a22SMike Makonnen case PTHREAD_CANCEL_DEFERRED: 944cd18a22SMike Makonnen if (curthread->cancelmode != M_OFF) 954cd18a22SMike Makonnen curthread->cancelmode = M_DEFERRED; 964cd18a22SMike Makonnen curthread->cancelstate = M_DEFERRED; 974cd18a22SMike Makonnen break; 984cd18a22SMike Makonnen default: 994cd18a22SMike Makonnen return (EINVAL); 1004cd18a22SMike Makonnen } 1014cd18a22SMike Makonnen if (oldtype != NULL) { 1024cd18a22SMike Makonnen if (omode == M_DEFERRED) 1034cd18a22SMike Makonnen *oldtype = PTHREAD_CANCEL_DEFERRED; 1044cd18a22SMike Makonnen else if (omode == M_ASYNC) 1054cd18a22SMike Makonnen *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; 1064cd18a22SMike Makonnen } 107bb535300SJeff Roberson return (0); 108bb535300SJeff Roberson } 109bb535300SJeff Roberson 110bb535300SJeff Roberson void 111bb535300SJeff Roberson _pthread_testcancel(void) 112bb535300SJeff Roberson { 1136da7f493SMike Makonnen testcancel(); 1146da7f493SMike Makonnen } 1156da7f493SMike Makonnen 1166da7f493SMike Makonnen static void 1176da7f493SMike Makonnen testcancel() 1186da7f493SMike Makonnen { 1194cd18a22SMike Makonnen if (curthread->cancelmode != M_OFF) { 1206da7f493SMike Makonnen 1214cd18a22SMike Makonnen /* Cleanup a canceled thread only once. */ 1224cd18a22SMike Makonnen if (atomic_cmpset_int(&curthread->cancellation, 1234cd18a22SMike Makonnen (int)CS_PENDING, (int)CS_SET) == 1) { 124bb535300SJeff Roberson _thread_exit_cleanup(); 125bb535300SJeff Roberson pthread_exit(PTHREAD_CANCELED); 126bb535300SJeff Roberson PANIC("cancel"); 127bb535300SJeff Roberson } 128bb535300SJeff Roberson } 1294cd18a22SMike Makonnen } 130bb535300SJeff Roberson 131bb535300SJeff Roberson void 132bb535300SJeff Roberson _thread_enter_cancellation_point(void) 133bb535300SJeff Roberson { 1346da7f493SMike Makonnen testcancel(); 1354cd18a22SMike Makonnen curthread->cancellationpoint = 1; 136bb535300SJeff Roberson } 137bb535300SJeff Roberson 138bb535300SJeff Roberson void 139bb535300SJeff Roberson _thread_leave_cancellation_point(void) 140bb535300SJeff Roberson { 1414cd18a22SMike Makonnen curthread->cancellationpoint = 0; 1426da7f493SMike Makonnen testcancel(); 143bb535300SJeff Roberson } 144