1 /* 2 * David Leonard <d@openbsd.org>, 1999. Public domain. 3 * $FreeBSD$ 4 */ 5 #include <sys/errno.h> 6 #include <pthread.h> 7 #include "thr_private.h" 8 9 __weak_reference(_pthread_cancel, pthread_cancel); 10 __weak_reference(_pthread_setcancelstate, pthread_setcancelstate); 11 __weak_reference(_pthread_setcanceltype, pthread_setcanceltype); 12 __weak_reference(_pthread_testcancel, pthread_testcancel); 13 14 int 15 _pthread_cancel(pthread_t pthread) 16 { 17 int ret; 18 19 if ((ret = _find_thread(pthread)) != 0) { 20 /* NOTHING */ 21 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK 22 || (pthread->flags & PTHREAD_EXITING) != 0) { 23 ret = 0; 24 } else { 25 GIANT_LOCK(curthread); 26 27 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || 28 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && 29 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) 30 /* Just mark it for cancellation: */ 31 pthread->cancelflags |= PTHREAD_CANCELLING; 32 else { 33 /* 34 * Check if we need to kick it back into the 35 * run queue: 36 */ 37 switch (pthread->state) { 38 case PS_RUNNING: 39 /* No need to resume: */ 40 pthread->cancelflags |= PTHREAD_CANCELLING; 41 break; 42 43 case PS_SLEEP_WAIT: 44 case PS_WAIT_WAIT: 45 pthread->cancelflags |= PTHREAD_CANCELLING; 46 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 47 break; 48 49 case PS_JOIN: 50 /* 51 * Disconnect the thread from the joinee: 52 */ 53 if (pthread->join_status.thread != NULL) { 54 pthread->join_status.thread->joiner 55 = NULL; 56 pthread->join_status.thread = NULL; 57 } 58 pthread->cancelflags |= PTHREAD_CANCELLING; 59 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 60 break; 61 62 case PS_MUTEX_WAIT: 63 case PS_COND_WAIT: 64 /* 65 * Threads in these states may be in queues. 66 * In order to preserve queue integrity, the 67 * cancelled thread must remove itself from the 68 * queue. When the thread resumes, it will 69 * remove itself from the queue and call the 70 * cancellation routine. 71 */ 72 pthread->cancelflags |= PTHREAD_CANCELLING; 73 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 74 break; 75 76 case PS_DEAD: 77 case PS_DEADLOCK: 78 case PS_STATE_MAX: 79 /* Ignore - only here to silence -Wall: */ 80 break; 81 } 82 } 83 84 /* Unprotect the scheduling queues: */ 85 GIANT_UNLOCK(curthread); 86 87 ret = 0; 88 } 89 return (ret); 90 } 91 92 int 93 _pthread_setcancelstate(int state, int *oldstate) 94 { 95 int ostate; 96 97 GIANT_LOCK(curthread); 98 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; 99 100 switch (state) { 101 case PTHREAD_CANCEL_ENABLE: 102 if (oldstate != NULL) 103 *oldstate = ostate; 104 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; 105 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) 106 break; 107 GIANT_UNLOCK(curthread); 108 pthread_testcancel(); 109 break; 110 case PTHREAD_CANCEL_DISABLE: 111 if (oldstate != NULL) 112 *oldstate = ostate; 113 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; 114 GIANT_UNLOCK(curthread); 115 break; 116 default: 117 GIANT_UNLOCK(curthread); 118 return (EINVAL); 119 } 120 121 return (0); 122 } 123 124 int 125 _pthread_setcanceltype(int type, int *oldtype) 126 { 127 int otype; 128 129 GIANT_LOCK(curthread); 130 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; 131 switch (type) { 132 case PTHREAD_CANCEL_ASYNCHRONOUS: 133 if (oldtype != NULL) 134 *oldtype = otype; 135 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; 136 GIANT_UNLOCK(curthread); 137 pthread_testcancel(); 138 break; 139 case PTHREAD_CANCEL_DEFERRED: 140 if (oldtype != NULL) 141 *oldtype = otype; 142 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; 143 GIANT_UNLOCK(curthread); 144 break; 145 default: 146 GIANT_UNLOCK(curthread); 147 return (EINVAL); 148 } 149 150 return (0); 151 } 152 153 /* 154 * XXXTHR Make an internal locked version. 155 */ 156 void 157 _pthread_testcancel(void) 158 { 159 GIANT_LOCK(curthread); 160 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && 161 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) && 162 ((curthread->flags & PTHREAD_EXITING) == 0)) { 163 /* 164 * It is possible for this thread to be swapped out 165 * while performing cancellation; do not allow it 166 * to be cancelled again. 167 */ 168 curthread->cancelflags &= ~PTHREAD_CANCELLING; 169 GIANT_UNLOCK(curthread); 170 _thread_exit_cleanup(); 171 pthread_exit(PTHREAD_CANCELED); 172 PANIC("cancel"); 173 } 174 GIANT_UNLOCK(curthread); 175 } 176 177 void 178 _thread_enter_cancellation_point(void) 179 { 180 pthread_testcancel(); 181 182 GIANT_LOCK(curthread); 183 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; 184 GIANT_UNLOCK(curthread); 185 } 186 187 void 188 _thread_leave_cancellation_point(void) 189 { 190 GIANT_LOCK(curthread); 191 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; 192 GIANT_UNLOCK(curthread); 193 194 pthread_testcancel(); 195 } 196