1/* 2 * David Leonard <d@openbsd.org>, 1999. Public domain.
| 1/* 2 * David Leonard <d@openbsd.org>, 1999. Public domain.
|
3 * $FreeBSD: head/lib/libkse/thread/thr_cancel.c 76909 2001-05-20 23:08:33Z jasone $
| 3 * $FreeBSD: head/lib/libkse/thread/thr_cancel.c 81750 2001-08-16 06:31:32Z jasone $
|
4 */ 5#include <sys/errno.h> 6#include <pthread.h> 7#include "pthread_private.h" 8 9static void finish_cancellation(void *arg); 10 11__weak_reference(_pthread_cancel, pthread_cancel); 12__weak_reference(_pthread_setcancelstate, pthread_setcancelstate); 13__weak_reference(_pthread_setcanceltype, pthread_setcanceltype); 14__weak_reference(_pthread_testcancel, pthread_testcancel); 15 16int 17_pthread_cancel(pthread_t pthread) 18{ 19 int ret; 20 21 if ((ret = _find_thread(pthread)) != 0) { 22 /* NOTHING */ 23 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) { 24 ret = 0; 25 } else { 26 /* Protect the scheduling queues: */ 27 _thread_kern_sig_defer(); 28 29 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || 30 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && 31 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) 32 /* Just mark it for cancellation: */ 33 pthread->cancelflags |= PTHREAD_CANCELLING; 34 else { 35 /* 36 * Check if we need to kick it back into the 37 * run queue: 38 */ 39 switch (pthread->state) { 40 case PS_RUNNING: 41 /* No need to resume: */ 42 pthread->cancelflags |= PTHREAD_CANCELLING; 43 break; 44 45 case PS_SPINBLOCK: 46 case PS_FDR_WAIT: 47 case PS_FDW_WAIT: 48 case PS_POLL_WAIT: 49 case PS_SELECT_WAIT: 50 /* Remove these threads from the work queue: */ 51 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) 52 != 0) 53 PTHREAD_WORKQ_REMOVE(pthread); 54 /* Fall through: */ 55 case PS_SIGTHREAD: 56 case PS_SLEEP_WAIT: 57 case PS_WAIT_WAIT: 58 case PS_SIGSUSPEND: 59 case PS_SIGWAIT: 60 /* Interrupt and resume: */ 61 pthread->interrupted = 1; 62 pthread->cancelflags |= PTHREAD_CANCELLING; 63 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 64 break; 65 66 case PS_JOIN:
| 4 */ 5#include <sys/errno.h> 6#include <pthread.h> 7#include "pthread_private.h" 8 9static void finish_cancellation(void *arg); 10 11__weak_reference(_pthread_cancel, pthread_cancel); 12__weak_reference(_pthread_setcancelstate, pthread_setcancelstate); 13__weak_reference(_pthread_setcanceltype, pthread_setcanceltype); 14__weak_reference(_pthread_testcancel, pthread_testcancel); 15 16int 17_pthread_cancel(pthread_t pthread) 18{ 19 int ret; 20 21 if ((ret = _find_thread(pthread)) != 0) { 22 /* NOTHING */ 23 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) { 24 ret = 0; 25 } else { 26 /* Protect the scheduling queues: */ 27 _thread_kern_sig_defer(); 28 29 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || 30 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && 31 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) 32 /* Just mark it for cancellation: */ 33 pthread->cancelflags |= PTHREAD_CANCELLING; 34 else { 35 /* 36 * Check if we need to kick it back into the 37 * run queue: 38 */ 39 switch (pthread->state) { 40 case PS_RUNNING: 41 /* No need to resume: */ 42 pthread->cancelflags |= PTHREAD_CANCELLING; 43 break; 44 45 case PS_SPINBLOCK: 46 case PS_FDR_WAIT: 47 case PS_FDW_WAIT: 48 case PS_POLL_WAIT: 49 case PS_SELECT_WAIT: 50 /* Remove these threads from the work queue: */ 51 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) 52 != 0) 53 PTHREAD_WORKQ_REMOVE(pthread); 54 /* Fall through: */ 55 case PS_SIGTHREAD: 56 case PS_SLEEP_WAIT: 57 case PS_WAIT_WAIT: 58 case PS_SIGSUSPEND: 59 case PS_SIGWAIT: 60 /* Interrupt and resume: */ 61 pthread->interrupted = 1; 62 pthread->cancelflags |= PTHREAD_CANCELLING; 63 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 64 break; 65 66 case PS_JOIN:
|
| 67 /* 68 * Disconnect the thread from the joinee and 69 * detach: 70 */ 71 if (pthread->data.thread != NULL) { 72 pthread->data.thread->joiner = NULL; 73 pthread_detach((pthread_t) 74 pthread->data.thread); 75 } 76 pthread->cancelflags |= PTHREAD_CANCELLING; 77 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 78 break; 79
|
67 case PS_SUSPENDED: 68 if (pthread->suspended == SUSP_NO || 69 pthread->suspended == SUSP_YES ||
| 80 case PS_SUSPENDED: 81 if (pthread->suspended == SUSP_NO || 82 pthread->suspended == SUSP_YES ||
|
| 83 pthread->suspended == SUSP_JOIN ||
|
70 pthread->suspended == SUSP_NOWAIT) { 71 /* 72 * This thread isn't in any scheduling 73 * queues; just change it's state: 74 */ 75 pthread->cancelflags |= 76 PTHREAD_CANCELLING; 77 PTHREAD_SET_STATE(pthread, PS_RUNNING); 78 break; 79 } 80 /* FALLTHROUGH */ 81 case PS_MUTEX_WAIT: 82 case PS_COND_WAIT: 83 case PS_FDLR_WAIT: 84 case PS_FDLW_WAIT: 85 case PS_FILE_WAIT: 86 /* 87 * Threads in these states may be in queues. 88 * In order to preserve queue integrity, the 89 * cancelled thread must remove itself from the 90 * queue. Mark the thread as interrupted and 91 * needing cancellation, and set the state to 92 * running. When the thread resumes, it will 93 * remove itself from the queue and call the 94 * cancellation completion routine. 95 */ 96 pthread->interrupted = 1; 97 pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; 98 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 99 pthread->continuation = finish_cancellation; 100 break; 101 102 case PS_DEAD: 103 case PS_DEADLOCK: 104 case PS_STATE_MAX: 105 /* Ignore - only here to silence -Wall: */ 106 break; 107 } 108 } 109 110 /* Unprotect the scheduling queues: */ 111 _thread_kern_sig_undefer(); 112 113 ret = 0; 114 } 115 return (ret); 116} 117 118int 119_pthread_setcancelstate(int state, int *oldstate) 120{ 121 struct pthread *curthread = _get_curthread(); 122 int ostate; 123 int ret; 124 125 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; 126 127 switch (state) { 128 case PTHREAD_CANCEL_ENABLE: 129 if (oldstate != NULL) 130 *oldstate = ostate; 131 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; 132 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0) 133 pthread_testcancel(); 134 ret = 0; 135 break; 136 case PTHREAD_CANCEL_DISABLE: 137 if (oldstate != NULL) 138 *oldstate = ostate; 139 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; 140 ret = 0; 141 break; 142 default: 143 ret = EINVAL; 144 } 145 146 return (ret); 147} 148 149int 150_pthread_setcanceltype(int type, int *oldtype) 151{ 152 struct pthread *curthread = _get_curthread(); 153 int otype; 154 int ret; 155 156 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; 157 switch (type) { 158 case PTHREAD_CANCEL_ASYNCHRONOUS: 159 if (oldtype != NULL) 160 *oldtype = otype; 161 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; 162 pthread_testcancel(); 163 ret = 0; 164 break; 165 case PTHREAD_CANCEL_DEFERRED: 166 if (oldtype != NULL) 167 *oldtype = otype; 168 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; 169 ret = 0; 170 break; 171 default: 172 ret = EINVAL; 173 } 174 175 return (ret); 176} 177 178void 179_pthread_testcancel(void) 180{ 181 struct pthread *curthread = _get_curthread(); 182 183 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && 184 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0)) { 185 /* 186 * It is possible for this thread to be swapped out 187 * while performing cancellation; do not allow it 188 * to be cancelled again. 189 */ 190 curthread->cancelflags &= ~PTHREAD_CANCELLING; 191 _thread_exit_cleanup();
| 84 pthread->suspended == SUSP_NOWAIT) { 85 /* 86 * This thread isn't in any scheduling 87 * queues; just change it's state: 88 */ 89 pthread->cancelflags |= 90 PTHREAD_CANCELLING; 91 PTHREAD_SET_STATE(pthread, PS_RUNNING); 92 break; 93 } 94 /* FALLTHROUGH */ 95 case PS_MUTEX_WAIT: 96 case PS_COND_WAIT: 97 case PS_FDLR_WAIT: 98 case PS_FDLW_WAIT: 99 case PS_FILE_WAIT: 100 /* 101 * Threads in these states may be in queues. 102 * In order to preserve queue integrity, the 103 * cancelled thread must remove itself from the 104 * queue. Mark the thread as interrupted and 105 * needing cancellation, and set the state to 106 * running. When the thread resumes, it will 107 * remove itself from the queue and call the 108 * cancellation completion routine. 109 */ 110 pthread->interrupted = 1; 111 pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; 112 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 113 pthread->continuation = finish_cancellation; 114 break; 115 116 case PS_DEAD: 117 case PS_DEADLOCK: 118 case PS_STATE_MAX: 119 /* Ignore - only here to silence -Wall: */ 120 break; 121 } 122 } 123 124 /* Unprotect the scheduling queues: */ 125 _thread_kern_sig_undefer(); 126 127 ret = 0; 128 } 129 return (ret); 130} 131 132int 133_pthread_setcancelstate(int state, int *oldstate) 134{ 135 struct pthread *curthread = _get_curthread(); 136 int ostate; 137 int ret; 138 139 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; 140 141 switch (state) { 142 case PTHREAD_CANCEL_ENABLE: 143 if (oldstate != NULL) 144 *oldstate = ostate; 145 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; 146 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0) 147 pthread_testcancel(); 148 ret = 0; 149 break; 150 case PTHREAD_CANCEL_DISABLE: 151 if (oldstate != NULL) 152 *oldstate = ostate; 153 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; 154 ret = 0; 155 break; 156 default: 157 ret = EINVAL; 158 } 159 160 return (ret); 161} 162 163int 164_pthread_setcanceltype(int type, int *oldtype) 165{ 166 struct pthread *curthread = _get_curthread(); 167 int otype; 168 int ret; 169 170 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; 171 switch (type) { 172 case PTHREAD_CANCEL_ASYNCHRONOUS: 173 if (oldtype != NULL) 174 *oldtype = otype; 175 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; 176 pthread_testcancel(); 177 ret = 0; 178 break; 179 case PTHREAD_CANCEL_DEFERRED: 180 if (oldtype != NULL) 181 *oldtype = otype; 182 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; 183 ret = 0; 184 break; 185 default: 186 ret = EINVAL; 187 } 188 189 return (ret); 190} 191 192void 193_pthread_testcancel(void) 194{ 195 struct pthread *curthread = _get_curthread(); 196 197 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && 198 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0)) { 199 /* 200 * It is possible for this thread to be swapped out 201 * while performing cancellation; do not allow it 202 * to be cancelled again. 203 */ 204 curthread->cancelflags &= ~PTHREAD_CANCELLING; 205 _thread_exit_cleanup();
|
192 pthread_detach((pthread_t)curthread);
| |
193 pthread_exit(PTHREAD_CANCELED); 194 PANIC("cancel"); 195 } 196} 197 198void 199_thread_enter_cancellation_point(void) 200{ 201 struct pthread *curthread = _get_curthread(); 202 203 /* Look for a cancellation before we block: */ 204 pthread_testcancel(); 205 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; 206} 207 208void 209_thread_leave_cancellation_point(void) 210{ 211 struct pthread *curthread = _get_curthread(); 212 213 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; 214 /* Look for a cancellation after we unblock: */ 215 pthread_testcancel(); 216} 217 218static void 219finish_cancellation(void *arg) 220{ 221 struct pthread *curthread = _get_curthread(); 222 223 curthread->continuation = NULL; 224 curthread->interrupted = 0; 225 226 if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) { 227 curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED; 228 _thread_exit_cleanup();
| 206 pthread_exit(PTHREAD_CANCELED); 207 PANIC("cancel"); 208 } 209} 210 211void 212_thread_enter_cancellation_point(void) 213{ 214 struct pthread *curthread = _get_curthread(); 215 216 /* Look for a cancellation before we block: */ 217 pthread_testcancel(); 218 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; 219} 220 221void 222_thread_leave_cancellation_point(void) 223{ 224 struct pthread *curthread = _get_curthread(); 225 226 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; 227 /* Look for a cancellation after we unblock: */ 228 pthread_testcancel(); 229} 230 231static void 232finish_cancellation(void *arg) 233{ 234 struct pthread *curthread = _get_curthread(); 235 236 curthread->continuation = NULL; 237 curthread->interrupted = 0; 238 239 if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) { 240 curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED; 241 _thread_exit_cleanup();
|
229 pthread_detach((pthread_t)curthread);
| |
230 pthread_exit(PTHREAD_CANCELED); 231 } 232}
| 242 pthread_exit(PTHREAD_CANCELED); 243 } 244}
|