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
);