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"
41 /* Static variables: */
42 static int volatile yield_on_unlock_thread = 0;
43 static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER;
45 /* Lock the thread list: */
49 /* Lock the thread list: */
50 _SPINLOCK(&thread_link_list_lock);
53 /* Lock the thread list: */
57 /* Unlock the thread list: */
58 _SPINUNLOCK(&thread_link_list_lock);
61 * Check if a scheduler interrupt occurred while the thread
64 if (yield_on_unlock_thread) {
65 /* Reset the interrupt flag: */
66 yield_on_unlock_thread = 0;
68 /* This thread has overstayed it's welcome: */
74 _thread_sig_handler(int sig, int code, struct sigcontext * scp)
81 * Check if the pthread kernel has unblocked signals (or is about to)
82 * and was on its way into a _select when the current
83 * signal interrupted it:
85 if (_thread_kern_in_select) {
86 /* Cast the signal number to a character variable: */
90 * Write the signal number to the kernel pipe so that it will
91 * be ready to read when this signal handler returns. This
92 * means that the _select call will complete
95 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
98 /* Check if the signal requires a dump of thread information: */
100 /* Dump thread information to file: */
103 /* Check if an interval timer signal: */
104 else if (sig == SIGVTALRM) {
105 /* Check if the scheduler interrupt has come at an
106 * unfortunate time which one of the threads is
107 * modifying the thread list:
109 if (thread_link_list_lock.access_lock)
111 * Set a flag so that the thread that has
112 * the lock yields when it unlocks the
115 yield_on_unlock_thread = 1;
118 * Check if the kernel has not been interrupted while
119 * executing scheduler code:
121 else if (!_thread_kern_in_sched) {
123 * Schedule the next thread. This function is not
124 * expected to return because it will do a longjmp
127 _thread_kern_sched(scp);
130 * This point should not be reached, so abort the
133 PANIC("Returned to signal function from scheduler");
136 /* Check if a child has terminated: */
137 if (sig == SIGCHLD) {
139 * Go through the file list and set all files
140 * to non-blocking again in case the child
141 * set some of them to block. Sigh.
143 for (i = 0; i < _thread_dtablesize; i++) {
144 /* Check if this file is used: */
145 if (_thread_fd_table[i] != NULL) {
147 * Set the file descriptor to
150 _thread_sys_fcntl(i, F_SETFL,
151 _thread_fd_table[i]->flags |
158 * POSIX says that pending SIGCONT signals are
159 * discarded when one of these signals occurs.
161 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
163 * Enter a loop to discard pending SIGCONT
166 for (pthread = _thread_link_list;
168 pthread = pthread->nxt)
169 sigdelset(&pthread->sigpend,SIGCONT);
173 * Enter a loop to process each thread in the linked
174 * list that is sigwait-ing on a signal. Since POSIX
175 * doesn't specify which thread will get the signal
176 * if there are multiple waiters, we'll give it to the
179 for (pthread = _thread_link_list; pthread != NULL;
180 pthread = pthread->nxt) {
181 if ((pthread->state == PS_SIGWAIT) &&
182 sigismember(pthread->data.sigwait, sig)) {
183 /* Change the state of the thread to run: */
184 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
186 /* Return the signal number: */
187 pthread->signo = sig;
190 * Do not attempt to deliver this signal
197 /* Check if the signal is not being ignored: */
198 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
200 * Enter a loop to process each thread in the linked
203 for (pthread = _thread_link_list; pthread != NULL;
204 pthread = pthread->nxt)
205 _thread_signal(pthread,sig);
207 /* Dispatch pending signals to the running thread: */
211 /* Returns nothing. */
215 /* Perform thread specific actions in response to a signal: */
217 _thread_signal(pthread_t pthread, int sig)
220 * Flag the signal as pending. It will be dispatched later.
222 sigaddset(&pthread->sigpend,sig);
225 * Process according to thread state:
227 switch (pthread->state) {
229 * States which do not change when a signal is trapped:
243 /* Nothing to do here. */
247 * The wait state is a special case due to the handling of
252 * Check for signals other than the death of a child
256 /* Flag the operation as interrupted: */
257 pthread->interrupted = 1;
259 /* Change the state of the thread to run: */
260 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
262 /* Return the signal number: */
263 pthread->signo = sig;
267 * States that are interrupted by the occurrence of a signal
268 * other than the scheduling alarm:
274 if (sig != SIGCHLD ||
275 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
276 /* Flag the operation as interrupted: */
277 pthread->interrupted = 1;
279 /* Change the state of the thread to run: */
280 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
282 /* Return the signal number: */
283 pthread->signo = sig;
289 * Only wake up the thread if the signal is unblocked
290 * and there is a handler installed for the signal.
292 if (!sigismember(&pthread->sigmask, sig) &&
293 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
294 /* Change the state of the thread to run: */
295 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
297 /* Return the signal number: */
298 pthread->signo = sig;
304 /* Dispatch pending signals to the running thread: */
311 * Check if there are pending signals for the running
312 * thread that aren't blocked:
314 if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0)
315 /* Look for all possible pending signals: */
316 for (i = 1; i < NSIG; i++)
318 * Check that a custom handler is installed
319 * and if the signal is not blocked:
321 if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
322 _thread_sigact[i - 1].sa_handler != SIG_IGN &&
323 sigismember(&_thread_run->sigpend,i) &&
324 !sigismember(&_thread_run->sigmask,i)) {
325 /* Clear the pending signal: */
326 sigdelset(&_thread_run->sigpend,i);
329 * Dispatch the signal via the custom signal
332 (*(_thread_sigact[i - 1].sa_handler))(i);