2 * David Leonard <d@openbsd.org>, 1999. Public domain.
7 #include "pthread_private.h"
9 static void finish_cancellation(void *arg);
12 pthread_cancel(pthread_t pthread)
16 if ((ret = _find_thread(pthread)) != 0) {
18 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) {
21 /* Protect the scheduling queues: */
22 _thread_kern_sig_defer();
24 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
25 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
26 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
27 /* Just mark it for cancellation: */
28 pthread->cancelflags |= PTHREAD_CANCELLING;
31 * Check if we need to kick it back into the
34 switch (pthread->state) {
36 /* No need to resume: */
37 pthread->cancelflags |= PTHREAD_CANCELLING;
42 * This thread isn't in any scheduling
43 * queues; just change it's state:
45 pthread->cancelflags |= PTHREAD_CANCELLING;
46 PTHREAD_SET_STATE(pthread, PS_RUNNING);
54 /* Remove these threads from the work queue: */
55 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
57 PTHREAD_WORKQ_REMOVE(pthread);
64 /* Interrupt and resume: */
65 pthread->interrupted = 1;
66 pthread->cancelflags |= PTHREAD_CANCELLING;
67 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
77 * Threads in these states may be in queues.
78 * In order to preserve queue integrity, the
79 * cancelled thread must remove itself from the
80 * queue. Mark the thread as interrupted and
81 * needing cancellation, and set the state to
82 * running. When the thread resumes, it will
83 * remove itself from the queue and call the
84 * cancellation completion routine.
86 pthread->interrupted = 1;
87 pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
88 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
89 pthread->continuation = finish_cancellation;
95 /* Ignore - only here to silence -Wall: */
100 /* Unprotect the scheduling queues: */
101 _thread_kern_sig_undefer();
109 pthread_setcancelstate(int state, int *oldstate)
114 ostate = _thread_run->cancelflags & PTHREAD_CANCEL_DISABLE;
117 case PTHREAD_CANCEL_ENABLE:
118 if (oldstate != NULL)
120 _thread_run->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
121 if ((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
122 pthread_testcancel();
125 case PTHREAD_CANCEL_DISABLE:
126 if (oldstate != NULL)
128 _thread_run->cancelflags |= PTHREAD_CANCEL_DISABLE;
139 pthread_setcanceltype(int type, int *oldtype)
144 otype = _thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
146 case PTHREAD_CANCEL_ASYNCHRONOUS:
149 _thread_run->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
150 pthread_testcancel();
153 case PTHREAD_CANCEL_DEFERRED:
156 _thread_run->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
167 pthread_testcancel(void)
169 if (((_thread_run->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
170 ((_thread_run->cancelflags & PTHREAD_CANCELLING) != 0)) {
172 * It is possible for this thread to be swapped out
173 * while performing cancellation; do not allow it
174 * to be cancelled again.
176 _thread_run->cancelflags &= ~PTHREAD_CANCELLING;
177 _thread_exit_cleanup();
178 pthread_exit(PTHREAD_CANCELED);
184 _thread_enter_cancellation_point(void)
186 /* Look for a cancellation before we block: */
187 pthread_testcancel();
188 _thread_run->cancelflags |= PTHREAD_AT_CANCEL_POINT;
192 _thread_leave_cancellation_point(void)
194 _thread_run->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
195 /* Look for a cancellation after we unblock: */
196 pthread_testcancel();
200 finish_cancellation(void *arg)
202 _thread_run->continuation = NULL;
203 _thread_run->interrupted = 0;
205 if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
206 _thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
207 _thread_exit_cleanup();
208 pthread_exit(PTHREAD_CANCELED);