Deleted Added
full compact
thr_sig.c (37045) thr_sig.c (38539)
1/*
2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33#include <signal.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <errno.h>
37#ifdef _THREAD_SAFE
38#include <pthread.h>
39#include "pthread_private.h"
40
41/* Static variables: */
42static int volatile yield_on_unlock_dead = 0;
43static int volatile yield_on_unlock_thread = 0;
44static spinlock_t thread_dead_lock = _SPINLOCK_INITIALIZER;
45static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER;
46
47/* Lock the thread list: */
48void
49_lock_thread_list()
50{
51 /* Lock the thread list: */
52 _SPINLOCK(&thread_link_list_lock);
53}
54
55/* Lock the dead thread list: */
56void
57_lock_dead_thread_list()
58{
59 /* Lock the dead thread list: */
60 _SPINLOCK(&thread_dead_lock);
61}
62
63/* Lock the thread list: */
64void
65_unlock_thread_list()
66{
67 /* Unlock the thread list: */
68 _SPINUNLOCK(&thread_link_list_lock);
69
70 /*
71 * Check if a scheduler interrupt occurred while the thread
72 * list was locked:
73 */
74 if (yield_on_unlock_thread) {
75 /* Reset the interrupt flag: */
76 yield_on_unlock_thread = 0;
77
78 /* This thread has overstayed it's welcome: */
79 sched_yield();
80 }
81}
82
83/* Lock the dead thread list: */
84void
85_unlock_dead_thread_list()
86{
87 /* Unlock the dead thread list: */
88 _SPINUNLOCK(&thread_dead_lock);
89
90 /*
91 * Check if a scheduler interrupt occurred while the dead
92 * thread list was locked:
93 */
94 if (yield_on_unlock_dead) {
95 /* Reset the interrupt flag: */
96 yield_on_unlock_dead = 0;
97
98 /* This thread has overstayed it's welcome: */
99 sched_yield();
100 }
101}
102
103void
104_thread_sig_handler(int sig, int code, struct sigcontext * scp)
105{
106 char c;
107 int i;
108 int dispatch = 0;
109 pthread_t pthread;
110
111 /*
112 * Check if the pthread kernel has unblocked signals (or is about to)
113 * and was on its way into a _select when the current
114 * signal interrupted it:
115 */
116 if (_thread_kern_in_select) {
117 /* Cast the signal number to a character variable: */
118 c = sig;
119
120 /*
121 * Write the signal number to the kernel pipe so that it will
122 * be ready to read when this signal handler returns. This
123 * means that the _select call will complete
124 * immediately.
125 */
126 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
127 }
128
129 /* Check if the signal requires a dump of thread information: */
130 if (sig == SIGINFO)
131 /* Dump thread information to file: */
132 _thread_dump_info();
133
134 /* Check if an interval timer signal: */
135 else if (sig == SIGVTALRM) {
136 /* Check if the scheduler interrupt has come at an
137 * unfortunate time which one of the threads is
138 * modifying the thread list:
139 */
140 if (thread_link_list_lock.access_lock)
141 /*
142 * Set a flag so that the thread that has
143 * the lock yields when it unlocks the
144 * thread list:
145 */
146 yield_on_unlock_thread = 1;
147
148 /* Check if the scheduler interrupt has come at an
149 * unfortunate time which one of the threads is
150 * modifying the dead thread list:
151 */
152 if (thread_dead_lock.access_lock)
153 /*
154 * Set a flag so that the thread that has
155 * the lock yields when it unlocks the
156 * dead thread list:
157 */
158 yield_on_unlock_dead = 1;
159
160 /*
161 * Check if the kernel has not been interrupted while
162 * executing scheduler code:
163 */
164 else if (!_thread_kern_in_sched) {
165 /*
166 * Schedule the next thread. This function is not
167 * expected to return because it will do a longjmp
168 * instead.
169 */
170 _thread_kern_sched(scp);
171
172 /*
173 * This point should not be reached, so abort the
174 * process:
175 */
176 PANIC("Returned to signal function from scheduler");
177 }
178 } else {
179 /* Check if a child has terminated: */
180 if (sig == SIGCHLD) {
181 /*
182 * Go through the file list and set all files
183 * to non-blocking again in case the child
184 * set some of them to block. Sigh.
185 */
186 for (i = 0; i < _thread_dtablesize; i++) {
187 /* Check if this file is used: */
188 if (_thread_fd_table[i] != NULL) {
189 /*
190 * Set the file descriptor to
191 * non-blocking:
192 */
193 _thread_sys_fcntl(i, F_SETFL,
194 _thread_fd_table[i]->flags |
195 O_NONBLOCK);
196 }
197 }
198 }
199
200 /*
201 * POSIX says that pending SIGCONT signals are
202 * discarded when one of there signals occurs.
203 */
204 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
205 /*
206 * Enter a loop to discard pending SIGCONT
207 * signals:
208 */
209 for (pthread = _thread_link_list;
210 pthread != NULL;
211 pthread = pthread->nxt)
212 sigdelset(&pthread->sigpend,SIGCONT);
213 }
214
1/*
2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33#include <signal.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <errno.h>
37#ifdef _THREAD_SAFE
38#include <pthread.h>
39#include "pthread_private.h"
40
41/* Static variables: */
42static int volatile yield_on_unlock_dead = 0;
43static int volatile yield_on_unlock_thread = 0;
44static spinlock_t thread_dead_lock = _SPINLOCK_INITIALIZER;
45static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER;
46
47/* Lock the thread list: */
48void
49_lock_thread_list()
50{
51 /* Lock the thread list: */
52 _SPINLOCK(&thread_link_list_lock);
53}
54
55/* Lock the dead thread list: */
56void
57_lock_dead_thread_list()
58{
59 /* Lock the dead thread list: */
60 _SPINLOCK(&thread_dead_lock);
61}
62
63/* Lock the thread list: */
64void
65_unlock_thread_list()
66{
67 /* Unlock the thread list: */
68 _SPINUNLOCK(&thread_link_list_lock);
69
70 /*
71 * Check if a scheduler interrupt occurred while the thread
72 * list was locked:
73 */
74 if (yield_on_unlock_thread) {
75 /* Reset the interrupt flag: */
76 yield_on_unlock_thread = 0;
77
78 /* This thread has overstayed it's welcome: */
79 sched_yield();
80 }
81}
82
83/* Lock the dead thread list: */
84void
85_unlock_dead_thread_list()
86{
87 /* Unlock the dead thread list: */
88 _SPINUNLOCK(&thread_dead_lock);
89
90 /*
91 * Check if a scheduler interrupt occurred while the dead
92 * thread list was locked:
93 */
94 if (yield_on_unlock_dead) {
95 /* Reset the interrupt flag: */
96 yield_on_unlock_dead = 0;
97
98 /* This thread has overstayed it's welcome: */
99 sched_yield();
100 }
101}
102
103void
104_thread_sig_handler(int sig, int code, struct sigcontext * scp)
105{
106 char c;
107 int i;
108 int dispatch = 0;
109 pthread_t pthread;
110
111 /*
112 * Check if the pthread kernel has unblocked signals (or is about to)
113 * and was on its way into a _select when the current
114 * signal interrupted it:
115 */
116 if (_thread_kern_in_select) {
117 /* Cast the signal number to a character variable: */
118 c = sig;
119
120 /*
121 * Write the signal number to the kernel pipe so that it will
122 * be ready to read when this signal handler returns. This
123 * means that the _select call will complete
124 * immediately.
125 */
126 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
127 }
128
129 /* Check if the signal requires a dump of thread information: */
130 if (sig == SIGINFO)
131 /* Dump thread information to file: */
132 _thread_dump_info();
133
134 /* Check if an interval timer signal: */
135 else if (sig == SIGVTALRM) {
136 /* Check if the scheduler interrupt has come at an
137 * unfortunate time which one of the threads is
138 * modifying the thread list:
139 */
140 if (thread_link_list_lock.access_lock)
141 /*
142 * Set a flag so that the thread that has
143 * the lock yields when it unlocks the
144 * thread list:
145 */
146 yield_on_unlock_thread = 1;
147
148 /* Check if the scheduler interrupt has come at an
149 * unfortunate time which one of the threads is
150 * modifying the dead thread list:
151 */
152 if (thread_dead_lock.access_lock)
153 /*
154 * Set a flag so that the thread that has
155 * the lock yields when it unlocks the
156 * dead thread list:
157 */
158 yield_on_unlock_dead = 1;
159
160 /*
161 * Check if the kernel has not been interrupted while
162 * executing scheduler code:
163 */
164 else if (!_thread_kern_in_sched) {
165 /*
166 * Schedule the next thread. This function is not
167 * expected to return because it will do a longjmp
168 * instead.
169 */
170 _thread_kern_sched(scp);
171
172 /*
173 * This point should not be reached, so abort the
174 * process:
175 */
176 PANIC("Returned to signal function from scheduler");
177 }
178 } else {
179 /* Check if a child has terminated: */
180 if (sig == SIGCHLD) {
181 /*
182 * Go through the file list and set all files
183 * to non-blocking again in case the child
184 * set some of them to block. Sigh.
185 */
186 for (i = 0; i < _thread_dtablesize; i++) {
187 /* Check if this file is used: */
188 if (_thread_fd_table[i] != NULL) {
189 /*
190 * Set the file descriptor to
191 * non-blocking:
192 */
193 _thread_sys_fcntl(i, F_SETFL,
194 _thread_fd_table[i]->flags |
195 O_NONBLOCK);
196 }
197 }
198 }
199
200 /*
201 * POSIX says that pending SIGCONT signals are
202 * discarded when one of there signals occurs.
203 */
204 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
205 /*
206 * Enter a loop to discard pending SIGCONT
207 * signals:
208 */
209 for (pthread = _thread_link_list;
210 pthread != NULL;
211 pthread = pthread->nxt)
212 sigdelset(&pthread->sigpend,SIGCONT);
213 }
214
215 /*
216 * Enter a loop to process each thread in the linked
217 * list that is sigwait-ing on a signal. Since POSIX
218 * doesn't specify which thread will get the signal
219 * if there are multiple waiters, we'll give it to the
220 * first one we find.
221 */
222 for (pthread = _thread_link_list; pthread != NULL;
223 pthread = pthread->nxt) {
224 if ((pthread->state == PS_SIGWAIT) &&
225 sigismember(&pthread->sigmask, sig)) {
226 /* Change the state of the thread to run: */
227 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
228
229 /* Return the signal number: */
230 pthread->signo = sig;
231
232 /*
233 * Do not attempt to deliver this signal
234 * to other threads.
235 */
236 return;
237 }
238 }
239
215 /* Check if the signal is not being ignored: */
216 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
217 /*
218 * Enter a loop to process each thread in the linked
219 * list:
220 */
221 for (pthread = _thread_link_list; pthread != NULL;
222 pthread = pthread->nxt)
223 _thread_signal(pthread,sig);
224
225 /* Dispatch pending signals to the running thread: */
226 _dispatch_signals();
227 }
228
229 /* Returns nothing. */
230 return;
231}
232
233/* Perform thread specific actions in response to a signal: */
234void
235_thread_signal(pthread_t pthread, int sig)
236{
237 pthread_t saved;
238 struct sigaction act;
239
240 /*
241 * Flag the signal as pending. It will be dispatched later.
242 */
243 sigaddset(&pthread->sigpend,sig);
244
245 /*
246 * Process according to thread state:
247 */
248 switch (pthread->state) {
249 /*
250 * States which do not change when a signal is trapped:
251 */
252 case PS_COND_WAIT:
253 case PS_DEAD:
254 case PS_FDLR_WAIT:
255 case PS_FDLW_WAIT:
256 case PS_FILE_WAIT:
257 case PS_JOIN:
258 case PS_MUTEX_WAIT:
259 case PS_RUNNING:
260 case PS_STATE_MAX:
261 case PS_SIGTHREAD:
240 /* Check if the signal is not being ignored: */
241 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
242 /*
243 * Enter a loop to process each thread in the linked
244 * list:
245 */
246 for (pthread = _thread_link_list; pthread != NULL;
247 pthread = pthread->nxt)
248 _thread_signal(pthread,sig);
249
250 /* Dispatch pending signals to the running thread: */
251 _dispatch_signals();
252 }
253
254 /* Returns nothing. */
255 return;
256}
257
258/* Perform thread specific actions in response to a signal: */
259void
260_thread_signal(pthread_t pthread, int sig)
261{
262 pthread_t saved;
263 struct sigaction act;
264
265 /*
266 * Flag the signal as pending. It will be dispatched later.
267 */
268 sigaddset(&pthread->sigpend,sig);
269
270 /*
271 * Process according to thread state:
272 */
273 switch (pthread->state) {
274 /*
275 * States which do not change when a signal is trapped:
276 */
277 case PS_COND_WAIT:
278 case PS_DEAD:
279 case PS_FDLR_WAIT:
280 case PS_FDLW_WAIT:
281 case PS_FILE_WAIT:
282 case PS_JOIN:
283 case PS_MUTEX_WAIT:
284 case PS_RUNNING:
285 case PS_STATE_MAX:
286 case PS_SIGTHREAD:
287 case PS_SIGWAIT:
262 case PS_SUSPENDED:
263 /* Nothing to do here. */
264 break;
265
266 /*
267 * The wait state is a special case due to the handling of
268 * SIGCHLD signals.
269 */
270 case PS_WAIT_WAIT:
271 /*
272 * Check for signals other than the death of a child
273 * process:
274 */
275 if (sig != SIGCHLD)
276 /* Flag the operation as interrupted: */
277 pthread->interrupted = 1;
278
279 /* Change the state of the thread to run: */
280 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
281
282 /* Return the signal number: */
283 pthread->signo = sig;
284 break;
285
286 /*
287 * States that are interrupted by the occurrence of a signal
288 * other than the scheduling alarm:
289 */
290 case PS_FDR_WAIT:
291 case PS_FDW_WAIT:
292 case PS_SLEEP_WAIT:
288 case PS_SUSPENDED:
289 /* Nothing to do here. */
290 break;
291
292 /*
293 * The wait state is a special case due to the handling of
294 * SIGCHLD signals.
295 */
296 case PS_WAIT_WAIT:
297 /*
298 * Check for signals other than the death of a child
299 * process:
300 */
301 if (sig != SIGCHLD)
302 /* Flag the operation as interrupted: */
303 pthread->interrupted = 1;
304
305 /* Change the state of the thread to run: */
306 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
307
308 /* Return the signal number: */
309 pthread->signo = sig;
310 break;
311
312 /*
313 * States that are interrupted by the occurrence of a signal
314 * other than the scheduling alarm:
315 */
316 case PS_FDR_WAIT:
317 case PS_FDW_WAIT:
318 case PS_SLEEP_WAIT:
293 case PS_SIGWAIT:
294 case PS_SELECT_WAIT:
295 if (sig != SIGCHLD ||
296 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
297 /* Flag the operation as interrupted: */
298 pthread->interrupted = 1;
299
300 /* Change the state of the thread to run: */
301 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
302
303 /* Return the signal number: */
304 pthread->signo = sig;
305 }
306 break;
307 }
308}
309
310/* Dispatch pending signals to the running thread: */
311void
312_dispatch_signals()
313{
314 int i;
315
316 /*
317 * Check if there are pending signals for the running
318 * thread that aren't blocked:
319 */
320 if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0)
321 /* Look for all possible pending signals: */
322 for (i = 1; i < NSIG; i++)
323 /*
324 * Check that a custom handler is installed
325 * and if the signal is not blocked:
326 */
327 if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
328 _thread_sigact[i - 1].sa_handler != SIG_IGN &&
329 sigismember(&_thread_run->sigpend,i) &&
330 !sigismember(&_thread_run->sigmask,i)) {
331 /* Clear the pending signal: */
332 sigdelset(&_thread_run->sigpend,i);
333
334 /*
335 * Dispatch the signal via the custom signal
336 * handler:
337 */
338 (*(_thread_sigact[i - 1].sa_handler))(i);
339 }
340}
341#endif
319 case PS_SELECT_WAIT:
320 if (sig != SIGCHLD ||
321 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
322 /* Flag the operation as interrupted: */
323 pthread->interrupted = 1;
324
325 /* Change the state of the thread to run: */
326 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
327
328 /* Return the signal number: */
329 pthread->signo = sig;
330 }
331 break;
332 }
333}
334
335/* Dispatch pending signals to the running thread: */
336void
337_dispatch_signals()
338{
339 int i;
340
341 /*
342 * Check if there are pending signals for the running
343 * thread that aren't blocked:
344 */
345 if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0)
346 /* Look for all possible pending signals: */
347 for (i = 1; i < NSIG; i++)
348 /*
349 * Check that a custom handler is installed
350 * and if the signal is not blocked:
351 */
352 if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
353 _thread_sigact[i - 1].sa_handler != SIG_IGN &&
354 sigismember(&_thread_run->sigpend,i) &&
355 !sigismember(&_thread_run->sigmask,i)) {
356 /* Clear the pending signal: */
357 sigdelset(&_thread_run->sigpend,i);
358
359 /*
360 * Dispatch the signal via the custom signal
361 * handler:
362 */
363 (*(_thread_sigact[i - 1].sa_handler))(i);
364 }
365}
366#endif