MFS - Use mmap() instead of malloc().
[dragonfly.git] / lib / libc_r / uthread / uthread_cancel.c
blobec663a2dabc218fb3c157cac9799200098dd7169
1 /*
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 $
5 */
6 #include <sys/errno.h>
7 #include <pthread.h>
8 #include "pthread_private.h"
10 static void finish_cancellation(void *arg);
12 int
13 _pthread_cancel(pthread_t pthread)
15 int ret;
17 if ((ret = _find_thread(pthread)) != 0) {
18 /* NOTHING */
19 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK
20 || (pthread->flags & PTHREAD_EXITING) != 0) {
21 ret = 0;
22 } else {
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;
31 else {
33 * Check if we need to kick it back into the
34 * run queue:
36 switch (pthread->state) {
37 case PS_RUNNING:
38 /* No need to resume: */
39 pthread->cancelflags |= PTHREAD_CANCELLING;
40 break;
42 case PS_SPINBLOCK:
43 case PS_FDR_WAIT:
44 case PS_FDW_WAIT:
45 case PS_POLL_WAIT:
46 case PS_SELECT_WAIT:
47 /* Remove these threads from the work queue: */
48 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
49 != 0)
50 PTHREAD_WORKQ_REMOVE(pthread);
51 /* Fall through: */
52 case PS_SIGTHREAD:
53 case PS_SLEEP_WAIT:
54 case PS_WAIT_WAIT:
55 case PS_SIGSUSPEND:
56 case PS_SIGWAIT:
57 /* Interrupt and resume: */
58 pthread->interrupted = 1;
59 pthread->cancelflags |= PTHREAD_CANCELLING;
60 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
61 break;
63 case PS_JOIN:
65 * Disconnect the thread from the joinee:
67 if (pthread->join_status.thread != NULL) {
68 pthread->join_status.thread->joiner
69 = NULL;
70 pthread->join_status.thread = NULL;
72 pthread->cancelflags |= PTHREAD_CANCELLING;
73 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
74 break;
76 case PS_SUSPENDED:
77 case PS_MUTEX_WAIT:
78 case PS_COND_WAIT:
79 case PS_FDLR_WAIT:
80 case PS_FDLW_WAIT:
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;
95 break;
97 case PS_DEAD:
98 case PS_DEADLOCK:
99 case PS_STATE_MAX:
100 /* Ignore - only here to silence -Wall: */
101 break;
105 /* Unprotect the scheduling queues: */
106 _thread_kern_sig_undefer();
108 ret = 0;
110 return (ret);
114 _pthread_setcancelstate(int state, int *oldstate)
116 struct pthread *curthread = _get_curthread();
117 int ostate;
118 int ret;
120 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
122 switch (state) {
123 case PTHREAD_CANCEL_ENABLE:
124 if (oldstate != NULL)
125 *oldstate = ostate;
126 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
127 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
128 pthread_testcancel();
129 ret = 0;
130 break;
131 case PTHREAD_CANCEL_DISABLE:
132 if (oldstate != NULL)
133 *oldstate = ostate;
134 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
135 ret = 0;
136 break;
137 default:
138 ret = EINVAL;
141 return (ret);
145 _pthread_setcanceltype(int type, int *oldtype)
147 struct pthread *curthread = _get_curthread();
148 int otype;
149 int ret;
151 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
152 switch (type) {
153 case PTHREAD_CANCEL_ASYNCHRONOUS:
154 if (oldtype != NULL)
155 *oldtype = otype;
156 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
157 pthread_testcancel();
158 ret = 0;
159 break;
160 case PTHREAD_CANCEL_DEFERRED:
161 if (oldtype != NULL)
162 *oldtype = otype;
163 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
164 ret = 0;
165 break;
166 default:
167 ret = EINVAL;
170 return (ret);
173 void
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);
189 PANIC("cancel");
193 void
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;
203 void
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();
213 static void
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);