2 * David Leonard <d@openbsd.org>, 1999. Public domain.
8 #include "un-namespace.h"
9 #include "thr_private.h"
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);
17 checkcancel(struct pthread *curthread)
19 if ((curthread->cancelflags & THR_CANCELLING) != 0) {
21 * It is possible for this thread to be swapped out
22 * while performing cancellation; do not allow it
23 * to be cancelled again.
25 if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
27 * This may happen once, but after this, it
28 * shouldn't happen again.
30 curthread->cancelflags &= ~THR_CANCELLING;
33 if ((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) {
34 curthread->cancelflags &= ~THR_CANCELLING;
42 testcancel(struct pthread *curthread)
44 if (checkcancel(curthread) != 0) {
45 /* Unlock before exiting: */
46 THR_THREAD_UNLOCK(curthread, curthread);
49 _pthread_exit(PTHREAD_CANCELED);
55 _pthread_cancel(pthread_t pthread)
57 struct pthread *curthread = _get_curthread();
58 struct pthread *joinee = NULL;
59 struct kse_mailbox *kmbx = NULL;
62 if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) {
64 * Take the thread's lock while we change the cancel flags.
66 THR_THREAD_LOCK(curthread, pthread);
67 THR_SCHED_LOCK(curthread, pthread);
68 if (pthread->flags & THR_FLAGS_EXITING) {
69 THR_SCHED_UNLOCK(curthread, pthread);
70 THR_THREAD_UNLOCK(curthread, pthread);
71 _thr_ref_delete(curthread, pthread);
74 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
75 (((pthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
76 ((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)))
77 /* Just mark it for cancellation: */
78 pthread->cancelflags |= THR_CANCELLING;
81 * Check if we need to kick it back into the
84 switch (pthread->state) {
86 /* No need to resume: */
87 pthread->cancelflags |= THR_CANCELLING;
92 * These can't be removed from the queue.
93 * Just mark it as cancelling and tell it
94 * to yield once it leaves the critical
97 pthread->cancelflags |= THR_CANCELLING;
98 pthread->critical_yield = 1;
104 /* Interrupt and resume: */
105 pthread->interrupted = 1;
106 pthread->cancelflags |= THR_CANCELLING;
107 kmbx = _thr_setrunnable_unlocked(pthread);
111 /* Disconnect the thread from the joinee: */
112 joinee = pthread->join_status.thread;
113 pthread->join_status.thread = NULL;
114 pthread->cancelflags |= THR_CANCELLING;
115 kmbx = _thr_setrunnable_unlocked(pthread);
116 if ((joinee != NULL) &&
117 (pthread->kseg == joinee->kseg)) {
118 /* Remove the joiner from the joinee. */
119 joinee->joiner = NULL;
128 * Threads in these states may be in queues.
129 * In order to preserve queue integrity, the
130 * cancelled thread must remove itself from the
131 * queue. Mark the thread as interrupted and
132 * needing cancellation, and set the state to
133 * running. When the thread resumes, it will
134 * remove itself from the queue and call the
135 * cancellation completion routine.
137 pthread->interrupted = 1;
138 pthread->cancelflags |= THR_CANCEL_NEEDED;
139 kmbx = _thr_setrunnable_unlocked(pthread);
140 pthread->continuation =
141 _thr_finish_cancellation;
147 /* Ignore - only here to silence -Wall: */
150 if ((pthread->cancelflags & THR_AT_CANCEL_POINT) &&
151 (pthread->blocked != 0 ||
152 pthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
153 kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
154 KSE_INTR_INTERRUPT, 0);
158 * Release the thread's lock and remove the
161 THR_SCHED_UNLOCK(curthread, pthread);
162 THR_THREAD_UNLOCK(curthread, pthread);
163 _thr_ref_delete(curthread, pthread);
167 if ((joinee != NULL) &&
168 (_thr_ref_add(curthread, joinee, /* include dead */1) == 0)) {
169 /* Remove the joiner from the joinee. */
170 THR_SCHED_LOCK(curthread, joinee);
171 joinee->joiner = NULL;
172 THR_SCHED_UNLOCK(curthread, joinee);
173 _thr_ref_delete(curthread, joinee);
180 _pthread_setcancelstate(int state, int *oldstate)
182 struct pthread *curthread = _get_curthread();
187 /* Take the thread's lock while fiddling with the state: */
188 THR_THREAD_LOCK(curthread, curthread);
190 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
193 case PTHREAD_CANCEL_ENABLE:
194 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
195 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
196 need_exit = checkcancel(curthread);
199 case PTHREAD_CANCEL_DISABLE:
200 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
207 THR_THREAD_UNLOCK(curthread, curthread);
208 if (need_exit != 0) {
210 _pthread_exit(PTHREAD_CANCELED);
213 if (ret == 0 && oldstate != NULL)
220 _pthread_setcanceltype(int type, int *oldtype)
222 struct pthread *curthread = _get_curthread();
227 /* Take the thread's lock while fiddling with the state: */
228 THR_THREAD_LOCK(curthread, curthread);
230 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
232 case PTHREAD_CANCEL_ASYNCHRONOUS:
233 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
234 need_exit = checkcancel(curthread);
237 case PTHREAD_CANCEL_DEFERRED:
238 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
245 THR_THREAD_UNLOCK(curthread, curthread);
246 if (need_exit != 0) {
248 _pthread_exit(PTHREAD_CANCELED);
251 if (ret == 0 && oldtype != NULL)
258 _pthread_testcancel(void)
260 struct pthread *curthread = _get_curthread();
262 THR_THREAD_LOCK(curthread, curthread);
263 testcancel(curthread);
264 THR_THREAD_UNLOCK(curthread, curthread);
268 _thr_cancel_enter(struct pthread *thread)
270 /* Look for a cancellation before we block: */
271 THR_THREAD_LOCK(thread, thread);
273 thread->cancelflags |= THR_AT_CANCEL_POINT;
274 THR_THREAD_UNLOCK(thread, thread);
278 _thr_cancel_leave(struct pthread *thread, int check)
280 THR_THREAD_LOCK(thread, thread);
281 thread->cancelflags &= ~THR_AT_CANCEL_POINT;
282 /* Look for a cancellation after we unblock: */
285 THR_THREAD_UNLOCK(thread, thread);
289 _thr_finish_cancellation(void *arg __unused)
291 struct pthread *curthread = _get_curthread();
293 curthread->continuation = NULL;
294 curthread->interrupted = 0;
296 THR_THREAD_LOCK(curthread, curthread);
297 if ((curthread->cancelflags & THR_CANCEL_NEEDED) != 0) {
298 curthread->cancelflags &= ~THR_CANCEL_NEEDED;
299 THR_THREAD_UNLOCK(curthread, curthread);
301 _pthread_exit(PTHREAD_CANCELED);
303 THR_THREAD_UNLOCK(curthread, curthread);