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)
112 * Check if the pthread kernel has unblocked signals (or is about to)
113 * and was on its way into a _select when the current
114 * signal interrupted it:
116 if (_thread_kern_in_select) {
117 /* Cast the signal number to a character variable: */
121 * Write the signal number to the kernel pipe so that it will
122 * be ready to read when this signal handler returns. This
123 * means that the _select call will complete
126 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
129 /* Check if the signal requires a dump of thread information: */
131 /* Dump thread information to file: */
134 /* Check if an interval timer signal: */
135 else if (sig == SIGVTALRM) {
136 /* Check if the scheduler interrupt has come at an
137 * unfortunate time which one of the threads is
138 * modifying the thread list:
140 if (thread_link_list_lock.access_lock)
142 * Set a flag so that the thread that has
143 * the lock yields when it unlocks the
146 yield_on_unlock_thread = 1;
148 /* Check if the scheduler interrupt has come at an
149 * unfortunate time which one of the threads is
150 * modifying the dead thread list:
152 if (thread_dead_lock.access_lock)
154 * Set a flag so that the thread that has
155 * the lock yields when it unlocks the
158 yield_on_unlock_dead = 1;
161 * Check if the kernel has not been interrupted while
162 * executing scheduler code:
164 else if (!_thread_kern_in_sched) {
166 * Schedule the next thread. This function is not
167 * expected to return because it will do a longjmp
170 _thread_kern_sched(scp);
173 * This point should not be reached, so abort the
176 PANIC("Returned to signal function from scheduler");
179 /* Check if a child has terminated: */
180 if (sig == SIGCHLD) {
182 * Go through the file list and set all files
183 * to non-blocking again in case the child
184 * set some of them to block. Sigh.
186 for (i = 0; i < _thread_dtablesize; i++) {
187 /* Check if this file is used: */
188 if (_thread_fd_table[i] != NULL) {
190 * Set the file descriptor to
193 _thread_sys_fcntl(i, F_SETFL,
194 _thread_fd_table[i]->flags |
201 * POSIX says that pending SIGCONT signals are
202 * discarded when one of there signals occurs.
204 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
206 * Enter a loop to discard pending SIGCONT
209 for (pthread = _thread_link_list;
211 pthread = pthread->nxt)
212 sigdelset(&pthread->sigpend,SIGCONT);
215 /* Check if the signal is not being ignored: */
216 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)
218 * Enter a loop to process each thread in the linked
221 for (pthread = _thread_link_list; pthread != NULL;
222 pthread = pthread->nxt)
223 _thread_signal(pthread,sig);
225 /* Dispatch pending signals to the running thread: */
229 /* Returns nothing. */
233 /* Perform thread specific actions in response to a signal: */
235 _thread_signal(pthread_t pthread, int sig)
238 struct sigaction act;
241 * Flag the signal as pending. It will be dispatched later.
243 sigaddset(&pthread->sigpend,sig);
246 * Process according to thread state:
248 switch (pthread->state) {
250 * States which do not change when a signal is trapped:
263 /* Nothing to do here. */
267 * The wait state is a special case due to the handling of
272 * Check for signals other than the death of a child
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;
287 * States that are interrupted by the occurrence of a signal
288 * other than the scheduling alarm:
295 if (sig != SIGCHLD ||
296 _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
297 /* Flag the operation as interrupted: */
298 pthread->interrupted = 1;
300 /* Change the state of the thread to run: */
301 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
303 /* Return the signal number: */
304 pthread->signo = sig;
310 /* Dispatch pending signals to the running thread: */
317 * Check if there are pending signals for the running
318 * thread that aren't blocked:
320 if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0)
321 /* Look for all possible pending signals: */
322 for (i = 1; i < NSIG; i++)
324 * Check that a custom handler is installed
325 * and if the signal is not blocked:
327 if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
328 _thread_sigact[i - 1].sa_handler != SIG_IGN &&
329 sigismember(&_thread_run->sigpend,i) &&
330 !sigismember(&_thread_run->sigmask,i)) {
331 /* Clear the pending signal: */
332 sigdelset(&_thread_run->sigpend,i);
335 * Dispatch the signal via the custom signal
338 (*(_thread_sigact[i - 1].sa_handler))(i);