2 * David Leonard <d@openbsd.org>, 1999. Public domain.
3 * $FreeBSD: src/lib/libc_r/uthread/uthread_cancel.c,v 1.3.2.9 2002/10/22 14:44:02 fjoe Exp $
4 * $DragonFly: src/lib/libc_r/uthread/uthread_cancel.c,v 1.4 2005/05/30 20:50:53 joerg Exp $
8 #include "pthread_private.h"
10 static void finish_cancellation(void *arg);
13 _pthread_cancel(pthread_t pthread)
17 if ((ret = _find_thread(pthread)) != 0) {
19 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK
20 || (pthread->flags & PTHREAD_EXITING) != 0) {
23 /* Protect the scheduling queues: */
24 _thread_kern_sig_defer();
26 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
27 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
28 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
29 /* Just mark it for cancellation: */
30 pthread->cancelflags |= PTHREAD_CANCELLING;
33 * Check if we need to kick it back into the
36 switch (pthread->state) {
38 /* No need to resume: */
39 pthread->cancelflags |= PTHREAD_CANCELLING;
47 /* Remove these threads from the work queue: */
48 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
50 PTHREAD_WORKQ_REMOVE(pthread);
57 /* Interrupt and resume: */
58 pthread->interrupted = 1;
59 pthread->cancelflags |= PTHREAD_CANCELLING;
60 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
65 * Disconnect the thread from the joinee:
67 if (pthread->join_status.thread != NULL) {
68 pthread->join_status.thread->joiner
70 pthread->join_status.thread = NULL;
72 pthread->cancelflags |= PTHREAD_CANCELLING;
73 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
82 * Threads in these states may be in queues.
83 * In order to preserve queue integrity, the
84 * cancelled thread must remove itself from the
85 * queue. Mark the thread as interrupted and
86 * needing cancellation, and set the state to
87 * running. When the thread resumes, it will
88 * remove itself from the queue and call the
89 * cancellation completion routine.
91 pthread->interrupted = 1;
92 pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
93 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
94 pthread->continuation = finish_cancellation;
100 /* Ignore - only here to silence -Wall: */
105 /* Unprotect the scheduling queues: */
106 _thread_kern_sig_undefer();
114 _pthread_setcancelstate(int state, int *oldstate)
116 struct pthread *curthread = _get_curthread();
120 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
123 case PTHREAD_CANCEL_ENABLE:
124 if (oldstate != NULL)
126 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
127 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
128 pthread_testcancel();
131 case PTHREAD_CANCEL_DISABLE:
132 if (oldstate != NULL)
134 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
145 _pthread_setcanceltype(int type, int *oldtype)
147 struct pthread *curthread = _get_curthread();
151 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
153 case PTHREAD_CANCEL_ASYNCHRONOUS:
156 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
157 pthread_testcancel();
160 case PTHREAD_CANCEL_DEFERRED:
163 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
174 _pthread_testcancel(void)
176 struct pthread *curthread = _get_curthread();
178 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
179 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) &&
180 ((curthread->flags & PTHREAD_EXITING) == 0)) {
182 * It is possible for this thread to be swapped out
183 * while performing cancellation; do not allow it
184 * to be cancelled again.
186 curthread->cancelflags &= ~PTHREAD_CANCELLING;
187 _thread_exit_cleanup();
188 pthread_exit(PTHREAD_CANCELED);
194 _thread_enter_cancellation_point(void)
196 struct pthread *curthread = _get_curthread();
198 /* Look for a cancellation before we block: */
199 pthread_testcancel();
200 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
204 _thread_leave_cancellation_point(void)
206 struct pthread *curthread = _get_curthread();
208 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
209 /* Look for a cancellation after we unblock: */
210 pthread_testcancel();
214 finish_cancellation(void *arg)
216 struct pthread *curthread = _get_curthread();
218 curthread->continuation = NULL;
219 curthread->interrupted = 0;
221 if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
222 curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
223 _thread_exit_cleanup();
224 pthread_exit(PTHREAD_CANCELED);
228 __strong_reference(_pthread_cancel, pthread_cancel);
229 __strong_reference(_pthread_setcancelstate, pthread_setcancelstate);
230 __strong_reference(_pthread_setcanceltype, pthread_setcanceltype);
231 __strong_reference(_pthread_testcancel, pthread_testcancel);