Deleted Added
full compact
thr_sig.c (58094) thr_sig.c (67097)
1/*
2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 15 unchanged lines hidden (view full) ---

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
30 * SUCH DAMAGE.
31 *
1/*
2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 15 unchanged lines hidden (view full) ---

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
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: head/lib/libkse/thread/thr_sig.c 58094 2000-03-15 13:59:27Z deischen $
32 * $FreeBSD: head/lib/libkse/thread/thr_sig.c 67097 2000-10-13 22:12:32Z deischen $
33 */
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/signalvar.h>
37#include <signal.h>
38#include <fcntl.h>
39#include <unistd.h>
40#include <setjmp.h>
41#include <errno.h>
42#ifdef _THREAD_SAFE
43#include <pthread.h>
44#include "pthread_private.h"
45
46/* Prototypes: */
33 */
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/signalvar.h>
37#include <signal.h>
38#include <fcntl.h>
39#include <unistd.h>
40#include <setjmp.h>
41#include <errno.h>
42#ifdef _THREAD_SAFE
43#include <pthread.h>
44#include "pthread_private.h"
45
46/* Prototypes: */
47static void thread_sig_check_state(pthread_t pthread, int sig);
48static void thread_sig_finish_longjmp(void *arg);
49static void handle_state_change(pthread_t pthread);
47static void thread_sig_add(pthread_t pthread, int sig, int has_args);
48static pthread_t thread_sig_find(int sig);
49static void thread_sig_handle_special(int sig);
50static void thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp);
51static void thread_sigframe_add(pthread_t thread, int sig);
52static void thread_sigframe_leave(pthread_t thread, int frame);
53static void thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf);
54static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf);
50
55
56/* #define DEBUG_SIGNAL */
57#ifdef DEBUG_SIGNAL
58#define DBG_MSG stdout_debug
59#else
60#define DBG_MSG(x...)
61#endif
51
62
52/* Static variables: */
53static spinlock_t signal_lock = _SPINLOCK_INITIALIZER;
54static unsigned int pending_sigs[NSIG];
55static unsigned int handled_sigs[NSIG];
56static int volatile check_pending = 0;
57static int volatile check_waiting = 0;
63#if defined(_PTHREADS_INVARIANTS)
64#define SIG_SET_ACTIVE() _sig_in_handler = 1
65#define SIG_SET_INACTIVE() _sig_in_handler = 0
66#else
67#define SIG_SET_ACTIVE()
68#define SIG_SET_INACTIVE()
69#endif
58
70
59/* Initialize signal handling facility: */
60void
71void
61_thread_sig_init(void)
72_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
62{
73{
63 int i;
74 pthread_t pthread;
75 int current_frame;
76 char c;
64
77
65 /* Clear pending and handled signal counts: */
66 for (i = 1; i < NSIG; i++) {
67 pending_sigs[i - 1] = 0;
68 handled_sigs[i - 1] = 0;
69 }
78 if (ucp == NULL)
79 PANIC("Thread signal handler received null context");
80 DBG_MSG("Got signal %d, current thread %p\n", sig, _thread_run);
70
81
71 /* Clear the lock: */
72 signal_lock.access_lock = 0;
73
74 /* Clear the process pending signals: */
75 sigemptyset(&_process_sigpending);
76}
77
78void
79_thread_sig_handler(int sig, int code, ucontext_t * scp)
80{
81 pthread_t pthread, pthread_next;
82 int i;
83 char c;
84
85 /* Check if an interval timer signal: */
86 if (sig == _SCHED_SIGNAL) {
82 /* Check if an interval timer signal: */
83 if (sig == _SCHED_SIGNAL) {
84 /* Update the scheduling clock: */
85 gettimeofday((struct timeval *)&_sched_tod, NULL);
86 _sched_ticks++;
87
87 if (_thread_kern_in_sched != 0) {
88 /*
89 * The scheduler is already running; ignore this
90 * signal.
91 */
92 }
93 /*
94 * Check if the scheduler interrupt has come when
95 * the currently running thread has deferred thread
96 * signals.
97 */
98 else if (_thread_run->sig_defer_count > 0)
99 _thread_run->yield_on_sig_undefer = 1;
88 if (_thread_kern_in_sched != 0) {
89 /*
90 * The scheduler is already running; ignore this
91 * signal.
92 */
93 }
94 /*
95 * Check if the scheduler interrupt has come when
96 * the currently running thread has deferred thread
97 * signals.
98 */
99 else if (_thread_run->sig_defer_count > 0)
100 _thread_run->yield_on_sig_undefer = 1;
100
101 else {
102 /*
101 else {
102 /*
103 * Save the context of the currently running thread:
104 */
105 thread_sig_savecontext(_thread_run, ucp);
106
107 /*
103 * Schedule the next thread. This function is not
104 * expected to return because it will do a longjmp
105 * instead.
106 */
108 * Schedule the next thread. This function is not
109 * expected to return because it will do a longjmp
110 * instead.
111 */
107 _thread_kern_sched(scp);
112 _thread_kern_sched(ucp);
108
109 /*
110 * This point should not be reached, so abort the
111 * process:
112 */
113 PANIC("Returned to signal function from scheduler");
114 }
115 }
116 /*
117 * Check if the kernel has been interrupted while the scheduler
118 * is accessing the scheduling queues or if there is a currently
119 * running thread that has deferred signals.
120 */
113
114 /*
115 * This point should not be reached, so abort the
116 * process:
117 */
118 PANIC("Returned to signal function from scheduler");
119 }
120 }
121 /*
122 * Check if the kernel has been interrupted while the scheduler
123 * is accessing the scheduling queues or if there is a currently
124 * running thread that has deferred signals.
125 */
121 else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) &&
122 (_thread_run->sig_defer_count > 0))) {
126 else if ((_thread_kern_in_sched != 0) ||
127 (_thread_run->sig_defer_count > 0)) {
123 /* Cast the signal number to a character variable: */
124 c = sig;
125
126 /*
127 * Write the signal number to the kernel pipe so that it will
128 * be ready to read when this signal handler returns.
129 */
128 /* Cast the signal number to a character variable: */
129 c = sig;
130
131 /*
132 * Write the signal number to the kernel pipe so that it will
133 * be ready to read when this signal handler returns.
134 */
130 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
135 if (_queue_signals != 0) {
136 _thread_sys_write(_thread_kern_pipe[1], &c, 1);
137 DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig);
138 }
139 if (_thread_sigq[sig - 1].blocked == 0) {
140 DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig);
141 /*
142 * Do not block this signal; it will be blocked
143 * when the pending signals are run down.
144 */
145 /* _thread_sigq[sig - 1].blocked = 1; */
131
146
132 /* Indicate that there are queued signals in the pipe. */
133 _sigq_check_reqd = 1;
134 } else {
135 if (_atomic_lock(&signal_lock.access_lock)) {
136 /* There is another signal handler running: */
137 pending_sigs[sig - 1]++;
138 check_pending = 1;
147 /*
148 * Queue the signal, saving siginfo and sigcontext
149 * (ucontext).
150 *
151 * XXX - Do we need to copy siginfo and ucp?
152 */
153 _thread_sigq[sig - 1].signo = sig;
154 if (info != NULL)
155 memcpy(&_thread_sigq[sig - 1].siginfo, info,
156 sizeof(*info));
157 memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
158
159 /* Indicate that there are queued signals: */
160 _thread_sigq[sig - 1].pending = 1;
161 _sigq_check_reqd = 1;
139 }
162 }
140 else {
141 /* It's safe to handle the signal now. */
142 pthread = _thread_sig_handle(sig, scp);
163 /* These signals need special handling: */
164 else if (sig == SIGCHLD || sig == SIGTSTP ||
165 sig == SIGTTIN || sig == SIGTTOU) {
166 _thread_sigq[sig - 1].pending = 1;
167 _thread_sigq[sig - 1].signo = sig;
168 _sigq_check_reqd = 1;
169 }
170 else
171 DBG_MSG("Got signal %d, ignored.\n", sig);
172 }
173 /*
174 * The signal handlers should have been installed so that they
175 * cannot be interrupted by other signals.
176 */
177 else if (_thread_sigq[sig - 1].blocked == 0) {
178 /* The signal is not blocked; handle the signal: */
179 current_frame = _thread_run->sigframe_count;
143
180
144 /* Reset the pending and handled count back to 0: */
145 pending_sigs[sig - 1] = 0;
146 handled_sigs[sig - 1] = 0;
181 /*
182 * Ignore subsequent occurrences of this signal
183 * until the current signal is handled:
184 */
185 _thread_sigq[sig - 1].blocked = 1;
147
186
148 if (pthread == NULL)
149 signal_lock.access_lock = 0;
150 else {
151 sigaddset(&pthread->sigmask, sig);
187 /* This signal will be handled; clear the pending flag: */
188 _thread_sigq[sig - 1].pending = 0;
152
189
153 /*
154 * Make sure not to deliver the same signal to
155 * the thread twice. sigpend is potentially
156 * modified by the call chain
157 * _thread_sig_handle() -->
158 * thread_sig_check_state(), which can happen
159 * just above.
160 */
161 if (sigismember(&pthread->sigpend, sig))
162 sigdelset(&pthread->sigpend, sig);
190 /*
191 * Save siginfo and sigcontext (ucontext).
192 *
193 * XXX - Do we need to copy siginfo and ucp?
194 */
195 _thread_sigq[sig - 1].signo = sig;
163
196
164 signal_lock.access_lock = 0;
165 _thread_sig_deliver(pthread, sig);
166 sigdelset(&pthread->sigmask, sig);
167 }
168 }
197 if (info != NULL)
198 memcpy(&_thread_sigq[sig - 1].siginfo, info,
199 sizeof(*info));
200 memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
201 SIG_SET_ACTIVE();
169
202
170 /* Enter a loop to process pending signals: */
171 while ((check_pending != 0) &&
172 (_atomic_lock(&signal_lock.access_lock) == 0)) {
173 check_pending = 0;
174 for (i = 1; i < NSIG; i++) {
175 if (pending_sigs[i - 1] > handled_sigs[i - 1]) {
176 pending_sigs[i - 1] = handled_sigs[i - 1];
177 pthread = _thread_sig_handle(i, scp);
178 if (pthread != NULL) {
179 sigaddset(&pthread->sigmask, i);
180 /* Save the old state: */
181 pthread->oldstate = pthread->state;
182 signal_lock.access_lock = 0;
183 _thread_sig_deliver(pthread, i);
184 sigdelset(&pthread->sigmask, i);
185 if (_atomic_lock(&signal_lock.access_lock)) {
186 check_pending = 1;
187 /*
188 * Have the lock holder take care
189 * of any state changes:
190 */
191 if (pthread->state != pthread->oldstate)
192 check_waiting = 1;
193 return;
194 }
195 if (pthread->state != pthread->oldstate)
196 handle_state_change(pthread);
197 }
198 }
199 }
200 while (check_waiting != 0) {
201 check_waiting = 0;
202 /*
203 * Enter a loop to wake up all threads waiting
204 * for a process to complete:
205 */
206 for (pthread = TAILQ_FIRST(&_waitingq);
207 pthread != NULL; pthread = pthread_next) {
208 pthread_next = TAILQ_NEXT(pthread, pqe);
209 if (pthread->state == PS_RUNNING)
210 handle_state_change(pthread);
211 }
212 }
213 /* Release the lock: */
214 signal_lock.access_lock = 0;
203 /* Handle special signals: */
204 thread_sig_handle_special(sig);
205
206 if ((pthread = thread_sig_find(sig)) != NULL) {
207 DBG_MSG("Got signal %d, adding frame to thread %p\n",
208 sig, pthread);
209 /*
210 * A thread was found that can handle the signal.
211 * Save the context of the currently running thread
212 * so that we can switch to another thread without
213 * losing track of where the current thread left off.
214 * This also applies if the current thread is the
215 * thread to be signaled.
216 */
217 thread_sig_savecontext(_thread_run, ucp);
218
219 /* Setup the target thread to receive the signal: */
220 thread_sig_add(pthread, sig, /*has_args*/ 1);
221
222 /* Take a peek at the next ready to run thread: */
223 pthread = PTHREAD_PRIOQ_FIRST();
224 DBG_MSG("Finished adding frame, head of prio list %p\n",
225 pthread);
215 }
226 }
227 else
228 DBG_MSG("No thread to handle signal %d\n", sig);
229 SIG_SET_INACTIVE();
216
217 /*
230
231 /*
218 * Check to see if the current thread performed a
219 * [sig|_]longjmp() out of a signal handler.
232 * Switch to a different context if the currently running
233 * thread takes a signal, or if another thread takes a
234 * signal and the currently running thread is not in a
235 * signal handler.
220 */
236 */
221 if ((_thread_run->jmpflags & (JMPFLAGS_LONGJMP |
222 JMPFLAGS__LONGJMP)) != 0) {
223 _thread_run->jmpflags = JMPFLAGS_NONE;
224 __longjmp(_thread_run->nested_jmp.jmp,
225 _thread_run->longjmp_val);
226 } else if ((_thread_run->jmpflags & JMPFLAGS_SIGLONGJMP) != 0) {
227 _thread_run->jmpflags = JMPFLAGS_NONE;
228 __siglongjmp(_thread_run->nested_jmp.sigjmp,
229 _thread_run->longjmp_val);
237 if ((_thread_run->sigframe_count > current_frame) ||
238 ((pthread != NULL) &&
239 (pthread->active_priority > _thread_run->active_priority))) {
240 /* Enter the kernel scheduler: */
241 DBG_MSG("Entering scheduler from signal handler\n");
242 _thread_kern_sched(ucp);
230 }
231 }
243 }
244 }
245 else {
246 SIG_SET_ACTIVE();
247 thread_sig_handle_special(sig);
248 SIG_SET_INACTIVE();
249 }
232}
233
250}
251
252static void
253thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp)
254{
255 struct pthread_signal_frame *psf;
256
257 psf = _thread_run->curframe;
258
259 memcpy(&psf->ctx.uc, ucp, sizeof(*ucp));
260
261 /* XXX - Save FP registers too? */
262 FP_SAVE_UC(&psf->ctx.uc);
263
264 /* Mark the context saved as a ucontext: */
265 psf->ctxtype = CTX_UC;
266}
267
268/*
269 * Find a thread that can handle the signal.
270 */
234pthread_t
271pthread_t
235_thread_sig_handle(int sig, ucontext_t * scp)
272thread_sig_find(int sig)
236{
273{
237 int i, handler_installed;
274 int handler_installed;
238 pthread_t pthread, pthread_next;
239 pthread_t suspended_thread, signaled_thread;
240
275 pthread_t pthread, pthread_next;
276 pthread_t suspended_thread, signaled_thread;
277
278 DBG_MSG("Looking for thread to handle signal %d\n", sig);
241 /* Check if the signal requires a dump of thread information: */
242 if (sig == SIGINFO)
243 /* Dump thread information to file: */
244 _thread_dump_info();
245
246 /* Check if an interval timer signal: */
247 else if (sig == _SCHED_SIGNAL) {
248 /*
249 * This shouldn't ever occur (should this panic?).
250 */
251 } else {
279 /* Check if the signal requires a dump of thread information: */
280 if (sig == SIGINFO)
281 /* Dump thread information to file: */
282 _thread_dump_info();
283
284 /* Check if an interval timer signal: */
285 else if (sig == _SCHED_SIGNAL) {
286 /*
287 * This shouldn't ever occur (should this panic?).
288 */
289 } else {
252 /* Check if a child has terminated: */
253 if (sig == SIGCHLD) {
254 /*
255 * Go through the file list and set all files
256 * to non-blocking again in case the child
257 * set some of them to block. Sigh.
258 */
259 for (i = 0; i < _thread_dtablesize; i++) {
260 /* Check if this file is used: */
261 if (_thread_fd_table[i] != NULL) {
262 /*
263 * Set the file descriptor to
264 * non-blocking:
265 */
266 _thread_sys_fcntl(i, F_SETFL,
267 _thread_fd_table[i]->flags |
268 O_NONBLOCK);
269 }
270 }
271 /*
272 * Enter a loop to wake up all threads waiting
273 * for a process to complete:
274 */
275 for (pthread = TAILQ_FIRST(&_waitingq);
276 pthread != NULL; pthread = pthread_next) {
277 /*
278 * Grab the next thread before possibly
279 * destroying the link entry:
280 */
281 pthread_next = TAILQ_NEXT(pthread, pqe);
282
283 /*
284 * If this thread is waiting for a child
285 * process to complete, wake it up:
286 */
287 if (pthread->state == PS_WAIT_WAIT) {
288 /* Make the thread runnable: */
289 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
290
291 /* Return the signal number: */
292 pthread->signo = sig;
293 }
294 }
295 }
296
297 /*
290 /*
298 * POSIX says that pending SIGCONT signals are
299 * discarded when one of these signals occurs.
300 */
301 if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
302 /*
303 * Enter a loop to discard pending SIGCONT
304 * signals:
305 */
306 TAILQ_FOREACH(pthread, &_thread_list, tle) {
307 sigdelset(&pthread->sigpend,SIGCONT);
308 }
309 }
310
311 /*
312 * Enter a loop to look for threads that have the signal
313 * unmasked. POSIX specifies that a thread in a sigwait
314 * will get the signal over any other threads. Second
291 * Enter a loop to look for threads that have the signal
292 * unmasked. POSIX specifies that a thread in a sigwait
293 * will get the signal over any other threads. Second
315 * preference will be threads in in a sigsuspend. If
316 * none of the above, then the signal is delivered to the
317 * first thread we find. Note that if a custom handler
318 * is not installed, the signal only affects threads in
319 * sigwait.
294 * preference will be threads in in a sigsuspend. Third
295 * preference will be the current thread. If none of the
296 * above, then the signal is delivered to the first thread
297 * that is found. Note that if a custom handler is not
298 * installed, the signal only affects threads in sigwait.
320 */
321 suspended_thread = NULL;
299 */
300 suspended_thread = NULL;
322 signaled_thread = NULL;
301 if ((_thread_run != &_thread_kern_thread) &&
302 !sigismember(&_thread_run->sigmask, sig))
303 signaled_thread = _thread_run;
304 else
305 signaled_thread = NULL;
323 if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) ||
324 (_thread_sigact[sig - 1].sa_handler == SIG_DFL))
325 handler_installed = 0;
326 else
327 handler_installed = 1;
328
329 for (pthread = TAILQ_FIRST(&_waitingq);
330 pthread != NULL; pthread = pthread_next) {
331 /*
332 * Grab the next thread before possibly destroying
333 * the link entry.
334 */
335 pthread_next = TAILQ_NEXT(pthread, pqe);
336
337 if ((pthread->state == PS_SIGWAIT) &&
338 sigismember(pthread->data.sigwait, sig)) {
339 /* Change the state of the thread to run: */
340 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
306 if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) ||
307 (_thread_sigact[sig - 1].sa_handler == SIG_DFL))
308 handler_installed = 0;
309 else
310 handler_installed = 1;
311
312 for (pthread = TAILQ_FIRST(&_waitingq);
313 pthread != NULL; pthread = pthread_next) {
314 /*
315 * Grab the next thread before possibly destroying
316 * the link entry.
317 */
318 pthread_next = TAILQ_NEXT(pthread, pqe);
319
320 if ((pthread->state == PS_SIGWAIT) &&
321 sigismember(pthread->data.sigwait, sig)) {
322 /* Change the state of the thread to run: */
323 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
324 /*
325 * A signal handler is not invoked for threads
326 * in sigwait. Clear the blocked and pending
327 * flags.
328 */
329 _thread_sigq[sig - 1].blocked = 0;
330 _thread_sigq[sig - 1].pending = 0;
341
342 /* Return the signal number: */
343 pthread->signo = sig;
344
345 /*
346 * POSIX doesn't doesn't specify which thread
347 * will get the signal if there are multiple
348 * waiters, so we give it to the first thread
349 * we find.
350 *
351 * Do not attempt to deliver this signal
331
332 /* Return the signal number: */
333 pthread->signo = sig;
334
335 /*
336 * POSIX doesn't doesn't specify which thread
337 * will get the signal if there are multiple
338 * waiters, so we give it to the first thread
339 * we find.
340 *
341 * Do not attempt to deliver this signal
352 * to other threads.
342 * to other threads and do not add the signal
343 * to the process pending set.
353 */
354 return (NULL);
355 }
356 else if ((handler_installed != 0) &&
357 !sigismember(&pthread->sigmask, sig)) {
358 if (pthread->state == PS_SIGSUSPEND) {
359 if (suspended_thread == NULL)
360 suspended_thread = pthread;
361 } else if (signaled_thread == NULL)
362 signaled_thread = pthread;
363 }
364 }
365
366 /*
367 * Only perform wakeups and signal delivery if there is a
368 * custom handler installed:
369 */
344 */
345 return (NULL);
346 }
347 else if ((handler_installed != 0) &&
348 !sigismember(&pthread->sigmask, sig)) {
349 if (pthread->state == PS_SIGSUSPEND) {
350 if (suspended_thread == NULL)
351 suspended_thread = pthread;
352 } else if (signaled_thread == NULL)
353 signaled_thread = pthread;
354 }
355 }
356
357 /*
358 * Only perform wakeups and signal delivery if there is a
359 * custom handler installed:
360 */
370 if (handler_installed != 0) {
361 if (handler_installed == 0) {
371 /*
362 /*
363 * There is no handler installed. Unblock the
364 * signal so that if a handler _is_ installed, any
365 * subsequent signals can be handled.
366 */
367 _thread_sigq[sig - 1].blocked = 0;
368 } else {
369 /*
372 * If we didn't find a thread in the waiting queue,
373 * check the all threads queue:
374 */
375 if (suspended_thread == NULL &&
376 signaled_thread == NULL) {
377 /*
378 * Enter a loop to look for other threads
379 * capable of receiving the signal:

--- 18 unchanged lines hidden (view full) ---

398 /*
399 * We only deliver the signal to one thread;
400 * give preference to the suspended thread:
401 */
402 if (suspended_thread != NULL)
403 pthread = suspended_thread;
404 else
405 pthread = signaled_thread;
370 * If we didn't find a thread in the waiting queue,
371 * check the all threads queue:
372 */
373 if (suspended_thread == NULL &&
374 signaled_thread == NULL) {
375 /*
376 * Enter a loop to look for other threads
377 * capable of receiving the signal:

--- 18 unchanged lines hidden (view full) ---

396 /*
397 * We only deliver the signal to one thread;
398 * give preference to the suspended thread:
399 */
400 if (suspended_thread != NULL)
401 pthread = suspended_thread;
402 else
403 pthread = signaled_thread;
406
407 /*
408 * Perform any state changes due to signal
409 * arrival:
410 */
411 thread_sig_check_state(pthread, sig);
412 return (pthread);
413 }
414 }
415 }
416
417 /* Returns nothing. */
418 return (NULL);
419}
420
404 return (pthread);
405 }
406 }
407 }
408
409 /* Returns nothing. */
410 return (NULL);
411}
412
421static void
422thread_sig_finish_longjmp(void *arg)
413void
414_thread_sig_check_pending(pthread_t pthread)
423{
415{
416 sigset_t sigset;
417 int i;
418
424 /*
419 /*
425 * Check to see if the current thread performed a [_]longjmp() out of a
426 * signal handler.
420 * Check if there are pending signals for the running
421 * thread or process that aren't blocked:
427 */
422 */
428 if ((_thread_run->jmpflags & (JMPFLAGS_LONGJMP | JMPFLAGS__LONGJMP))
429 != 0) {
430 _thread_run->jmpflags = JMPFLAGS_NONE;
431 _thread_run->continuation = NULL;
432 __longjmp(_thread_run->nested_jmp.jmp,
433 _thread_run->longjmp_val);
423 sigset = pthread->sigpend;
424 SIGSETOR(sigset, _process_sigpending);
425 SIGSETNAND(sigset, pthread->sigmask);
426 if (SIGNOTEMPTY(sigset)) {
427 for (i = 1; i < NSIG; i++) {
428 if (sigismember(&sigset, i) != 0) {
429 if (sigismember(&pthread->sigpend, i) != 0)
430 thread_sig_add(pthread, i,
431 /*has_args*/ 0);
432 else {
433 thread_sig_add(pthread, i,
434 /*has_args*/ 1);
435 sigdelset(&_process_sigpending, i);
436 }
437 }
438 }
434 }
439 }
440}
441
442/*
443 * This can only be called from the kernel scheduler. It assumes that
444 * all thread contexts are saved and that a signal frame can safely be
445 * added to any user thread.
446 */
447void
448_thread_sig_handle_pending(void)
449{
450 pthread_t pthread;
451 int i, sig;
452
453 PTHREAD_ASSERT(_thread_kern_in_sched != 0,
454 "_thread_sig_handle_pending called from outside kernel schedule");
435 /*
455 /*
436 * Check to see if the current thread performed a siglongjmp
437 * out of a signal handler:
456 * Check the array of pending signals:
438 */
457 */
439 else if ((_thread_run->jmpflags & JMPFLAGS_SIGLONGJMP) != 0) {
440 _thread_run->jmpflags = JMPFLAGS_NONE;
441 _thread_run->continuation = NULL;
442 __siglongjmp(_thread_run->nested_jmp.sigjmp,
443 _thread_run->longjmp_val);
458 for (i = 0; i < NSIG; i++) {
459 if (_thread_sigq[i].pending != 0) {
460 /* This signal is no longer pending. */
461 _thread_sigq[i].pending = 0;
462
463 sig = _thread_sigq[i].signo;
464
465 /* Some signals need special handling: */
466 thread_sig_handle_special(sig);
467
468 if (_thread_sigq[i].blocked == 0) {
469 /*
470 * Block future signals until this one
471 * is handled:
472 */
473 _thread_sigq[i].blocked = 1;
474
475 if ((pthread = thread_sig_find(sig)) != NULL) {
476 /*
477 * Setup the target thread to receive
478 * the signal:
479 */
480 thread_sig_add(pthread, sig,
481 /*has_args*/ 1);
482 }
483 }
484 }
444 }
445}
446
447static void
485 }
486}
487
488static void
448handle_state_change(pthread_t pthread)
489thread_sig_handle_special(int sig)
449{
490{
450 /*
451 * We should only need to handle threads whose state was
452 * changed to running:
453 */
454 if (pthread->state == PS_RUNNING) {
455 switch (pthread->oldstate) {
491 pthread_t pthread, pthread_next;
492 int i;
493
494 switch (sig) {
495 case SIGCHLD:
456 /*
496 /*
457 * States which do not change when a signal is trapped:
497 * Go through the file list and set all files
498 * to non-blocking again in case the child
499 * set some of them to block. Sigh.
458 */
500 */
459 case PS_DEAD:
460 case PS_DEADLOCK:
461 case PS_RUNNING:
462 case PS_SIGTHREAD:
463 case PS_STATE_MAX:
464 case PS_SUSPENDED:
465 break;
466
501 for (i = 0; i < _thread_dtablesize; i++) {
502 /* Check if this file is used: */
503 if (_thread_fd_table[i] != NULL) {
504 /*
505 * Set the file descriptor to non-blocking:
506 */
507 _thread_sys_fcntl(i, F_SETFL,
508 _thread_fd_table[i]->flags | O_NONBLOCK);
509 }
510 }
467 /*
511 /*
468 * States which need to return to critical sections
469 * before they can switch contexts:
512 * Enter a loop to wake up all threads waiting
513 * for a process to complete:
470 */
514 */
471 case PS_COND_WAIT:
472 case PS_FDLR_WAIT:
473 case PS_FDLW_WAIT:
474 case PS_FILE_WAIT:
475 case PS_JOIN:
476 case PS_MUTEX_WAIT:
477 /* Indicate that the thread was interrupted: */
478 pthread->interrupted = 1;
515 for (pthread = TAILQ_FIRST(&_waitingq);
516 pthread != NULL; pthread = pthread_next) {
479 /*
517 /*
480 * Defer the [sig|_]longjmp until leaving the critical
481 * region:
518 * Grab the next thread before possibly
519 * destroying the link entry:
482 */
520 */
483 pthread->jmpflags |= JMPFLAGS_DEFERRED;
521 pthread_next = TAILQ_NEXT(pthread, pqe);
484
522
485 /* Set the continuation routine: */
486 pthread->continuation = thread_sig_finish_longjmp;
487 /* FALLTHROUGH */
488 case PS_FDR_WAIT:
489 case PS_FDW_WAIT:
490 case PS_POLL_WAIT:
491 case PS_SELECT_WAIT:
492 case PS_SIGSUSPEND:
493 case PS_SIGWAIT:
494 case PS_SLEEP_WAIT:
495 case PS_SPINBLOCK:
496 case PS_WAIT_WAIT:
497 if ((pthread->flags & PTHREAD_FLAGS_IN_WAITQ) != 0) {
498 PTHREAD_WAITQ_REMOVE(pthread);
499 if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
500 PTHREAD_WORKQ_REMOVE(pthread);
523 /*
524 * If this thread is waiting for a child
525 * process to complete, wake it up:
526 */
527 if (pthread->state == PS_WAIT_WAIT) {
528 /* Make the thread runnable: */
529 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
530
531 /* Return the signal number: */
532 pthread->signo = sig;
501 }
533 }
502 break;
503 }
534 }
535 break;
504
536
505 if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0)
506 PTHREAD_PRIOQ_INSERT_TAIL(pthread);
537 /*
538 * POSIX says that pending SIGCONT signals are
539 * discarded when one of these signals occurs.
540 */
541 case SIGTSTP:
542 case SIGTTIN:
543 case SIGTTOU:
544 /*
545 * Enter a loop to discard pending SIGCONT
546 * signals:
547 */
548 TAILQ_FOREACH(pthread, &_thread_list, tle) {
549 sigdelset(&pthread->sigpend, SIGCONT);
550 }
551 break;
552
553 default:
554 break;
507 }
508}
509
555 }
556}
557
510
511/* Perform thread specific actions in response to a signal: */
558/*
559 * Perform thread specific actions in response to a signal.
560 * This function is only called if there is a handler installed
561 * for the signal, and if the target thread has the signal
562 * unmasked.
563 */
512static void
564static void
513thread_sig_check_state(pthread_t pthread, int sig)
565thread_sig_add(pthread_t pthread, int sig, int has_args)
514{
566{
567 int restart, frame;
568 int block_signals = 0;
569 int suppress_handler = 0;
570
571 restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
572
515 /*
516 * Process according to thread state:
517 */
518 switch (pthread->state) {
519 /*
520 * States which do not change when a signal is trapped:
521 */
573 /*
574 * Process according to thread state:
575 */
576 switch (pthread->state) {
577 /*
578 * States which do not change when a signal is trapped:
579 */
522 case PS_COND_WAIT:
523 case PS_DEAD:
524 case PS_DEADLOCK:
580 case PS_DEAD:
581 case PS_DEADLOCK:
525 case PS_FILE_WAIT:
526 case PS_JOIN:
527 case PS_MUTEX_WAIT:
528 case PS_RUNNING:
529 case PS_STATE_MAX:
530 case PS_SIGTHREAD:
582 case PS_STATE_MAX:
583 case PS_SIGTHREAD:
531 case PS_SPINBLOCK:
584 /*
585 * You can't call a signal handler for threads in these
586 * states.
587 */
588 suppress_handler = 1;
589 break;
590
591 /*
592 * States which do not need any cleanup handling when signals
593 * occur:
594 */
595 case PS_RUNNING:
596 /*
597 * Remove the thread from the queue before changing its
598 * priority:
599 */
600 if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0)
601 PTHREAD_PRIOQ_REMOVE(pthread);
602 break;
603
532 case PS_SUSPENDED:
604 case PS_SUSPENDED:
533 /* Increment the pending signal count. */
534 sigaddset(&pthread->sigpend,sig);
535 break;
536
605 break;
606
607 case PS_SPINBLOCK:
608 /* Remove the thread from the workq and waitq: */
609 PTHREAD_WORKQ_REMOVE(pthread);
610 PTHREAD_WAITQ_REMOVE(pthread);
611 /* Make the thread runnable: */
612 PTHREAD_SET_STATE(pthread, PS_RUNNING);
613 break;
614
537 case PS_SIGWAIT:
615 case PS_SIGWAIT:
616 /* The signal handler is not called for threads in SIGWAIT. */
617 suppress_handler = 1;
538 /* Wake up the thread if the signal is blocked. */
539 if (sigismember(pthread->data.sigwait, sig)) {
540 /* Change the state of the thread to run: */
618 /* Wake up the thread if the signal is blocked. */
619 if (sigismember(pthread->data.sigwait, sig)) {
620 /* Change the state of the thread to run: */
541 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
621 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
542
543 /* Return the signal number: */
544 pthread->signo = sig;
545 } else
546 /* Increment the pending signal count. */
622
623 /* Return the signal number: */
624 pthread->signo = sig;
625 } else
626 /* Increment the pending signal count. */
547 sigaddset(&pthread->sigpend,sig);
627 sigaddset(&pthread->sigpend, sig);
548 break;
549
550 /*
551 * The wait state is a special case due to the handling of
552 * SIGCHLD signals.
553 */
554 case PS_WAIT_WAIT:
628 break;
629
630 /*
631 * The wait state is a special case due to the handling of
632 * SIGCHLD signals.
633 */
634 case PS_WAIT_WAIT:
555 /*
556 * Check for signals other than the death of a child
557 * process:
558 */
559 if (sig != SIGCHLD)
560 /* Flag the operation as interrupted: */
561 pthread->interrupted = 1;
635 if (sig == SIGCHLD) {
636 /* Change the state of the thread to run: */
637 PTHREAD_WAITQ_REMOVE(pthread);
638 PTHREAD_SET_STATE(pthread, PS_RUNNING);
562
639
563 /* Change the state of the thread to run: */
564 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
640 /* Return the signal number: */
641 pthread->signo = sig;
642 }
643 else {
644 /*
645 * Mark the thread as interrupted only if the
646 * restart flag is not set on the signal action:
647 */
648 if (restart == 0)
649 pthread->interrupted = 1;
650 PTHREAD_WAITQ_REMOVE(pthread);
651 PTHREAD_SET_STATE(pthread, PS_RUNNING);
652 }
653 break;
565
654
566 /* Return the signal number: */
567 pthread->signo = sig;
655 /*
656 * States which cannot be interrupted but still require the
657 * signal handler to run:
658 */
659 case PS_COND_WAIT:
660 case PS_JOIN:
661 case PS_MUTEX_WAIT:
662 /*
663 * Remove the thread from the wait queue. It will
664 * be added back to the wait queue once all signal
665 * handlers have been invoked.
666 */
667 PTHREAD_WAITQ_REMOVE(pthread);
568 break;
569
570 /*
668 break;
669
670 /*
571 * States that are interrupted by the occurrence of a signal
572 * other than the scheduling alarm:
671 * States which are interruptible but may need to be removed
672 * from queues before any signal handler is called.
673 *
674 * XXX - We may not need to handle this condition, but will
675 * mark it as a potential problem.
573 */
574 case PS_FDLR_WAIT:
575 case PS_FDLW_WAIT:
676 */
677 case PS_FDLR_WAIT:
678 case PS_FDLW_WAIT:
679 case PS_FILE_WAIT:
680 if (restart == 0)
681 pthread->interrupted = 1;
682 /*
683 * Remove the thread from the wait queue. Our
684 * signal handler hook will remove this thread
685 * from the fd or file queue before invoking
686 * the actual handler.
687 */
688 PTHREAD_WAITQ_REMOVE(pthread);
689 /*
690 * To ensure the thread is removed from the fd and file
691 * queues before any other signal interrupts it, set the
692 * signal mask to block all signals. As soon as the thread
693 * is removed from the queue the signal mask will be
694 * restored.
695 */
696 block_signals = 1;
697 break;
698
699 /*
700 * States which are interruptible:
701 */
576 case PS_FDR_WAIT:
577 case PS_FDW_WAIT:
702 case PS_FDR_WAIT:
703 case PS_FDW_WAIT:
578 case PS_POLL_WAIT:
579 case PS_SLEEP_WAIT:
580 case PS_SELECT_WAIT:
581 if ((_thread_sigact[sig - 1].sa_flags & SA_RESTART) == 0) {
582 /* Flag the operation as interrupted: */
704 if (restart == 0) {
705 /*
706 * Flag the operation as interrupted and
707 * set the state to running:
708 */
583 pthread->interrupted = 1;
709 pthread->interrupted = 1;
584
585 if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
586 PTHREAD_WORKQ_REMOVE(pthread);
587
588 /* Change the state of the thread to run: */
589 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
590
591 /* Return the signal number: */
592 pthread->signo = sig;
710 PTHREAD_SET_STATE(pthread, PS_RUNNING);
593 }
711 }
712 PTHREAD_WORKQ_REMOVE(pthread);
713 PTHREAD_WAITQ_REMOVE(pthread);
594 break;
595
714 break;
715
596 case PS_SIGSUSPEND:
716 case PS_POLL_WAIT:
717 case PS_SELECT_WAIT:
718 case PS_SLEEP_WAIT:
597 /*
719 /*
598 * Only wake up the thread if there is a handler installed
599 * for the signal.
720 * Unmasked signals always cause poll, select, and sleep
721 * to terminate early, regardless of SA_RESTART:
600 */
722 */
601 if (_thread_sigact[sig - 1].sa_handler != SIG_DFL) {
602 /* Change the state of the thread to run: */
603 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
723 pthread->interrupted = 1;
724 /* Remove threads in poll and select from the workq: */
725 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
726 PTHREAD_WORKQ_REMOVE(pthread);
727 PTHREAD_WAITQ_REMOVE(pthread);
728 PTHREAD_SET_STATE(pthread, PS_RUNNING);
729 break;
604
730
605 /* Return the signal number: */
606 pthread->signo = sig;
607 }
731 case PS_SIGSUSPEND:
732 PTHREAD_WAITQ_REMOVE(pthread);
733 PTHREAD_SET_STATE(pthread, PS_RUNNING);
608 break;
609 }
734 break;
735 }
736
737 if (suppress_handler == 0) {
738 /*
739 * Save the current state of the thread and add a
740 * new signal frame.
741 */
742 frame = pthread->sigframe_count;
743 thread_sigframe_save(pthread, pthread->curframe);
744 thread_sigframe_add(pthread, sig);
745 pthread->sigframes[frame + 1]->sig_has_args = has_args;
746 SIGSETOR(pthread->sigmask, _thread_sigact[sig - 1].sa_mask);
747 if (block_signals != 0) {
748 /* Save the signal mask and block all signals: */
749 pthread->sigframes[frame + 1]->saved_state.psd_sigmask =
750 pthread->sigmask;
751 sigfillset(&pthread->sigmask);
752 }
753
754 /* Make sure the thread is runnable: */
755 if (pthread->state != PS_RUNNING)
756 PTHREAD_SET_STATE(pthread, PS_RUNNING);
757 /*
758 * The thread should be removed from all scheduling
759 * queues at this point. Raise the priority and place
760 * the thread in the run queue.
761 */
762 pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY;
763 if (pthread != _thread_run)
764 PTHREAD_PRIOQ_INSERT_TAIL(pthread);
765 }
610}
611
766}
767
612/* Send a signal to a specific thread (ala pthread_kill): */
768/*
769 * Send a signal to a specific thread (ala pthread_kill):
770 */
613void
614_thread_sig_send(pthread_t pthread, int sig)
615{
616 /*
617 * Check that the signal is not being ignored:
618 */
619 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
620 if (pthread->state == PS_SIGWAIT &&
621 sigismember(pthread->data.sigwait, sig)) {
622 /* Change the state of the thread to run: */
771void
772_thread_sig_send(pthread_t pthread, int sig)
773{
774 /*
775 * Check that the signal is not being ignored:
776 */
777 if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
778 if (pthread->state == PS_SIGWAIT &&
779 sigismember(pthread->data.sigwait, sig)) {
780 /* Change the state of the thread to run: */
623 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
781 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
624
625 /* Return the signal number: */
626 pthread->signo = sig;
782
783 /* Return the signal number: */
784 pthread->signo = sig;
627 } else if (pthread->state != PS_SIGWAIT &&
628 !sigismember(&pthread->sigmask, sig)) {
629 /* Perform any state changes due to signal arrival: */
630 thread_sig_check_state(pthread, sig);
631 /* Increment the pending signal count. */
632 sigaddset(&pthread->sigpend,sig);
785 } else if (pthread == _thread_run) {
786 /* Add the signal to the pending set: */
787 sigaddset(&pthread->sigpend, sig);
788 /*
789 * Deliver the signal to the process if a
790 * handler is not installed:
791 */
792 if (_thread_sigact[sig - 1].sa_handler == SIG_DFL)
793 kill(getpid(), sig);
794 if (!sigismember(&pthread->sigmask, sig)) {
795 /*
796 * Call the kernel scheduler which will safely
797 * install a signal frame for this thread:
798 */
799 _thread_kern_sched_sig();
800 }
633 } else {
801 } else {
634 /* Increment the pending signal count. */
635 sigaddset(&pthread->sigpend,sig);
802 if (pthread->state != PS_SIGWAIT &&
803 !sigismember(&pthread->sigmask, sig)) {
804 /* Protect the scheduling queues: */
805 _thread_kern_sig_defer();
806 /*
807 * Perform any state changes due to signal
808 * arrival:
809 */
810 thread_sig_add(pthread, sig, /* has args */ 0);
811 /* Unprotect the scheduling queues: */
812 _thread_kern_sig_undefer();
813 }
814 else
815 /* Increment the pending signal count. */
816 sigaddset(&pthread->sigpend,sig);
817
818 /*
819 * Deliver the signal to the process if a
820 * handler is not installed:
821 */
822 if (_thread_sigact[sig - 1].sa_handler == SIG_DFL)
823 kill(getpid(), sig);
636 }
637 }
638}
639
824 }
825 }
826}
827
640/* Dispatch pending signals to the running thread: */
828/*
829 * User thread signal handler wrapper.
830 *
831 * thread - current running thread
832 */
641void
833void
642_dispatch_signals()
834_thread_sig_wrapper(void)
643{
835{
644 sigset_t sigset;
645 int i;
836 void (*sigfunc)(int, siginfo_t *, void *);
837 struct pthread_signal_frame *psf;
838 pthread_t thread;
839 int dead = 0;
840 int i, sig, has_args;
841 int frame, dst_frame;
646
842
843 thread = _thread_run;
844
845 /* Get the current frame and state: */
846 frame = thread->sigframe_count;
847 PTHREAD_ASSERT(frame > 0, "Invalid signal frame in signal handler");
848 psf = thread->curframe;
849
850 /* Check the threads previous state: */
851 if (psf->saved_state.psd_state != PS_RUNNING) {
852 /*
853 * Do a little cleanup handling for those threads in
854 * queues before calling the signal handler. Signals
855 * for these threads are temporarily blocked until
856 * after cleanup handling.
857 */
858 switch (psf->saved_state.psd_state) {
859 case PS_FDLR_WAIT:
860 case PS_FDLW_WAIT:
861 _fd_lock_backout(thread);
862 psf->saved_state.psd_state = PS_RUNNING;
863 /* Reenable signals: */
864 thread->sigmask = psf->saved_state.psd_sigmask;
865 break;
866
867 case PS_FILE_WAIT:
868 _flockfile_backout(thread);
869 psf->saved_state.psd_state = PS_RUNNING;
870 /* Reenable signals: */
871 thread->sigmask = psf->saved_state.psd_sigmask;
872 break;
873
874 default:
875 break;
876 }
877 }
878
647 /*
879 /*
648 * Check if there are pending signals for the running
649 * thread or process that aren't blocked:
880 * Unless the thread exits or longjmps out of the signal handler,
881 * return to the previous frame:
650 */
882 */
651 sigset = _thread_run->sigpend;
652 SIGSETOR(sigset, _process_sigpending);
653 SIGSETNAND(sigset, _thread_run->sigmask);
654 if (SIGNOTEMPTY(sigset)) {
883 dst_frame = frame - 1;
884
885 /*
886 * Check that a custom handler is installed and if the signal
887 * is not blocked:
888 */
889 sigfunc = _thread_sigact[psf->signo - 1].sa_sigaction;
890 if (((__sighandler_t *)sigfunc != SIG_DFL) &&
891 ((__sighandler_t *)sigfunc != SIG_IGN)) {
655 /*
892 /*
656 * Enter a loop to calculate deliverable pending signals
657 * before actually delivering them. The pending signals
658 * must be removed from the pending signal sets before
659 * calling the signal handler because the handler may
660 * call library routines that again check for and deliver
661 * pending signals.
893 * The signal jump buffer is allocated off the stack.
894 * If the signal handler tries to [_][sig]longjmp() or
895 * setcontext(), our wrapped versions of these routines
896 * will copy the user supplied jump buffer or context
897 * to the destination signal frame, set the destination
898 * signal frame in psf->dst_frame, and _longjmp() back
899 * to here.
662 */
900 */
663 for (i = 1; i < NSIG; i++) {
901 jmp_buf jb;
902
903 /*
904 * Set up the context for abnormal returns out of signal
905 * handlers.
906 */
907 psf->sig_jb = &jb;
908 if (_setjmp(jb) == 0) {
909 DBG_MSG("_thread_sig_wrapper: Entering frame %d, "
910 "stack 0x%lx\n", frame, GET_STACK_JB(jb));
664 /*
911 /*
665 * Check that a custom handler is installed
666 * and if the signal is not blocked:
912 * Invalidate the destination frame before calling
913 * the signal handler.
667 */
914 */
668 if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
669 _thread_sigact[i - 1].sa_handler != SIG_IGN &&
670 sigismember(&sigset, i)) {
671 if (sigismember(&_thread_run->sigpend,i))
672 /* Clear the thread pending signal: */
673 sigdelset(&_thread_run->sigpend,i);
674 else
675 /* Clear the process pending signal: */
676 sigdelset(&_process_sigpending,i);
677 }
915 psf->dst_frame = -1;
916
917 /*
918 * Dispatch the signal via the custom signal
919 * handler:
920 */
921 if (psf->sig_has_args == 0)
922 (*(sigfunc))(psf->signo, NULL, NULL);
923 else if ((_thread_sigact[psf->signo - 1].sa_flags &
924 SA_SIGINFO) != 0)
925 (*(sigfunc))(psf->signo,
926 &_thread_sigq[psf->signo - 1].siginfo,
927 &_thread_sigq[psf->signo - 1].uc);
678 else
928 else
679 /* Remove the signal if it can't be handled: */
680 sigdelset(&sigset, i);
929 (*(sigfunc))(psf->signo,
930 (siginfo_t *)_thread_sigq[psf->signo - 1].siginfo.si_code,
931 &_thread_sigq[psf->signo - 1].uc);
681 }
932 }
933 else {
934 /*
935 * The return from _setjmp() should only be non-zero
936 * when the signal handler wants to xxxlongjmp() or
937 * setcontext() to a different context, or if the
938 * thread has exited (via pthread_exit).
939 */
940 /*
941 * Grab a copy of the destination frame before it
942 * gets clobbered after unwinding.
943 */
944 dst_frame = psf->dst_frame;
945 DBG_MSG("Abnormal exit from handler for signal %d, "
946 "frame %d\n", psf->signo, frame);
682
947
683 /* Now deliver the signals: */
684 for (i = 1; i < NSIG; i++) {
685 if (sigismember(&sigset, i))
686 /* Deliver the signal to the running thread: */
687 _thread_sig_deliver(_thread_run, i);
948 /* Has the thread exited? */
949 if ((dead = thread->flags & PTHREAD_EXITING) != 0)
950 /* When exiting, unwind to frame 0. */
951 dst_frame = 0;
952 else if ((dst_frame < 0) || (dst_frame > frame))
953 PANIC("Attempt to unwind to invalid "
954 "signal frame");
955
956 /* Unwind to the target frame: */
957 for (i = frame; i > dst_frame; i--) {
958 DBG_MSG("Leaving frame %d, signal %d\n", i,
959 thread->sigframes[i]->signo);
960 /* Leave the current signal frame: */
961 thread_sigframe_leave(thread, i);
962
963 /*
964 * Save whatever is needed out of the state
965 * data; as soon as the frame count is
966 * is decremented, another signal can arrive
967 * and corrupt this view of the state data.
968 */
969 sig = thread->sigframes[i]->signo;
970 has_args = thread->sigframes[i]->sig_has_args;
971
972 /*
973 * We're done with this signal frame:
974 */
975 thread->curframe = thread->sigframes[i - 1];
976 thread->sigframe_count = i - 1;
977
978 /*
979 * Only unblock the signal if it was a
980 * process signal as opposed to a signal
981 * generated by pthread_kill().
982 */
983 if (has_args != 0)
984 _thread_sigq[sig - 1].blocked = 0;
985 }
688 }
689 }
986 }
987 }
988
989 /*
990 * Call the kernel scheduler to schedule the next
991 * thread.
992 */
993 if (dead == 0) {
994 /* Restore the threads state: */
995 thread_sigframe_restore(thread, thread->sigframes[dst_frame]);
996 _thread_kern_sched_frame(dst_frame);
997 }
998 else {
999 PTHREAD_ASSERT(dst_frame == 0,
1000 "Invalid signal frame for dead thread");
1001
1002 /* Perform any necessary cleanup before exiting. */
1003 thread_sigframe_leave(thread, 0);
1004
1005 /* This should never return: */
1006 _thread_exit_finish();
1007 PANIC("Return from _thread_exit_finish in signal wrapper");
1008 }
690}
691
1009}
1010
692/* Deliver a signal to a thread: */
693void
694_thread_sig_deliver(pthread_t pthread, int sig)
1011static void
1012thread_sigframe_add(pthread_t thread, int sig)
695{
1013{
696 sigset_t mask;
697 pthread_t pthread_saved;
698 jmp_buf jb, *saved_sighandler_jmp_buf;
1014 unsigned long stackp = 0;
699
1015
1016 /* Get the top of the threads stack: */
1017 switch (thread->curframe->ctxtype) {
1018 case CTX_JB:
1019 case CTX_JB_NOSIG:
1020 stackp = GET_STACK_JB(thread->curframe->ctx.jb);
1021 break;
1022 case CTX_SJB:
1023 stackp = GET_STACK_SJB(thread->curframe->ctx.sigjb);
1024 break;
1025 case CTX_UC:
1026 stackp = GET_STACK_UC(&thread->curframe->ctx.uc);
1027 break;
1028 default:
1029 PANIC("Invalid thread context type");
1030 break;
1031 }
1032
700 /*
1033 /*
701 * Check that a custom handler is installed
702 * and if the signal is not blocked:
1034 * Leave a little space on the stack and round down to the
1035 * nearest aligned word:
703 */
1036 */
704 if (_thread_sigact[sig - 1].sa_handler != SIG_DFL &&
705 _thread_sigact[sig - 1].sa_handler != SIG_IGN) {
706 /* Save the current thread: */
707 pthread_saved = _thread_run;
1037 stackp -= sizeof(double);
1038 stackp &= ~0x3UL;
708
1039
709 /* Save the threads signal mask: */
710 mask = pthread->sigmask;
1040 /* Allocate room on top of the stack for a new signal frame: */
1041 stackp -= sizeof(struct pthread_signal_frame);
711
1042
712 /*
713 * Add the current signal and signal handler
714 * mask to the thread's current signal mask:
715 */
716 SIGSETOR(pthread->sigmask, _thread_sigact[sig - 1].sa_mask);
717 sigaddset(&pthread->sigmask, sig);
1043 /* Set up the new frame: */
1044 thread->sigframe_count++;
1045 thread->sigframes[thread->sigframe_count] =
1046 (struct pthread_signal_frame *) stackp;
1047 thread->curframe = thread->sigframes[thread->sigframe_count];
1048 thread->curframe->stackp = stackp;
1049 thread->curframe->ctxtype = CTX_JB;
1050 thread->curframe->longjmp_val = 1;
1051 thread->curframe->signo = sig;
718
1052
719 /* Current thread inside critical region? */
720 if (_thread_run->sig_defer_count > 0)
721 pthread->sig_defer_count++;
1053 /*
1054 * Set up the context:
1055 */
1056 _setjmp(thread->curframe->ctx.jb);
1057 SET_STACK_JB(thread->curframe->ctx.jb, stackp);
1058 SET_RETURN_ADDR_JB(thread->curframe->ctx.jb, _thread_sig_wrapper);
1059}
722
1060
723 /* Increment the number of nested signals being handled. */
724 pthread->signal_nest_level++;
1061/*
1062 * Locate the signal frame from the specified stack pointer.
1063 */
1064int
1065_thread_sigframe_find(pthread_t pthread, void *stackp)
1066{
1067 int frame;
725
1068
726 /*
727 * The jump buffer is allocated off the stack and the current
728 * jump buffer is saved. If the signal handler tries to
729 * [sig|_]longjmp(), our version of [sig|_]longjmp() will copy
730 * the user supplied jump buffer into
731 * _thread_run->nested_jmp.[sig]jmp and _longjmp() back to here.
732 */
733 saved_sighandler_jmp_buf = pthread->sighandler_jmp_buf;
734 pthread->sighandler_jmp_buf = &jb;
1069 /*
1070 * Find the destination of the target frame based on the
1071 * given stack pointer.
1072 */
1073 for (frame = pthread->sigframe_count; frame >= 0; frame--) {
1074 if (stackp < (void *)pthread->sigframes[frame]->stackp)
1075 break;
1076 }
1077 return (frame);
1078}
1079
1080void
1081thread_sigframe_leave(pthread_t thread, int frame)
1082{
1083 struct pthread_state_data *psd;
735
1084
736 _thread_run = pthread;
1085 psd = &thread->sigframes[frame]->saved_state;
737
1086
738 if (_setjmp(jb) == 0) {
739 /*
740 * Dispatch the signal via the custom signal
741 * handler:
742 */
743 (*(_thread_sigact[sig - 1].sa_handler))(sig);
744 }
1087 /*
1088 * Perform any necessary cleanup for this signal frame:
1089 */
1090 switch (psd->psd_state) {
1091 case PS_DEAD:
1092 case PS_DEADLOCK:
1093 case PS_RUNNING:
1094 case PS_SIGTHREAD:
1095 case PS_STATE_MAX:
1096 case PS_SUSPENDED:
1097 break;
745
1098
746 _thread_run = pthread_saved;
1099 /*
1100 * Threads in the following states need to be removed
1101 * from queues.
1102 */
1103 case PS_COND_WAIT:
1104 _cond_wait_backout(thread);
1105 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
1106 PTHREAD_WAITQ_REMOVE(thread);
1107 break;
747
1108
748 pthread->sighandler_jmp_buf = saved_sighandler_jmp_buf;
1109 case PS_FDLR_WAIT:
1110 case PS_FDLW_WAIT:
1111 _fd_lock_backout(thread);
1112 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
1113 PTHREAD_WAITQ_REMOVE(thread);
1114 break;
749
1115
750 /* Decrement the signal nest level. */
751 pthread->signal_nest_level--;
1116 case PS_FILE_WAIT:
1117 _flockfile_backout(thread);
1118 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
1119 PTHREAD_WAITQ_REMOVE(thread);
1120 break;
752
1121
753 /* Current thread inside critical region? */
754 if (_thread_run->sig_defer_count > 0)
755 pthread->sig_defer_count--;
1122 case PS_JOIN:
1123 _join_backout(thread);
1124 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
1125 PTHREAD_WAITQ_REMOVE(thread);
1126 break;
756
1127
757 /* Restore the threads signal mask: */
758 pthread->sigmask = mask;
1128 case PS_MUTEX_WAIT:
1129 _mutex_lock_backout(thread);
1130 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
1131 PTHREAD_WAITQ_REMOVE(thread);
1132 break;
1133
1134 case PS_FDR_WAIT:
1135 case PS_FDW_WAIT:
1136 case PS_POLL_WAIT:
1137 case PS_SELECT_WAIT:
1138 case PS_SIGSUSPEND:
1139 case PS_SIGWAIT:
1140 case PS_SLEEP_WAIT:
1141 case PS_SPINBLOCK:
1142 case PS_WAIT_WAIT:
1143 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) {
1144 PTHREAD_WAITQ_REMOVE(thread);
1145 if ((psd->psd_flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
1146 PTHREAD_WORKQ_REMOVE(thread);
1147 }
1148 break;
759 }
760}
1149 }
1150}
1151
1152static void
1153thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf)
1154{
1155 thread->interrupted = psf->saved_state.psd_interrupted;
1156 thread->sigmask = psf->saved_state.psd_sigmask;
1157 thread->state = psf->saved_state.psd_state;
1158 thread->flags = psf->saved_state.psd_flags;
1159 thread->wakeup_time = psf->saved_state.psd_wakeup_time;
1160 thread->data = psf->saved_state.psd_wait_data;
1161}
1162
1163static void
1164thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf)
1165{
1166 psf->saved_state.psd_interrupted = thread->interrupted;
1167 psf->saved_state.psd_sigmask = thread->sigmask;
1168 psf->saved_state.psd_state = thread->state;
1169 psf->saved_state.psd_flags = thread->flags;
1170 thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
1171 PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ |
1172 PTHREAD_FLAGS_IN_JOINQ;
1173 psf->saved_state.psd_wakeup_time = thread->wakeup_time;
1174 psf->saved_state.psd_wait_data = thread->data;
1175}
1176
761#endif
1177#endif