Deleted Added
full compact
thr_cancel.c (76909) thr_cancel.c (81750)
1/*
2 * David Leonard <d@openbsd.org>, 1999. Public domain.
1/*
2 * David Leonard <d@openbsd.org>, 1999. Public domain.
3 * $FreeBSD: head/lib/libkse/thread/thr_cancel.c 76909 2001-05-20 23:08:33Z jasone $
3 * $FreeBSD: head/lib/libkse/thread/thr_cancel.c 81750 2001-08-16 06:31:32Z jasone $
4 */
5#include <sys/errno.h>
6#include <pthread.h>
7#include "pthread_private.h"
8
9static void finish_cancellation(void *arg);
10
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);
15
16int
17_pthread_cancel(pthread_t pthread)
18{
19 int ret;
20
21 if ((ret = _find_thread(pthread)) != 0) {
22 /* NOTHING */
23 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) {
24 ret = 0;
25 } else {
26 /* Protect the scheduling queues: */
27 _thread_kern_sig_defer();
28
29 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
30 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
31 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
32 /* Just mark it for cancellation: */
33 pthread->cancelflags |= PTHREAD_CANCELLING;
34 else {
35 /*
36 * Check if we need to kick it back into the
37 * run queue:
38 */
39 switch (pthread->state) {
40 case PS_RUNNING:
41 /* No need to resume: */
42 pthread->cancelflags |= PTHREAD_CANCELLING;
43 break;
44
45 case PS_SPINBLOCK:
46 case PS_FDR_WAIT:
47 case PS_FDW_WAIT:
48 case PS_POLL_WAIT:
49 case PS_SELECT_WAIT:
50 /* Remove these threads from the work queue: */
51 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
52 != 0)
53 PTHREAD_WORKQ_REMOVE(pthread);
54 /* Fall through: */
55 case PS_SIGTHREAD:
56 case PS_SLEEP_WAIT:
57 case PS_WAIT_WAIT:
58 case PS_SIGSUSPEND:
59 case PS_SIGWAIT:
60 /* Interrupt and resume: */
61 pthread->interrupted = 1;
62 pthread->cancelflags |= PTHREAD_CANCELLING;
63 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
64 break;
65
66 case PS_JOIN:
4 */
5#include <sys/errno.h>
6#include <pthread.h>
7#include "pthread_private.h"
8
9static void finish_cancellation(void *arg);
10
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);
15
16int
17_pthread_cancel(pthread_t pthread)
18{
19 int ret;
20
21 if ((ret = _find_thread(pthread)) != 0) {
22 /* NOTHING */
23 } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) {
24 ret = 0;
25 } else {
26 /* Protect the scheduling queues: */
27 _thread_kern_sig_defer();
28
29 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
30 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
31 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
32 /* Just mark it for cancellation: */
33 pthread->cancelflags |= PTHREAD_CANCELLING;
34 else {
35 /*
36 * Check if we need to kick it back into the
37 * run queue:
38 */
39 switch (pthread->state) {
40 case PS_RUNNING:
41 /* No need to resume: */
42 pthread->cancelflags |= PTHREAD_CANCELLING;
43 break;
44
45 case PS_SPINBLOCK:
46 case PS_FDR_WAIT:
47 case PS_FDW_WAIT:
48 case PS_POLL_WAIT:
49 case PS_SELECT_WAIT:
50 /* Remove these threads from the work queue: */
51 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
52 != 0)
53 PTHREAD_WORKQ_REMOVE(pthread);
54 /* Fall through: */
55 case PS_SIGTHREAD:
56 case PS_SLEEP_WAIT:
57 case PS_WAIT_WAIT:
58 case PS_SIGSUSPEND:
59 case PS_SIGWAIT:
60 /* Interrupt and resume: */
61 pthread->interrupted = 1;
62 pthread->cancelflags |= PTHREAD_CANCELLING;
63 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
64 break;
65
66 case PS_JOIN:
67 /*
68 * Disconnect the thread from the joinee and
69 * detach:
70 */
71 if (pthread->data.thread != NULL) {
72 pthread->data.thread->joiner = NULL;
73 pthread_detach((pthread_t)
74 pthread->data.thread);
75 }
76 pthread->cancelflags |= PTHREAD_CANCELLING;
77 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
78 break;
79
67 case PS_SUSPENDED:
68 if (pthread->suspended == SUSP_NO ||
69 pthread->suspended == SUSP_YES ||
80 case PS_SUSPENDED:
81 if (pthread->suspended == SUSP_NO ||
82 pthread->suspended == SUSP_YES ||
83 pthread->suspended == SUSP_JOIN ||
70 pthread->suspended == SUSP_NOWAIT) {
71 /*
72 * This thread isn't in any scheduling
73 * queues; just change it's state:
74 */
75 pthread->cancelflags |=
76 PTHREAD_CANCELLING;
77 PTHREAD_SET_STATE(pthread, PS_RUNNING);
78 break;
79 }
80 /* FALLTHROUGH */
81 case PS_MUTEX_WAIT:
82 case PS_COND_WAIT:
83 case PS_FDLR_WAIT:
84 case PS_FDLW_WAIT:
85 case PS_FILE_WAIT:
86 /*
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.
95 */
96 pthread->interrupted = 1;
97 pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
98 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
99 pthread->continuation = finish_cancellation;
100 break;
101
102 case PS_DEAD:
103 case PS_DEADLOCK:
104 case PS_STATE_MAX:
105 /* Ignore - only here to silence -Wall: */
106 break;
107 }
108 }
109
110 /* Unprotect the scheduling queues: */
111 _thread_kern_sig_undefer();
112
113 ret = 0;
114 }
115 return (ret);
116}
117
118int
119_pthread_setcancelstate(int state, int *oldstate)
120{
121 struct pthread *curthread = _get_curthread();
122 int ostate;
123 int ret;
124
125 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
126
127 switch (state) {
128 case PTHREAD_CANCEL_ENABLE:
129 if (oldstate != NULL)
130 *oldstate = ostate;
131 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
132 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
133 pthread_testcancel();
134 ret = 0;
135 break;
136 case PTHREAD_CANCEL_DISABLE:
137 if (oldstate != NULL)
138 *oldstate = ostate;
139 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
140 ret = 0;
141 break;
142 default:
143 ret = EINVAL;
144 }
145
146 return (ret);
147}
148
149int
150_pthread_setcanceltype(int type, int *oldtype)
151{
152 struct pthread *curthread = _get_curthread();
153 int otype;
154 int ret;
155
156 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
157 switch (type) {
158 case PTHREAD_CANCEL_ASYNCHRONOUS:
159 if (oldtype != NULL)
160 *oldtype = otype;
161 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
162 pthread_testcancel();
163 ret = 0;
164 break;
165 case PTHREAD_CANCEL_DEFERRED:
166 if (oldtype != NULL)
167 *oldtype = otype;
168 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
169 ret = 0;
170 break;
171 default:
172 ret = EINVAL;
173 }
174
175 return (ret);
176}
177
178void
179_pthread_testcancel(void)
180{
181 struct pthread *curthread = _get_curthread();
182
183 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
184 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0)) {
185 /*
186 * It is possible for this thread to be swapped out
187 * while performing cancellation; do not allow it
188 * to be cancelled again.
189 */
190 curthread->cancelflags &= ~PTHREAD_CANCELLING;
191 _thread_exit_cleanup();
84 pthread->suspended == SUSP_NOWAIT) {
85 /*
86 * This thread isn't in any scheduling
87 * queues; just change it's state:
88 */
89 pthread->cancelflags |=
90 PTHREAD_CANCELLING;
91 PTHREAD_SET_STATE(pthread, PS_RUNNING);
92 break;
93 }
94 /* FALLTHROUGH */
95 case PS_MUTEX_WAIT:
96 case PS_COND_WAIT:
97 case PS_FDLR_WAIT:
98 case PS_FDLW_WAIT:
99 case PS_FILE_WAIT:
100 /*
101 * Threads in these states may be in queues.
102 * In order to preserve queue integrity, the
103 * cancelled thread must remove itself from the
104 * queue. Mark the thread as interrupted and
105 * needing cancellation, and set the state to
106 * running. When the thread resumes, it will
107 * remove itself from the queue and call the
108 * cancellation completion routine.
109 */
110 pthread->interrupted = 1;
111 pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
112 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
113 pthread->continuation = finish_cancellation;
114 break;
115
116 case PS_DEAD:
117 case PS_DEADLOCK:
118 case PS_STATE_MAX:
119 /* Ignore - only here to silence -Wall: */
120 break;
121 }
122 }
123
124 /* Unprotect the scheduling queues: */
125 _thread_kern_sig_undefer();
126
127 ret = 0;
128 }
129 return (ret);
130}
131
132int
133_pthread_setcancelstate(int state, int *oldstate)
134{
135 struct pthread *curthread = _get_curthread();
136 int ostate;
137 int ret;
138
139 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
140
141 switch (state) {
142 case PTHREAD_CANCEL_ENABLE:
143 if (oldstate != NULL)
144 *oldstate = ostate;
145 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
146 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
147 pthread_testcancel();
148 ret = 0;
149 break;
150 case PTHREAD_CANCEL_DISABLE:
151 if (oldstate != NULL)
152 *oldstate = ostate;
153 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
154 ret = 0;
155 break;
156 default:
157 ret = EINVAL;
158 }
159
160 return (ret);
161}
162
163int
164_pthread_setcanceltype(int type, int *oldtype)
165{
166 struct pthread *curthread = _get_curthread();
167 int otype;
168 int ret;
169
170 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
171 switch (type) {
172 case PTHREAD_CANCEL_ASYNCHRONOUS:
173 if (oldtype != NULL)
174 *oldtype = otype;
175 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
176 pthread_testcancel();
177 ret = 0;
178 break;
179 case PTHREAD_CANCEL_DEFERRED:
180 if (oldtype != NULL)
181 *oldtype = otype;
182 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
183 ret = 0;
184 break;
185 default:
186 ret = EINVAL;
187 }
188
189 return (ret);
190}
191
192void
193_pthread_testcancel(void)
194{
195 struct pthread *curthread = _get_curthread();
196
197 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
198 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0)) {
199 /*
200 * It is possible for this thread to be swapped out
201 * while performing cancellation; do not allow it
202 * to be cancelled again.
203 */
204 curthread->cancelflags &= ~PTHREAD_CANCELLING;
205 _thread_exit_cleanup();
192 pthread_detach((pthread_t)curthread);
193 pthread_exit(PTHREAD_CANCELED);
194 PANIC("cancel");
195 }
196}
197
198void
199_thread_enter_cancellation_point(void)
200{
201 struct pthread *curthread = _get_curthread();
202
203 /* Look for a cancellation before we block: */
204 pthread_testcancel();
205 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
206}
207
208void
209_thread_leave_cancellation_point(void)
210{
211 struct pthread *curthread = _get_curthread();
212
213 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
214 /* Look for a cancellation after we unblock: */
215 pthread_testcancel();
216}
217
218static void
219finish_cancellation(void *arg)
220{
221 struct pthread *curthread = _get_curthread();
222
223 curthread->continuation = NULL;
224 curthread->interrupted = 0;
225
226 if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
227 curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
228 _thread_exit_cleanup();
206 pthread_exit(PTHREAD_CANCELED);
207 PANIC("cancel");
208 }
209}
210
211void
212_thread_enter_cancellation_point(void)
213{
214 struct pthread *curthread = _get_curthread();
215
216 /* Look for a cancellation before we block: */
217 pthread_testcancel();
218 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
219}
220
221void
222_thread_leave_cancellation_point(void)
223{
224 struct pthread *curthread = _get_curthread();
225
226 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
227 /* Look for a cancellation after we unblock: */
228 pthread_testcancel();
229}
230
231static void
232finish_cancellation(void *arg)
233{
234 struct pthread *curthread = _get_curthread();
235
236 curthread->continuation = NULL;
237 curthread->interrupted = 0;
238
239 if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
240 curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED;
241 _thread_exit_cleanup();
229 pthread_detach((pthread_t)curthread);
230 pthread_exit(PTHREAD_CANCELED);
231 }
232}
242 pthread_exit(PTHREAD_CANCELED);
243 }
244}