1 /* 2 * David Leonard <d@openbsd.org>, 1999. Public domain. 3 * $FreeBSD$ 4 */ 5 #include <sys/errno.h> 6 #include <pthread.h> 7 #include <stdlib.h> 8 #include "thr_private.h" 9 10 /* 11 * Static prototypes 12 */ 13 static void testcancel(void); 14 15 __weak_reference(_pthread_cancel, pthread_cancel); 16 __weak_reference(_pthread_setcancelstate, pthread_setcancelstate); 17 __weak_reference(_pthread_setcanceltype, pthread_setcanceltype); 18 __weak_reference(_pthread_testcancel, pthread_testcancel); 19 20 /* 21 * Posix requires this function to be async-cancel-safe, so it 22 * may not aquire any type of resource or call any functions 23 * that might do so. 24 */ 25 int 26 _pthread_cancel(pthread_t pthread) 27 { 28 /* Don't continue if cancellation has already been set. */ 29 if (atomic_cmpset_int(&pthread->cancellation, (int)CS_NULL, 30 (int)CS_PENDING) != 1) 31 return (0); 32 33 /* 34 * Only wakeup threads that are in cancellation points or 35 * have set async cancel. 36 * XXX - access to pthread->flags is not safe. We should just 37 * unconditionally wake the thread and make sure that 38 * the the library correctly handles spurious wakeups. 39 */ 40 if ((pthread->cancellationpoint || pthread->cancelmode == M_ASYNC) && 41 (pthread->flags & PTHREAD_FLAGS_NOT_RUNNING) != 0) 42 PTHREAD_WAKE(pthread); 43 return (0); 44 } 45 46 /* 47 * Posix requires this function to be async-cancel-safe, so it 48 * may not aquire any type of resource or call any functions 49 * that might do so. 50 */ 51 int 52 _pthread_setcancelstate(int state, int *oldstate) 53 { 54 int ostate; 55 56 ostate = (curthread->cancelmode == M_OFF) ? PTHREAD_CANCEL_DISABLE : 57 PTHREAD_CANCEL_ENABLE; 58 switch (state) { 59 case PTHREAD_CANCEL_ENABLE: 60 curthread->cancelmode = curthread->cancelstate; 61 break; 62 case PTHREAD_CANCEL_DISABLE: 63 if (curthread->cancelmode != M_OFF) { 64 curthread->cancelstate = curthread->cancelmode; 65 curthread->cancelmode = M_OFF; 66 } 67 break; 68 default: 69 return (EINVAL); 70 } 71 if (oldstate != NULL) 72 *oldstate = ostate; 73 return (0); 74 } 75 76 /* 77 * Posix requires this function to be async-cancel-safe, so it 78 * may not aquire any type of resource or call any functions that 79 * might do so. 80 */ 81 int 82 _pthread_setcanceltype(int type, int *oldtype) 83 { 84 enum cancel_mode omode; 85 86 omode = curthread->cancelstate; 87 switch (type) { 88 case PTHREAD_CANCEL_ASYNCHRONOUS: 89 if (curthread->cancelmode != M_OFF) 90 curthread->cancelmode = M_ASYNC; 91 curthread->cancelstate = M_ASYNC; 92 break; 93 case PTHREAD_CANCEL_DEFERRED: 94 if (curthread->cancelmode != M_OFF) 95 curthread->cancelmode = M_DEFERRED; 96 curthread->cancelstate = M_DEFERRED; 97 break; 98 default: 99 return (EINVAL); 100 } 101 if (oldtype != NULL) { 102 if (omode == M_DEFERRED) 103 *oldtype = PTHREAD_CANCEL_DEFERRED; 104 else if (omode == M_ASYNC) 105 *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; 106 } 107 return (0); 108 } 109 110 void 111 _pthread_testcancel(void) 112 { 113 testcancel(); 114 } 115 116 static void 117 testcancel() 118 { 119 if (curthread->cancelmode != M_OFF) { 120 121 /* Cleanup a canceled thread only once. */ 122 if (atomic_cmpset_int(&curthread->cancellation, 123 (int)CS_PENDING, (int)CS_SET) == 1) { 124 _thread_exit_cleanup(); 125 pthread_exit(PTHREAD_CANCELED); 126 PANIC("cancel"); 127 } 128 } 129 } 130 131 void 132 _thread_enter_cancellation_point(void) 133 { 134 testcancel(); 135 curthread->cancellationpoint = 1; 136 } 137 138 void 139 _thread_leave_cancellation_point(void) 140 { 141 curthread->cancellationpoint = 0; 142 testcancel(); 143 } 144