2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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 AUTHOR 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
32 * $Id: uthread_sig.c,v 1.17 1999/06/20 08:28:44 jb Exp $
40 #include "pthread_private.h"
42 /* Static variables: */
43 static spinlock_t signal_lock = _SPINLOCK_INITIALIZER;
44 unsigned int pending_sigs[NSIG];
45 unsigned int handled_sigs[NSIG];
46 int volatile check_pending = 0;
48 /* Initialize signal handling facility: */
50 _thread_sig_init(void)
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;
61 signal_lock.access_lock = 0;
65 _thread_sig_handler(int sig, int code, struct sigcontext * scp)
70 /* Check if an interval timer signal: */
71 if (sig == _SCHED_SIGNAL) {
72 if (_thread_kern_in_sched != 0) {
74 * The scheduler is already running; ignore this
79 * Check if the scheduler interrupt has come when
80 * the currently running thread has deferred thread
83 else if (_thread_run->sig_defer_count > 0)
84 _thread_run->yield_on_sig_undefer = 1;
88 * Schedule the next thread. This function is not
89 * expected to return because it will do a longjmp
92 _thread_kern_sched(scp);
95 * This point should not be reached, so abort the
98 PANIC("Returned to signal function from scheduler");
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.
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: */
112 * Write the signal number to the kernel pipe so that it will
113 * be ready to read when this signal handler returns.
115 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
117 /* Indicate that there are queued signals in the pipe. */
118 _sigq_check_reqd = 1;
121 if (_atomic_lock(&signal_lock.access_lock)) {
122 /* There is another signal handler running: */
123 pending_sigs[sig - 1]++;
127 /* It's safe to handle the signal now. */
128 _thread_sig_handle(sig, scp);
130 /* Reset the pending and handled count back to 0: */
131 pending_sigs[sig - 1] = 0;
132 handled_sigs[sig - 1] = 0;
134 signal_lock.access_lock = 0;
137 /* Enter a loop to process pending signals: */
138 while ((check_pending != 0) &&
139 (_atomic_lock(&signal_lock.access_lock) == 0)) {
141 for (i = 1; i < NSIG; i++) {
142 if (pending_sigs[i - 1] > handled_sigs[i - 1])
143 _thread_sig_handle(i, scp);
145 signal_lock.access_lock = 0;
151 _thread_sig_handle(int sig, struct sigcontext * scp)
154 pthread_t pthread, pthread_next;
156 /* Check if the signal requires a dump of thread information: */
158 /* Dump thread information to file: */
161 /* Check if an interval timer signal: */
162 else if (sig == _SCHED_SIGNAL) {
164 * This shouldn't ever occur (should this panic?).
167 /* Check if a child has terminated: */
168 if (sig == SIGCHLD) {
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.
174 for (i = 0; i < _thread_dtablesize; i++) {
175 /* Check if this file is used: */
176 if (_thread_fd_table[i] != NULL) {
178 * Set the file descriptor to
181 _thread_sys_fcntl(i, F_SETFL,
182 _thread_fd_table[i]->flags |
189 * POSIX says that pending SIGCONT signals are
190 * discarded when one of these signals occurs.
192 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
194 * Enter a loop to discard pending SIGCONT
197 TAILQ_FOREACH(pthread, &_thread_list, tle) {
198 sigdelset(&pthread->sigpend,SIGCONT);
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
209 for (pthread = TAILQ_FIRST(&_waitingq);
210 pthread != NULL; pthread = pthread_next) {
212 * Grab the next thread before possibly destroying
215 pthread_next = TAILQ_NEXT(pthread, pqe);
217 if ((pthread->state == PS_SIGWAIT) &&
218 sigismember(pthread->data.sigwait, sig)) {
219 /* Change the state of the thread to run: */
220 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
222 /* Return the signal number: */
223 pthread->signo = sig;
226 * Do not attempt to deliver this signal
233 /* Check if the signal is not being ignored: */
234 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
236 * Enter a loop to process each thread in the linked
239 TAILQ_FOREACH(pthread, &_thread_list, tle) {
240 pthread_t pthread_saved = _thread_run;
242 /* Current thread inside critical region? */
243 if (_thread_run->sig_defer_count > 0)
244 pthread->sig_defer_count++;
246 _thread_run = pthread;
247 _thread_signal(pthread,sig);
250 * Dispatch pending signals to the
254 _thread_run = pthread_saved;
256 /* Current thread inside critical region? */
257 if (_thread_run->sig_defer_count > 0)
258 pthread->sig_defer_count--;
262 /* Returns nothing. */
266 /* Perform thread specific actions in response to a signal: */
268 _thread_signal(pthread_t pthread, int sig)
271 * Flag the signal as pending. It will be dispatched later.
273 sigaddset(&pthread->sigpend,sig);
276 * Process according to thread state:
278 switch (pthread->state) {
280 * States which do not change when a signal is trapped:
294 /* Nothing to do here. */
298 * The wait state is a special case due to the handling of
303 * Check for signals other than the death of a child
307 /* Flag the operation as interrupted: */
308 pthread->interrupted = 1;
310 /* Change the state of the thread to run: */
311 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
313 /* Return the signal number: */
314 pthread->signo = sig;
318 * States that are interrupted by the occurrence of a signal
319 * other than the scheduling alarm:
326 if (sig != SIGCHLD ||
327 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
328 /* Flag the operation as interrupted: */
329 pthread->interrupted = 1;
331 if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
332 PTHREAD_WORKQ_REMOVE(pthread);
334 /* Change the state of the thread to run: */
335 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
337 /* Return the signal number: */
338 pthread->signo = sig;
344 * Only wake up the thread if the signal is unblocked
345 * and there is a handler installed for the signal.
347 if (!sigismember(&pthread->sigmask, sig) &&
348 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
349 /* Change the state of the thread to run: */
350 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
352 /* Return the signal number: */
353 pthread->signo = sig;
359 /* Dispatch pending signals to the running thread: */
366 * Check if there are pending signals for the running
367 * thread that aren't blocked:
369 if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0)
370 /* Look for all possible pending signals: */
371 for (i = 1; i < NSIG; i++)
373 * Check that a custom handler is installed
374 * and if the signal is not blocked:
376 if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
377 _thread_sigact[i - 1].sa_handler != SIG_IGN &&
378 sigismember(&_thread_run->sigpend,i) &&
379 !sigismember(&_thread_run->sigmask,i)) {
380 /* Clear the pending signal: */
381 sigdelset(&_thread_run->sigpend,i);
384 * Dispatch the signal via the custom signal
387 (*(_thread_sigact[i - 1].sa_handler))(i);