2 * David Leonard <d@openbsd.org>, 1999. Public domain.
7 #include "pthread_private.h"
9 static void finish_cancellation(void *arg);
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 _pthread_cancel(pthread_t pthread)
21 if ((ret = _find_thread(pthread)) != 0) {
23 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK
24 || (pthread->flags & PTHREAD_EXITING) != 0) {
27 /* Protect the scheduling queues: */
28 _thread_kern_sig_defer();
30 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
31 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
32 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
33 /* Just mark it for cancellation: */
34 pthread->cancelflags |= PTHREAD_CANCELLING;
37 * Check if we need to kick it back into the
40 switch (pthread->state) {
42 /* No need to resume: */
43 pthread->cancelflags |= PTHREAD_CANCELLING;
51 /* Remove these threads from the work queue: */
52 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
54 PTHREAD_WORKQ_REMOVE(pthread);
61 /* Interrupt and resume: */
62 pthread->interrupted = 1;
63 pthread->cancelflags |= PTHREAD_CANCELLING;
64 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
69 * Disconnect the thread from the joinee:
71 if (pthread->join_status.thread != NULL) {
72 pthread->join_status.thread->joiner
74 pthread->join_status.thread = NULL;
76 pthread->cancelflags |= PTHREAD_CANCELLING;
77 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
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.
96 pthread->interrupted = 1;
97 pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
98 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
99 pthread->continuation = finish_cancellation;
105 /* Ignore - only here to silence -Wall: */
110 /* Unprotect the scheduling queues: */
111 _thread_kern_sig_undefer();
119 _pthread_setcancelstate(int state, int *oldstate)
121 struct pthread *curthread = _get_curthread();
125 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
128 case PTHREAD_CANCEL_ENABLE:
129 if (oldstate != NULL)
131 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
132 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
133 pthread_testcancel();
136 case PTHREAD_CANCEL_DISABLE:
137 if (oldstate != NULL)
139 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
150 _pthread_setcanceltype(int type, int *oldtype)
152 struct pthread *curthread = _get_curthread();
156 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
158 case PTHREAD_CANCEL_ASYNCHRONOUS:
161 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
162 pthread_testcancel();
165 case PTHREAD_CANCEL_DEFERRED:
168 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
179 _pthread_testcancel(void)
181 struct pthread *curthread = _get_curthread();
183 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
184 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) &&
185 ((curthread->flags & PTHREAD_EXITING) == 0)) {
187 * It is possible for this thread to be swapped out
188 * while performing cancellation; do not allow it
189 * to be cancelled again.
191 curthread->cancelflags &= ~PTHREAD_CANCELLING;
192 _thread_exit_cleanup();
193 pthread_exit(PTHREAD_CANCELED);
199 _thread_enter_cancellation_point(void)
201 struct pthread *curthread = _get_curthread();
203 /* Look for a cancellation before we block: */
204 pthread_testcancel();
205 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
209 _thread_leave_cancellation_point(void)
211 struct pthread *curthread = _get_curthread();
213 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
214 /* Look for a cancellation after we unblock: */
215 pthread_testcancel();
219 finish_cancellation(void *arg)
221 struct pthread *curthread = _get_curthread();
223 curthread->continuation = NULL;
224 curthread->interrupted = 0;
226 if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
227 curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
228 _thread_exit_cleanup();
229 pthread_exit(PTHREAD_CANCELED);