Deleted Added
full compact
thr_sig.c (44963) thr_sig.c (48046)
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

--- 15 unchanged lines hidden (view full) ---

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 *
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

--- 15 unchanged lines hidden (view full) ---

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 * $Id$
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
33 */
34#include <signal.h>
35#include <fcntl.h>
36#include <unistd.h>
37#include <errno.h>
38#ifdef _THREAD_SAFE
39#include <pthread.h>
40#include "pthread_private.h"
41
41/*
42 * State change macro for signal handler:
43 */
44#define PTHREAD_SIG_NEW_STATE(thrd, newstate) { \
45 if ((_thread_run->sched_defer_count == 0) && \
46 (_thread_kern_in_sched == 0)) { \
47 PTHREAD_NEW_STATE(thrd, newstate); \
48 } else { \
49 _waitingq_check_reqd = 1; \
50 PTHREAD_SET_STATE(thrd, newstate); \
51 } \
52}
53
54/* Static variables: */
42/* Static variables: */
55static int volatile yield_on_unlock_thread = 0;
56static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER;
43static spinlock_t signal_lock = _SPINLOCK_INITIALIZER;
44unsigned int pending_sigs[NSIG];
45unsigned int handled_sigs[NSIG];
46int volatile check_pending = 0;
57
47
58/* Lock the thread list: */
48/* Initialize signal handling facility: */
59void
49void
60_lock_thread_list()
50_thread_sig_init(void)
61{
51{
62 /* Lock the thread list: */
63 _SPINLOCK(&thread_link_list_lock);
64}
52 int i;
65
53
66/* Lock the thread list: */
67void
68_unlock_thread_list()
69{
70 /* Unlock the thread list: */
71 _SPINUNLOCK(&thread_link_list_lock);
72
73 /*
74 * Check if a scheduler interrupt occurred while the thread
75 * list was locked:
76 */
77 if (yield_on_unlock_thread) {
78 /* Reset the interrupt flag: */
79 yield_on_unlock_thread = 0;
80
81 /* This thread has overstayed it's welcome: */
82 sched_yield();
54 /* Clear pending and handled signal counts: */
55 for (i = 1; i < NSIG; i++) {
56 pending_sigs[i - 1] = 0;
57 handled_sigs[i - 1] = 0;
83 }
58 }
59
60 /* Clear the lock: */
61 signal_lock.access_lock = 0;
84}
85
86void
87_thread_sig_handler(int sig, int code, struct sigcontext * scp)
88{
62}
63
64void
65_thread_sig_handler(int sig, int code, struct sigcontext * scp)
66{
89 char c;
90 int i;
91 pthread_t pthread;
67 char c;
68 int i;
92
69
93 /*
94 * Check if the pthread kernel has unblocked signals (or is about to)
95 * and was on its way into a _select when the current
96 * signal interrupted it:
97 */
98 if (_thread_kern_in_select) {
99 /* Cast the signal number to a character variable: */
100 c = sig;
101
102 /*
103 * Write the signal number to the kernel pipe so that it will
104 * be ready to read when this signal handler returns. This
105 * means that the _select call will complete
106 * immediately.
107 */
108 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
109 }
110 /* Check if the signal requires a dump of thread information: */
111 if (sig == SIGINFO)
112 /* Dump thread information to file: */
113 _thread_dump_info();
114
115 /* Check if an interval timer signal: */
70 /* Check if an interval timer signal: */
116 else if (sig == _SCHED_SIGNAL) {
117 /* Check if the scheduler interrupt has come at an
118 * unfortunate time which one of the threads is
119 * modifying the thread list:
120 */
121 if (thread_link_list_lock.access_lock)
71 if (sig == _SCHED_SIGNAL) {
72 if (_thread_kern_in_sched != 0) {
122 /*
73 /*
123 * Set a flag so that the thread that has
124 * the lock yields when it unlocks the
125 * thread list:
74 * The scheduler is already running; ignore this
75 * signal.
126 */
76 */
127 yield_on_unlock_thread = 1;
128
77 }
129 /*
130 * Check if the scheduler interrupt has come when
131 * the currently running thread has deferred thread
78 /*
79 * Check if the scheduler interrupt has come when
80 * the currently running thread has deferred thread
132 * scheduling.
81 * signals.
133 */
82 */
134 else if (_thread_run->sched_defer_count)
135 _thread_run->yield_on_sched_undefer = 1;
83 else if (_thread_run->sig_defer_count > 0)
84 _thread_run->yield_on_sig_undefer = 1;
136
85
137 /*
138 * Check if the kernel has not been interrupted while
139 * executing scheduler code:
140 */
141 else if (!_thread_kern_in_sched) {
86 else {
142 /*
143 * Schedule the next thread. This function is not
144 * expected to return because it will do a longjmp
145 * instead.
146 */
147 _thread_kern_sched(scp);
148
149 /*
150 * This point should not be reached, so abort the
151 * process:
152 */
153 PANIC("Returned to signal function from scheduler");
154 }
87 /*
88 * Schedule the next thread. This function is not
89 * expected to return because it will do a longjmp
90 * instead.
91 */
92 _thread_kern_sched(scp);
93
94 /*
95 * This point should not be reached, so abort the
96 * process:
97 */
98 PANIC("Returned to signal function from scheduler");
99 }
100 }
101 /*
102 * Check if the kernel has been interrupted while the scheduler
103 * is accessing the scheduling queues or if there is a currently
104 * running thread that has deferred signals.
105 */
106 else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) &&
107 (_thread_run->sig_defer_count > 0))) {
108 /* Cast the signal number to a character variable: */
109 c = sig;
110
111 /*
112 * Write the signal number to the kernel pipe so that it will
113 * be ready to read when this signal handler returns.
114 */
115 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
116
117 /* Indicate that there are queued signals in the pipe. */
118 _sigq_check_reqd = 1;
119 }
120 else {
121 if (_atomic_lock(&signal_lock.access_lock)) {
122 /* There is another signal handler running: */
123 pending_sigs[sig - 1]++;
124 check_pending = 1;
125 }
126 else {
127 /* It's safe to handle the signal now. */
128 _thread_sig_handle(sig, scp);
129
130 /* Reset the pending and handled count back to 0: */
131 pending_sigs[sig - 1] = 0;
132 handled_sigs[sig - 1] = 0;
133
134 signal_lock.access_lock = 0;
135 }
136
137 /* Enter a loop to process pending signals: */
138 while ((check_pending != 0) &&
139 (_atomic_lock(&signal_lock.access_lock) == 0)) {
140 check_pending = 0;
141 for (i = 1; i < NSIG; i++) {
142 if (pending_sigs[i - 1] > handled_sigs[i - 1])
143 _thread_sig_handle(i, scp);
144 }
145 signal_lock.access_lock = 0;
146 }
147 }
148}
149
150void
151_thread_sig_handle(int sig, struct sigcontext * scp)
152{
153 int i;
154 pthread_t pthread, pthread_next;
155
156 /* Check if the signal requires a dump of thread information: */
157 if (sig == SIGINFO)
158 /* Dump thread information to file: */
159 _thread_dump_info();
160
161 /* Check if an interval timer signal: */
162 else if (sig == _SCHED_SIGNAL) {
163 /*
164 * This shouldn't ever occur (should this panic?).
165 */
155 } else {
156 /* Check if a child has terminated: */
157 if (sig == SIGCHLD) {
158 /*
159 * Go through the file list and set all files
160 * to non-blocking again in case the child
161 * set some of them to block. Sigh.
162 */

--- 15 unchanged lines hidden (view full) ---

178 * POSIX says that pending SIGCONT signals are
179 * discarded when one of these signals occurs.
180 */
181 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
182 /*
183 * Enter a loop to discard pending SIGCONT
184 * signals:
185 */
166 } else {
167 /* Check if a child has terminated: */
168 if (sig == SIGCHLD) {
169 /*
170 * Go through the file list and set all files
171 * to non-blocking again in case the child
172 * set some of them to block. Sigh.
173 */

--- 15 unchanged lines hidden (view full) ---

189 * POSIX says that pending SIGCONT signals are
190 * discarded when one of these signals occurs.
191 */
192 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
193 /*
194 * Enter a loop to discard pending SIGCONT
195 * signals:
196 */
186 for (pthread = _thread_link_list;
187 pthread != NULL;
188 pthread = pthread->nxt)
197 TAILQ_FOREACH(pthread, &_thread_list, tle) {
189 sigdelset(&pthread->sigpend,SIGCONT);
198 sigdelset(&pthread->sigpend,SIGCONT);
199 }
190 }
191
192 /*
193 * Enter a loop to process each thread in the waiting
194 * list that is sigwait-ing on a signal. Since POSIX
195 * doesn't specify which thread will get the signal
196 * if there are multiple waiters, we'll give it to the
197 * first one we find.
198 */
200 }
201
202 /*
203 * Enter a loop to process each thread in the waiting
204 * list that is sigwait-ing on a signal. Since POSIX
205 * doesn't specify which thread will get the signal
206 * if there are multiple waiters, we'll give it to the
207 * first one we find.
208 */
199 TAILQ_FOREACH(pthread, &_waitingq, pqe) {
209 for (pthread = TAILQ_FIRST(&_waitingq);
210 pthread != NULL; pthread = pthread_next) {
211 /*
212 * Grab the next thread before possibly destroying
213 * the link entry.
214 */
215 pthread_next = TAILQ_NEXT(pthread, pqe);
216
200 if ((pthread->state == PS_SIGWAIT) &&
201 sigismember(pthread->data.sigwait, sig)) {
202 /* Change the state of the thread to run: */
217 if ((pthread->state == PS_SIGWAIT) &&
218 sigismember(pthread->data.sigwait, sig)) {
219 /* Change the state of the thread to run: */
203 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
220 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
204
205 /* Return the signal number: */
206 pthread->signo = sig;
207
208 /*
209 * Do not attempt to deliver this signal
210 * to other threads.
211 */
212 return;
213 }
214 }
215
216 /* Check if the signal is not being ignored: */
217 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
218 /*
219 * Enter a loop to process each thread in the linked
220 * list:
221 */
221
222 /* Return the signal number: */
223 pthread->signo = sig;
224
225 /*
226 * Do not attempt to deliver this signal
227 * to other threads.
228 */
229 return;
230 }
231 }
232
233 /* Check if the signal is not being ignored: */
234 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
235 /*
236 * Enter a loop to process each thread in the linked
237 * list:
238 */
222 for (pthread = _thread_link_list; pthread != NULL;
223 pthread = pthread->nxt) {
239 TAILQ_FOREACH(pthread, &_thread_list, tle) {
224 pthread_t pthread_saved = _thread_run;
225
240 pthread_t pthread_saved = _thread_run;
241
242 /* Current thread inside critical region? */
243 if (_thread_run->sig_defer_count > 0)
244 pthread->sig_defer_count++;
245
226 _thread_run = pthread;
227 _thread_signal(pthread,sig);
228
229 /*
230 * Dispatch pending signals to the
231 * running thread:
232 */
233 _dispatch_signals();
234 _thread_run = pthread_saved;
246 _thread_run = pthread;
247 _thread_signal(pthread,sig);
248
249 /*
250 * Dispatch pending signals to the
251 * running thread:
252 */
253 _dispatch_signals();
254 _thread_run = pthread_saved;
255
256 /* Current thread inside critical region? */
257 if (_thread_run->sig_defer_count > 0)
258 pthread->sig_defer_count--;
235 }
236 }
237
238 /* Returns nothing. */
239 return;
240}
241
242/* Perform thread specific actions in response to a signal: */

--- 36 unchanged lines hidden (view full) ---

279 * Check for signals other than the death of a child
280 * process:
281 */
282 if (sig != SIGCHLD)
283 /* Flag the operation as interrupted: */
284 pthread->interrupted = 1;
285
286 /* Change the state of the thread to run: */
259 }
260 }
261
262 /* Returns nothing. */
263 return;
264}
265
266/* Perform thread specific actions in response to a signal: */

