Deleted Added
full compact
thr_cancel.c (117277) thr_cancel.c (126000)
1/*
2 * David Leonard <d@openbsd.org>, 1999. Public domain.
1/*
2 * David Leonard <d@openbsd.org>, 1999. Public domain.
3 * $FreeBSD: head/lib/libthr/thread/thr_cancel.c 117277 2003-07-06 10:18:48Z mtm $
3 * $FreeBSD: head/lib/libthr/thread/thr_cancel.c 126000 2004-02-19 13:51:52Z mtm $
4 */
5#include <sys/errno.h>
6#include <pthread.h>
7#include <stdlib.h>
8#include "thr_private.h"
9
10/*
11 * Static prototypes
12 */
13static void testcancel(void);
14
15__weak_reference(_pthread_cancel, pthread_cancel);
16__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
17__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
18__weak_reference(_pthread_testcancel, pthread_testcancel);
19
20int
21_pthread_cancel(pthread_t pthread)
22{
23 int ret;
24 pthread_t joined;
25
26 /*
27 * When canceling a thread that has joined another thread, this
28 * routine breaks the normal lock order of locking first the
29 * joined and then the joiner. Therefore, it is necessary that
30 * if it can't obtain the second lock, that it release the first
31 * one and restart from the top.
32 */
33retry:
34 if ((ret = _find_thread(pthread)) != 0)
35 /* The thread is not on the list of active threads */
36 goto out;
37
38 _thread_critical_enter(pthread);
39
40 if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK
41 || (pthread->flags & PTHREAD_EXITING) != 0) {
42 /*
43 * The thread is in the process of (or has already) exited
44 * or is deadlocked.
45 */
46 _thread_critical_exit(pthread);
47 ret = 0;
48 goto out;
49 }
50
51 /*
52 * The thread is on the active thread list and is not in the process
53 * of exiting.
54 */
55
56 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
57 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
58 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
59 /* Just mark it for cancellation: */
60 pthread->cancelflags |= PTHREAD_CANCELLING;
61 else {
62 /*
63 * Check if we need to kick it back into the
64 * run queue:
65 */
66 switch (pthread->state) {
67 case PS_RUNNING:
68 /* No need to resume: */
69 pthread->cancelflags |= PTHREAD_CANCELLING;
70 break;
71
72 case PS_SLEEP_WAIT:
73 case PS_WAIT_WAIT:
74 pthread->cancelflags |= PTHREAD_CANCELLING;
75 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
76 break;
77
78 case PS_JOIN:
79 /*
80 * Disconnect the thread from the joinee:
81 */
82 if ((joined = pthread->join_status.thread) != NULL) {
83 UMTX_TRYLOCK(&joined->lock, ret);
84 if (ret == EBUSY) {
85 _thread_critical_exit(pthread);
86 goto retry;
87 }
88 pthread->join_status.thread->joiner = NULL;
89 UMTX_UNLOCK(&joined->lock);
90 joined = pthread->join_status.thread = NULL;
91 }
92 pthread->cancelflags |= PTHREAD_CANCELLING;
93 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
94 break;
95
4 */
5#include <sys/errno.h>
6#include <pthread.h>
7#include <stdlib.h>
8#include "thr_private.h"
9
10/*
11 * Static prototypes
12 */
13static void testcancel(void);
14
15__weak_reference(_pthread_cancel, pthread_cancel);
16__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
17__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
18__weak_reference(_pthread_testcancel, pthread_testcancel);
19
20int
21_pthread_cancel(pthread_t pthread)
22{
23 int ret;
24 pthread_t joined;
25
26 /*
27 * When canceling a thread that has joined another thread, this
28 * routine breaks the normal lock order of locking first the
29 * joined and then the joiner. Therefore, it is necessary that
30 * if it can't obtain the second lock, that it release the first
31 * one and restart from the top.
32 */
33retry:
34 if ((ret = _find_thread(pthread)) != 0)
35 /* The thread is not on the list of active threads */
36 goto out;
37
38 _thread_critical_enter(pthread);
39
40 if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK
41 || (pthread->flags & PTHREAD_EXITING) != 0) {
42 /*
43 * The thread is in the process of (or has already) exited
44 * or is deadlocked.
45 */
46 _thread_critical_exit(pthread);
47 ret = 0;
48 goto out;
49 }
50
51 /*
52 * The thread is on the active thread list and is not in the process
53 * of exiting.
54 */
55
56 if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
57 (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) &&
58 ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0)))
59 /* Just mark it for cancellation: */
60 pthread->cancelflags |= PTHREAD_CANCELLING;
61 else {
62 /*
63 * Check if we need to kick it back into the
64 * run queue:
65 */
66 switch (pthread->state) {
67 case PS_RUNNING:
68 /* No need to resume: */
69 pthread->cancelflags |= PTHREAD_CANCELLING;
70 break;
71
72 case PS_SLEEP_WAIT:
73 case PS_WAIT_WAIT:
74 pthread->cancelflags |= PTHREAD_CANCELLING;
75 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
76 break;
77
78 case PS_JOIN:
79 /*
80 * Disconnect the thread from the joinee:
81 */
82 if ((joined = pthread->join_status.thread) != NULL) {
83 UMTX_TRYLOCK(&joined->lock, ret);
84 if (ret == EBUSY) {
85 _thread_critical_exit(pthread);
86 goto retry;
87 }
88 pthread->join_status.thread->joiner = NULL;
89 UMTX_UNLOCK(&joined->lock);
90 joined = pthread->join_status.thread = NULL;
91 }
92 pthread->cancelflags |= PTHREAD_CANCELLING;
93 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
94 break;
95
96 case PS_BARRIER_WAIT:
96 case PS_MUTEX_WAIT:
97 case PS_COND_WAIT:
98 /*
99 * Threads in these states may be in queues.
100 * In order to preserve queue integrity, the
101 * cancelled thread must remove itself from the
102 * queue. When the thread resumes, it will
103 * remove itself from the queue and call the
104 * cancellation routine.
105 */
106 pthread->cancelflags |= PTHREAD_CANCELLING;
107 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
108 break;
109
110 case PS_DEAD:
111 case PS_DEADLOCK:
112 case PS_STATE_MAX:
113 /* Ignore - only here to silence -Wall: */
114 break;
115 }
116 }
117
118 /* Unprotect the scheduling queues: */
119 _thread_critical_exit(pthread);
120
121 ret = 0;
122out:
123 return (ret);
124}
125
126int
127_pthread_setcancelstate(int state, int *oldstate)
128{
129 int ostate, ret;
130
131 ret = 0;
132
133 _thread_critical_enter(curthread);
134
135 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
136
137 switch (state) {
138 case PTHREAD_CANCEL_ENABLE:
139 if (oldstate != NULL)
140 *oldstate = ostate;
141 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
142 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)
143 break;
144 testcancel();
145 break;
146 case PTHREAD_CANCEL_DISABLE:
147 if (oldstate != NULL)
148 *oldstate = ostate;
149 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
150 break;
151 default:
152 ret = EINVAL;
153 }
154
155 _thread_critical_exit(curthread);
156 return (ret);
157}
158
159int
160_pthread_setcanceltype(int type, int *oldtype)
161{
162 int otype;
163
164 _thread_critical_enter(curthread);
165 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
166 switch (type) {
167 case PTHREAD_CANCEL_ASYNCHRONOUS:
168 if (oldtype != NULL)
169 *oldtype = otype;
170 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
171 testcancel();
172 break;
173 case PTHREAD_CANCEL_DEFERRED:
174 if (oldtype != NULL)
175 *oldtype = otype;
176 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
177 break;
178 default:
179 return (EINVAL);
180 }
181
182 _thread_critical_exit(curthread);
183 return (0);
184}
185
186void
187_pthread_testcancel(void)
188{
189 _thread_critical_enter(curthread);
190 testcancel();
191 _thread_critical_exit(curthread);
192}
193
194static void
195testcancel()
196{
197 /*
198 * This pthread should already be locked by the caller.
199 */
200
201 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
202 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) &&
203 ((curthread->flags & PTHREAD_EXITING) == 0)) {
204 /*
205 * It is possible for this thread to be swapped out
206 * while performing cancellation; do not allow it
207 * to be cancelled again.
208 */
209 curthread->cancelflags &= ~PTHREAD_CANCELLING;
210 _thread_critical_exit(curthread);
211 _thread_exit_cleanup();
212 pthread_exit(PTHREAD_CANCELED);
213 PANIC("cancel");
214 }
215}
216
217void
218_thread_enter_cancellation_point(void)
219{
220 _thread_critical_enter(curthread);
221 testcancel();
222 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
223 _thread_critical_exit(curthread);
224}
225
226void
227_thread_leave_cancellation_point(void)
228{
229 _thread_critical_enter(curthread);
230 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
231 testcancel();
232 _thread_critical_exit(curthread);
233
234}
97 case PS_MUTEX_WAIT:
98 case PS_COND_WAIT:
99 /*
100 * Threads in these states may be in queues.
101 * In order to preserve queue integrity, the
102 * cancelled thread must remove itself from the
103 * queue. When the thread resumes, it will
104 * remove itself from the queue and call the
105 * cancellation routine.
106 */
107 pthread->cancelflags |= PTHREAD_CANCELLING;
108 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
109 break;
110
111 case PS_DEAD:
112 case PS_DEADLOCK:
113 case PS_STATE_MAX:
114 /* Ignore - only here to silence -Wall: */
115 break;
116 }
117 }
118
119 /* Unprotect the scheduling queues: */
120 _thread_critical_exit(pthread);
121
122 ret = 0;
123out:
124 return (ret);
125}
126
127int
128_pthread_setcancelstate(int state, int *oldstate)
129{
130 int ostate, ret;
131
132 ret = 0;
133
134 _thread_critical_enter(curthread);
135
136 ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
137
138 switch (state) {
139 case PTHREAD_CANCEL_ENABLE:
140 if (oldstate != NULL)
141 *oldstate = ostate;
142 curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
143 if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)
144 break;
145 testcancel();
146 break;
147 case PTHREAD_CANCEL_DISABLE:
148 if (oldstate != NULL)
149 *oldstate = ostate;
150 curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
151 break;
152 default:
153 ret = EINVAL;
154 }
155
156 _thread_critical_exit(curthread);
157 return (ret);
158}
159
160int
161_pthread_setcanceltype(int type, int *oldtype)
162{
163 int otype;
164
165 _thread_critical_enter(curthread);
166 otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
167 switch (type) {
168 case PTHREAD_CANCEL_ASYNCHRONOUS:
169 if (oldtype != NULL)
170 *oldtype = otype;
171 curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
172 testcancel();
173 break;
174 case PTHREAD_CANCEL_DEFERRED:
175 if (oldtype != NULL)
176 *oldtype = otype;
177 curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
178 break;
179 default:
180 return (EINVAL);
181 }
182
183 _thread_critical_exit(curthread);
184 return (0);
185}
186
187void
188_pthread_testcancel(void)
189{
190 _thread_critical_enter(curthread);
191 testcancel();
192 _thread_critical_exit(curthread);
193}
194
195static void
196testcancel()
197{
198 /*
199 * This pthread should already be locked by the caller.
200 */
201
202 if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
203 ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) &&
204 ((curthread->flags & PTHREAD_EXITING) == 0)) {
205 /*
206 * It is possible for this thread to be swapped out
207 * while performing cancellation; do not allow it
208 * to be cancelled again.
209 */
210 curthread->cancelflags &= ~PTHREAD_CANCELLING;
211 _thread_critical_exit(curthread);
212 _thread_exit_cleanup();
213 pthread_exit(PTHREAD_CANCELED);
214 PANIC("cancel");
215 }
216}
217
218void
219_thread_enter_cancellation_point(void)
220{
221 _thread_critical_enter(curthread);
222 testcancel();
223 curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
224 _thread_critical_exit(curthread);
225}
226
227void
228_thread_leave_cancellation_point(void)
229{
230 _thread_critical_enter(curthread);
231 curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
232 testcancel();
233 _thread_critical_exit(curthread);
234
235}