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_dead = 0;
43 static int volatile yield_on_unlock_thread = 0;
44 static spinlock_t thread_dead_lock = _SPINLOCK_INITIALIZER;
45 static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER;
47 /* Lock the thread list: */
51 /* Lock the thread list: */
52 _SPINLOCK(&thread_link_list_lock);
55 /* Lock the dead thread list: */
57 _lock_dead_thread_list()
59 /* Lock the dead thread list: */
60 _SPINLOCK(&thread_dead_lock);
63 /* Lock the thread list: */
67 /* Unlock the thread list: */
68 _SPINUNLOCK(&thread_link_list_lock);
71 * Check if a scheduler interrupt occurred while the thread
74 if (yield_on_unlock_thread) {
75 /* Reset the interrupt flag: */
76 yield_on_unlock_thread = 0;
78 /* This thread has overstayed it's welcome: */
83 /* Lock the dead thread list: */
85 _unlock_dead_thread_list()
87 /* Unlock the dead thread list: */
88 _SPINUNLOCK(&thread_dead_lock);
91 * Check if a scheduler interrupt occurred while the dead
92 * thread list was locked:
94 if (yield_on_unlock_dead) {
95 /* Reset the interrupt flag: */
96 yield_on_unlock_dead = 0;
98 /* This thread has overstayed it's welcome: */
104 _thread_sig_handler(int sig, int code, struct sigcontext * scp)
111 * Check if the pthread kernel has unblocked signals (or is about to)
112 * and was on its way into a _select when the current
113 * signal interrupted it:
115 if (_thread_kern_in_select) {
116 /* Cast the signal number to a character variable: */
120 * Write the signal number to the kernel pipe so that it will
121 * be ready to read when this signal handler returns. This
122 * means that the _select call will complete
125 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
128 /* Check if the signal requires a dump of thread information: */
130 /* Dump thread information to file: */
133 /* Check if an interval timer signal: */
134 else if (sig == SIGVTALRM) {
135 /* Check if the scheduler interrupt has come at an
136 * unfortunate time which one of the threads is
137 * modifying the thread list:
139 if (thread_link_list_lock.access_lock)
141 * Set a flag so that the thread that has
142 * the lock yields when it unlocks the
145 yield_on_unlock_thread = 1;
147 /* Check if the scheduler interrupt has come at an
148 * unfortunate time which one of the threads is
149 * modifying the dead thread list:
151 if (thread_dead_lock.access_lock)
153 * Set a flag so that the thread that has
154 * the lock yields when it unlocks the
157 yield_on_unlock_dead = 1;
160 * Check if the kernel has not been interrupted while
161 * executing scheduler code:
163 else if (!_thread_kern_in_sched) {
165 * Schedule the next thread. This function is not
166 * expected to return because it will do a longjmp
169 _thread_kern_sched(scp);
172 * This point should not be reached, so abort the
175 PANIC("Returned to signal function from scheduler");
178 /* Check if a child has terminated: */
179 if (sig == SIGCHLD) {
181 * Go through the file list and set all files
182 * to non-blocking again in case the child
183 * set some of them to block. Sigh.
185 for (i = 0; i < _thread_dtablesize; i++) {
186 /* Check if this file is used: */
187 if (_thread_fd_table[i] != NULL) {
189 * Set the file descriptor to
192 _thread_sys_fcntl(i, F_SETFL,
193 _thread_fd_table[i]->flags |
200 * POSIX says that pending SIGCONT signals are
201 * discarded when one of there signals occurs.
203 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
205 * Enter a loop to discard pending SIGCONT
208 for (pthread = _thread_link_list;
210 pthread = pthread->nxt)
211 sigdelset(&pthread->sigpend,SIGCONT);
214 /* Check if the signal is not being ignored: */
215 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
217 * Enter a loop to process each thread in the linked
220 for (pthread = _thread_link_list; pthread != NULL;
221 pthread = pthread->nxt)
222 _thread_signal(pthread,sig);
224 /* Dispatch pending signals to the running thread: */
228 /* Returns nothing. */
232 /* Perform thread specific actions in response to a signal: */
234 _thread_signal(pthread_t pthread, int sig)
237 * Flag the signal as pending. It will be dispatched later.
239 sigaddset(&pthread->sigpend,sig);
242 * Process according to thread state:
244 switch (pthread->state) {
246 * States which do not change when a signal is trapped:
259 /* Nothing to do here. */
263 * The wait state is a special case due to the handling of
268 * Check for signals other than the death of a child
272 /* Flag the operation as interrupted: */
273 pthread->interrupted = 1;
275 /* Change the state of the thread to run: */
276 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
278 /* Return the signal number: */
279 pthread->signo = sig;
283 * States that are interrupted by the occurrence of a signal
284 * other than the scheduling alarm:
291 if (sig != SIGCHLD ||
292 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
293 /* Flag the operation as interrupted: */
294 pthread->interrupted = 1;
296 /* Change the state of the thread to run: */
297 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
299 /* Return the signal number: */
300 pthread->signo = sig;
306 /* Dispatch pending signals to the running thread: */
313 * Check if there are pending signals for the running
314 * thread that aren't blocked:
316 if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0)
317 /* Look for all possible pending signals: */
318 for (i = 1; i < NSIG; i++)
320 * Check that a custom handler is installed
321 * and if the signal is not blocked:
323 if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
324 _thread_sigact[i - 1].sa_handler != SIG_IGN &&
325 sigismember(&_thread_run->sigpend,i) &&
326 !sigismember(&_thread_run->sigmask,i)) {
327 /* Clear the pending signal: */
328 sigdelset(&_thread_run->sigpend,i);
331 * Dispatch the signal via the custom signal
334 (*(_thread_sigact[i - 1].sa_handler))(i);