2 * David Leonard <d@openbsd.org>, 1999. Public domain.
7 #include "thr_private.h"
9 LT10_COMPAT_PRIVATE(_pthread_cancel);
10 LT10_COMPAT_DEFAULT(pthread_cancel);
11 LT10_COMPAT_PRIVATE(_pthread_setcancelstate);
12 LT10_COMPAT_DEFAULT(pthread_setcancelstate);
13 LT10_COMPAT_PRIVATE(_pthread_setcanceltype);
14 LT10_COMPAT_DEFAULT(pthread_setcanceltype);
15 LT10_COMPAT_PRIVATE(_pthread_testcancel);
16 LT10_COMPAT_DEFAULT(pthread_testcancel);
18 __weak_reference(_pthread_cancel, pthread_cancel);
19 __weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
20 __weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
21 __weak_reference(_pthread_testcancel, pthread_testcancel);
24 checkcancel(struct pthread *curthread)
26 if ((curthread->cancelflags & THR_CANCELLING) != 0) {
28 * It is possible for this thread to be swapped out
29 * while performing cancellation; do not allow it
30 * to be cancelled again.
32 if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
34 * This may happen once, but after this, it
35 * shouldn't happen again.
37 curthread->cancelflags &= ~THR_CANCELLING;
40 if ((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) {
41 curthread->cancelflags &= ~THR_CANCELLING;
49 testcancel(struct pthread *curthread)
51 if (checkcancel(curthread) != 0) {
52 /* Unlock before exiting: */
53 THR_THREAD_UNLOCK(curthread, curthread);
56 pthread_exit(PTHREAD_CANCELED);
62 _pthread_cancel(pthread_t pthread)
64 struct pthread *curthread = _get_curthread();
65 struct pthread *joinee = NULL;
66 struct kse_mailbox *kmbx = NULL;
69 if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) {
71 * Take the thread's lock while we change the cancel flags.
73 THR_THREAD_LOCK(curthread, pthread);
74 THR_SCHED_LOCK(curthread, pthread);
75 if (pthread->flags & THR_FLAGS_EXITING) {
76 THR_SCHED_UNLOCK(curthread, pthread);
77 THR_THREAD_UNLOCK(curthread, pthread);
78 _thr_ref_delete(curthread, pthread);
81 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
82 (((pthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
83 ((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)))
84 /* Just mark it for cancellation: */
85 pthread->cancelflags |= THR_CANCELLING;
88 * Check if we need to kick it back into the
91 switch (pthread->state) {
93 /* No need to resume: */
94 pthread->cancelflags |= THR_CANCELLING;
99 * These can't be removed from the queue.
100 * Just mark it as cancelling and tell it
101 * to yield once it leaves the critical
104 pthread->cancelflags |= THR_CANCELLING;
105 pthread->critical_yield = 1;
111 /* Interrupt and resume: */
112 pthread->interrupted = 1;
113 pthread->cancelflags |= THR_CANCELLING;
114 kmbx = _thr_setrunnable_unlocked(pthread);
118 /* Disconnect the thread from the joinee: */
119 joinee = pthread->join_status.thread;
120 pthread->join_status.thread = NULL;
121 pthread->cancelflags |= THR_CANCELLING;
122 kmbx = _thr_setrunnable_unlocked(pthread);
123 if ((joinee != NULL) &&
124 (pthread->kseg == joinee->kseg)) {
125 /* Remove the joiner from the joinee. */
126 joinee->joiner = NULL;
135 * Threads in these states may be in queues.
136 * In order to preserve queue integrity, the
137 * cancelled thread must remove itself from the
138 * queue. Mark the thread as interrupted and
139 * needing cancellation, and set the state to
140 * running. When the thread resumes, it will
141 * remove itself from the queue and call the
142 * cancellation completion routine.
144 pthread->interrupted = 1;
145 pthread->cancelflags |= THR_CANCEL_NEEDED;
146 kmbx = _thr_setrunnable_unlocked(pthread);
147 pthread->continuation =
148 _thr_finish_cancellation;
154 /* Ignore - only here to silence -Wall: */
157 if ((pthread->cancelflags & THR_AT_CANCEL_POINT) &&
158 (pthread->blocked != 0 ||
159 pthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
160 kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
161 KSE_INTR_INTERRUPT, 0);
165 * Release the thread's lock and remove the
168 THR_SCHED_UNLOCK(curthread, pthread);
169 THR_THREAD_UNLOCK(curthread, pthread);
170 _thr_ref_delete(curthread, pthread);
174 if ((joinee != NULL) &&
175 (_thr_ref_add(curthread, joinee, /* include dead */1) == 0)) {
176 /* Remove the joiner from the joinee. */
177 THR_SCHED_LOCK(curthread, joinee);
178 joinee->joiner = NULL;
179 THR_SCHED_UNLOCK(curthread, joinee);
180 _thr_ref_delete(curthread, joinee);
187 _pthread_setcancelstate(int state, int *oldstate)
189 struct pthread *curthread = _get_curthread();
194 /* Take the thread's lock while fiddling with the state: */
195 THR_THREAD_LOCK(curthread, curthread);
197 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
200 case PTHREAD_CANCEL_ENABLE:
201 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
202 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
203 need_exit = checkcancel(curthread);
206 case PTHREAD_CANCEL_DISABLE:
207 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
214 THR_THREAD_UNLOCK(curthread, curthread);
215 if (need_exit != 0) {
217 pthread_exit(PTHREAD_CANCELED);
220 if (ret == 0 && oldstate != NULL)
227 _pthread_setcanceltype(int type, int *oldtype)
229 struct pthread *curthread = _get_curthread();
234 /* Take the thread's lock while fiddling with the state: */
235 THR_THREAD_LOCK(curthread, curthread);
237 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
239 case PTHREAD_CANCEL_ASYNCHRONOUS:
240 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
241 need_exit = checkcancel(curthread);
244 case PTHREAD_CANCEL_DEFERRED:
245 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
252 THR_THREAD_UNLOCK(curthread, curthread);
253 if (need_exit != 0) {
255 pthread_exit(PTHREAD_CANCELED);
258 if (ret == 0 && oldtype != NULL)
265 _pthread_testcancel(void)
267 struct pthread *curthread = _get_curthread();
269 THR_THREAD_LOCK(curthread, curthread);
270 testcancel(curthread);
271 THR_THREAD_UNLOCK(curthread, curthread);
275 _thr_cancel_enter(struct pthread *thread)
277 /* Look for a cancellation before we block: */
278 THR_THREAD_LOCK(thread, thread);
280 thread->cancelflags |= THR_AT_CANCEL_POINT;
281 THR_THREAD_UNLOCK(thread, thread);
285 _thr_cancel_leave(struct pthread *thread, int check)
287 THR_THREAD_LOCK(thread, thread);
288 thread->cancelflags &= ~THR_AT_CANCEL_POINT;
289 /* Look for a cancellation after we unblock: */
292 THR_THREAD_UNLOCK(thread, thread);
296 _thr_finish_cancellation(void *arg)
298 struct pthread *curthread = _get_curthread();
300 curthread->continuation = NULL;
301 curthread->interrupted = 0;
303 THR_THREAD_LOCK(curthread, curthread);
304 if ((curthread->cancelflags & THR_CANCEL_NEEDED) != 0) {
305 curthread->cancelflags &= ~THR_CANCEL_NEEDED;
306 THR_THREAD_UNLOCK(curthread, curthread);
308 pthread_exit(PTHREAD_CANCELED);
310 THR_THREAD_UNLOCK(curthread, curthread);