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 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
39 #include "pthread_private.h"
42 * State change macro for signal handler:
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); \
49 _waitingq_check_reqd = 1; \
50 PTHREAD_SET_STATE(thrd, newstate); \
54 /* Static variables: */
55 static int volatile yield_on_unlock_thread = 0;
56 static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER;
58 /* Lock the thread list: */
62 /* Lock the thread list: */
63 _SPINLOCK(&thread_link_list_lock);
66 /* Lock the thread list: */
70 /* Unlock the thread list: */
71 _SPINUNLOCK(&thread_link_list_lock);
74 * Check if a scheduler interrupt occurred while the thread
77 if (yield_on_unlock_thread) {
78 /* Reset the interrupt flag: */
79 yield_on_unlock_thread = 0;
81 /* This thread has overstayed it's welcome: */
87 _thread_sig_handler(int sig, int code, struct sigcontext * scp)
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:
98 if (_thread_kern_in_select) {
99 /* Cast the signal number to a character variable: */
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
108 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
110 /* Check if the signal requires a dump of thread information: */
112 /* Dump thread information to file: */
115 /* 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:
121 if (thread_link_list_lock.access_lock)
123 * Set a flag so that the thread that has
124 * the lock yields when it unlocks the
127 yield_on_unlock_thread = 1;
130 * Check if the scheduler interrupt has come when
131 * the currently running thread has deferred thread
134 else if (_thread_run->sched_defer_count)
135 _thread_run->yield_on_sched_undefer = 1;
138 * Check if the kernel has not been interrupted while
139 * executing scheduler code:
141 else if (!_thread_kern_in_sched) {
143 * Schedule the next thread. This function is not
144 * expected to return because it will do a longjmp
147 _thread_kern_sched(scp);
150 * This point should not be reached, so abort the
153 PANIC("Returned to signal function from scheduler");
156 /* Check if a child has terminated: */
157 if (sig == SIGCHLD) {
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.
163 for (i = 0; i < _thread_dtablesize; i++) {
164 /* Check if this file is used: */
165 if (_thread_fd_table[i] != NULL) {
167 * Set the file descriptor to
170 _thread_sys_fcntl(i, F_SETFL,
171 _thread_fd_table[i]->flags |
178 * POSIX says that pending SIGCONT signals are
179 * discarded when one of these signals occurs.
181 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
183 * Enter a loop to discard pending SIGCONT
186 for (pthread = _thread_link_list;
188 pthread = pthread->nxt)
189 sigdelset(&pthread->sigpend,SIGCONT);
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
199 TAILQ_FOREACH(pthread, &_waitingq, pqe) {
200 if ((pthread->state == PS_SIGWAIT) &&
201 sigismember(pthread->data.sigwait, sig)) {
202 /* Change the state of the thread to run: */
203 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
205 /* Return the signal number: */
206 pthread->signo = sig;
209 * Do not attempt to deliver this signal
216 /* Check if the signal is not being ignored: */
217 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
219 * Enter a loop to process each thread in the linked
222 for (pthread = _thread_link_list; pthread != NULL;
223 pthread = pthread->nxt) {
224 pthread_t pthread_saved = _thread_run;
226 _thread_run = pthread;
227 _thread_signal(pthread,sig);
230 * Dispatch pending signals to the
234 _thread_run = pthread_saved;
238 /* Returns nothing. */
242 /* Perform thread specific actions in response to a signal: */
244 _thread_signal(pthread_t pthread, int sig)
247 * Flag the signal as pending. It will be dispatched later.
249 sigaddset(&pthread->sigpend,sig);
252 * Process according to thread state:
254 switch (pthread->state) {
256 * States which do not change when a signal is trapped:
270 /* Nothing to do here. */
274 * The wait state is a special case due to the handling of
279 * Check for signals other than the death of a child
283 /* Flag the operation as interrupted: */
284 pthread->interrupted = 1;
286 /* Change the state of the thread to run: */
287 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
289 /* Return the signal number: */
290 pthread->signo = sig;
294 * States that are interrupted by the occurrence of a signal
295 * other than the scheduling alarm:
301 if (sig != SIGCHLD ||
302 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
303 /* Flag the operation as interrupted: */
304 pthread->interrupted = 1;
306 /* Change the state of the thread to run: */
307 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
309 /* Return the signal number: */
310 pthread->signo = sig;
316 * Only wake up the thread if the signal is unblocked
317 * and there is a handler installed for the signal.
319 if (!sigismember(&pthread->sigmask, sig) &&
320 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
321 /* Change the state of the thread to run: */
322 PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
324 /* Return the signal number: */
325 pthread->signo = sig;
331 /* Dispatch pending signals to the running thread: */
338 * Check if there are pending signals for the running
339 * thread that aren't blocked:
341 if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0)
342 /* Look for all possible pending signals: */
343 for (i = 1; i < NSIG; i++)
345 * Check that a custom handler is installed
346 * and if the signal is not blocked:
348 if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
349 _thread_sigact[i - 1].sa_handler != SIG_IGN &&
350 sigismember(&_thread_run->sigpend,i) &&
351 !sigismember(&_thread_run->sigmask,i)) {
352 /* Clear the pending signal: */
353 sigdelset(&_thread_run->sigpend,i);
356 * Dispatch the signal via the custom signal
359 (*(_thread_sigact[i - 1].sa_handler))(i);