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.2 2003/06/17 04:26:48 dillon Exp $
8 #include "pthread_private.h"
10 static void finish_cancellation(void *arg);
12 __weak_reference(_pthread_cancel, pthread_cancel);
13 __weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
14 __weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
15 __weak_reference(_pthread_testcancel, pthread_testcancel);
18 _pthread_cancel(pthread_t pthread)
22 if ((ret = _find_thread(pthread)) != 0) {
24 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK
25 || (pthread->flags & PTHREAD_EXITING) != 0) {
28 /* Protect the scheduling queues: */
29 _thread_kern_sig_defer();
31 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
32 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
33 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
34 /* Just mark it for cancellation: */
35 pthread->cancelflags |= PTHREAD_CANCELLING;
38 * Check if we need to kick it back into the
41 switch (pthread->state) {
43 /* No need to resume: */
44 pthread->cancelflags |= PTHREAD_CANCELLING;
52 /* Remove these threads from the work queue: */
53 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
55 PTHREAD_WORKQ_REMOVE(pthread);
62 /* Interrupt and resume: */
63 pthread->interrupted = 1;
64 pthread->cancelflags |= PTHREAD_CANCELLING;
65 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
70 * Disconnect the thread from the joinee:
72 if (pthread->join_status.thread != NULL) {
73 pthread->join_status.thread->joiner
75 pthread->join_status.thread = NULL;
77 pthread->cancelflags |= PTHREAD_CANCELLING;
78 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
88 * Threads in these states may be in queues.
89 * In order to preserve queue integrity, the
90 * cancelled thread must remove itself from the
91 * queue. Mark the thread as interrupted and
92 * needing cancellation, and set the state to
93 * running. When the thread resumes, it will
94 * remove itself from the queue and call the
95 * cancellation completion routine.
97 pthread->interrupted = 1;
98 pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
99 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
100 pthread->continuation = finish_cancellation;
106 /* Ignore - only here to silence -Wall: */
111 /* Unprotect the scheduling queues: */
112 _thread_kern_sig_undefer();
120 _pthread_setcancelstate(int state, int *oldstate)
122 struct pthread *curthread = _get_curthread();
126 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
129 case PTHREAD_CANCEL_ENABLE:
130 if (oldstate != NULL)
132 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
133 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
134 pthread_testcancel();
137 case PTHREAD_CANCEL_DISABLE:
138 if (oldstate != NULL)
140 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
151 _pthread_setcanceltype(int type, int *oldtype)
153 struct pthread *curthread = _get_curthread();
157 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
159 case PTHREAD_CANCEL_ASYNCHRONOUS:
162 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
163 pthread_testcancel();
166 case PTHREAD_CANCEL_DEFERRED:
169 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
180 _pthread_testcancel(void)
182 struct pthread *curthread = _get_curthread();
184 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
185 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) &&
186 ((curthread->flags & PTHREAD_EXITING) == 0)) {
188 * It is possible for this thread to be swapped out
189 * while performing cancellation; do not allow it
190 * to be cancelled again.
192 curthread->cancelflags &= ~PTHREAD_CANCELLING;
193 _thread_exit_cleanup();
194 pthread_exit(PTHREAD_CANCELED);
200 _thread_enter_cancellation_point(void)
202 struct pthread *curthread = _get_curthread();
204 /* Look for a cancellation before we block: */
205 pthread_testcancel();
206 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
210 _thread_leave_cancellation_point(void)
212 struct pthread *curthread = _get_curthread();
214 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
215 /* Look for a cancellation after we unblock: */
216 pthread_testcancel();
220 finish_cancellation(void *arg)
222 struct pthread *curthread = _get_curthread();
224 curthread->continuation = NULL;
225 curthread->interrupted = 0;
227 if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
228 curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
229 _thread_exit_cleanup();
230 pthread_exit(PTHREAD_CANCELED);