--- 36 unchanged lines hidden (view full) ---

303 * Check for signals other than the death of a child
304 * process:
305 */
306 if (sig != SIGCHLD)
307 /* Flag the operation as interrupted: */
308 pthread->interrupted = 1;
309
310 /* Change the state of the thread to run: */
287 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
311 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
288
289 /* Return the signal number: */
290 pthread->signo = sig;
291 break;
292
293 /*
294 * States that are interrupted by the occurrence of a signal
295 * other than the scheduling alarm:
296 */
297 case PS_FDR_WAIT:
298 case PS_FDW_WAIT:
312
313 /* Return the signal number: */
314 pthread->signo = sig;
315 break;
316
317 /*
318 * States that are interrupted by the occurrence of a signal
319 * other than the scheduling alarm:
320 */
321 case PS_FDR_WAIT:
322 case PS_FDW_WAIT:
323 case PS_POLL_WAIT:
299 case PS_SLEEP_WAIT:
300 case PS_SELECT_WAIT:
301 if (sig != SIGCHLD ||
302 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
303 /* Flag the operation as interrupted: */
304 pthread->interrupted = 1;
305
324 case PS_SLEEP_WAIT:
325 case PS_SELECT_WAIT:
326 if (sig != SIGCHLD ||
327 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
328 /* Flag the operation as interrupted: */
329 pthread->interrupted = 1;
330
331 if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
332 PTHREAD_WORKQ_REMOVE(pthread);
333
306 /* Change the state of the thread to run: */
334 /* Change the state of the thread to run: */
307 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
335 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
308
309 /* Return the signal number: */
310 pthread->signo = sig;
311 }
312 break;
313
314 case PS_SIGSUSPEND:
315 /*
316 * Only wake up the thread if the signal is unblocked
317 * and there is a handler installed for the signal.
318 */
319 if (!sigismember(&pthread->sigmask, sig) &&
320 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
321 /* Change the state of the thread to run: */
336
337 /* Return the signal number: */
338 pthread->signo = sig;
339 }
340 break;
341
342 case PS_SIGSUSPEND:
343 /*
344 * Only wake up the thread if the signal is unblocked
345 * and there is a handler installed for the signal.
346 */
347 if (!sigismember(&pthread->sigmask, sig) &&
348 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
349 /* Change the state of the thread to run: */
322 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
350 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
323
324 /* Return the signal number: */
325 pthread->signo = sig;
326 }
327 break;
328 }
329}
330

--- 32 unchanged lines hidden ---
351
352 /* Return the signal number: */
353 pthread->signo = sig;
354 }
355 break;
356 }
357}
358

--- 32 unchanged lines hidden ---