Deleted Added
sdiff udiff text old ( 115080 ) new ( 115278 )
full compact
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
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.
19 *
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 AUTHOR 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
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: head/lib/libkse/thread/thr_sig.c 115080 2003-05-16 19:58:30Z deischen $
33 */
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/signalvar.h>
37#include <signal.h>
38#include <errno.h>
39#include <fcntl.h>
40#include <unistd.h>
41#include <string.h>
42#include <pthread.h>
43#include "thr_private.h"
44#include "pthread_md.h"
45
46/* Prototypes: */
47static void build_siginfo(siginfo_t *info, int signo);
48/* static void thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info); */
49static void thr_sig_check_state(struct pthread *pthread, int sig);
50static struct pthread *thr_sig_find(struct kse *curkse, int sig,
51 siginfo_t *info);
52static void handle_special_signals(struct kse *curkse, int sig);
53static void thr_sigframe_add(struct pthread *thread, int sig,
54 siginfo_t *info);
55static void thr_sigframe_restore(struct pthread *thread,
56 struct pthread_sigframe *psf);
57static void thr_sigframe_save(struct pthread *thread,
58 struct pthread_sigframe *psf);
59static void thr_sig_invoke_handler(struct pthread *, int sig,
60 siginfo_t *info, ucontext_t *ucp);
61
62/* #define DEBUG_SIGNAL */
63#ifdef DEBUG_SIGNAL
64#define DBG_MSG stdout_debug
65#else
66#define DBG_MSG(x...)
67#endif
68
69/*
70 * Signal setup and delivery.
71 *
72 * 1) Delivering signals to threads in the same KSE.
73 * These signals are sent by upcall events and are set in the
74 * km_sigscaught field of the KSE mailbox. Since these signals
75 * are received while operating on the KSE stack, they can be
76 * delivered either by using signalcontext() to add a stack frame
77 * to the target thread's stack, or by adding them in the thread's
78 * pending set and having the thread run them down after it
79 * 2) Delivering signals to threads in other KSEs/KSEGs.
80 * 3) Delivering signals to threads in critical regions.
81 * 4) Delivering signals to threads after they change their signal masks.
82 *
83 * Methods of delivering signals.
84 *
85 * 1) Add a signal frame to the thread's saved context.
86 * 2) Add the signal to the thread structure, mark the thread as
87 * having signals to handle, and let the thread run them down
88 * after it resumes from the KSE scheduler.
89 *
90 * Problem with 1). You can't do this to a running thread or a
91 * thread in a critical region.
92 *
93 * Problem with 2). You can't do this to a thread that doesn't
94 * yield in some way (explicitly enters the scheduler). A thread
95 * blocked in the kernel or a CPU hungry thread will not see the
96 * signal without entering the scheduler.
97 *
98 * The solution is to use both 1) and 2) to deliver signals:
99 *
100 * o Thread in critical region - use 2). When the thread
101 * leaves the critical region it will check to see if it
102 * has pending signals and run them down.
103 *
104 * o Thread enters scheduler explicitly - use 2). The thread
105 * can check for pending signals after it returns from the
106 * the scheduler.
107 *
108 * o Thread is running and not current thread - use 2). When the
109 * thread hits a condition specified by one of the other bullets,
110 * the signal will be delivered.
111 *
112 * o Thread is running and is current thread (e.g., the thread
113 * has just changed its signal mask and now sees that it has
114 * pending signals) - just run down the pending signals.
115 *
116 * o Thread is swapped out due to quantum expiration - use 1)
117 *
118 * o Thread is blocked in kernel - kse_thr_wakeup() and then
119 * use 1)
120 */
121
122/*
123 * Rules for selecting threads for signals received:
124 *
125 * 1) If the signal is a sychronous signal, it is delivered to
126 * the generating (current thread). If the thread has the
127 * signal masked, it is added to the threads pending signal
128 * set until the thread unmasks it.
129 *
130 * 2) A thread in sigwait() where the signal is in the thread's
131 * waitset.
132 *
133 * 3) A thread in sigsuspend() where the signal is not in the
134 * thread's suspended signal mask.
135 *
136 * 4) Any thread (first found/easiest to deliver) that has the
137 * signal unmasked.
138 */
139
140/*
141 * This signal handler only delivers asynchronous signals.
142 * This must be called with upcalls disabled and without
143 * holding any locks.
144 */
145void
146_thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
147{
148 struct pthread *thread;
149
150 DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig);
151
152 /* Some signals need special handling: */
153 handle_special_signals(curkse, sig);
154
155 if ((thread = thr_sig_find(curkse, sig, info)) != NULL) {
156 /*
157 * Setup the target thread to receive the signal:
158 */
159 DBG_MSG("Got signal %d, selecting thread %p\n", sig, thread);
160 KSE_SCHED_LOCK(curkse, thread->kseg);
161 _thr_sig_add(thread, sig, info);
162 KSE_SCHED_UNLOCK(curkse, thread->kseg);
163 }
164}
165
166void
167_thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
168{
169 void (*sigfunc)(int, siginfo_t *, void *);
170 struct kse *curkse;
171
172 curkse = _get_curkse();
173 if ((curkse == NULL) || ((curkse->k_flags & KF_STARTED) == 0)) {
174 /* Upcalls are not yet started; just call the handler. */
175 sigfunc = _thread_sigact[sig - 1].sa_sigaction;
176 ucp->uc_sigmask = _thr_proc_sigmask;
177 if (((__sighandler_t *)sigfunc != SIG_DFL) &&
178 ((__sighandler_t *)sigfunc != SIG_IGN)) {
179 if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO)
180 != 0) || (info == NULL))
181 (*(sigfunc))(sig, info, ucp);
182 else
183 (*(sigfunc))(sig, (siginfo_t *)info->si_code,
184 ucp);
185 }
186 }
187 else {
188 /* Nothing. */
189 DBG_MSG("Got signal %d\n", sig);
190 sigaddset(&curkse->k_mbx.km_sigscaught, sig);
191 ucp->uc_sigmask = _thr_proc_sigmask;
192 }
193}
194
195static void
196thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
197 ucontext_t *ucp)
198{
199 void (*sigfunc)(int, siginfo_t *, void *);
200 sigset_t saved_mask;
201 int saved_seqno;
202
203 /* Invoke the signal handler without going through the scheduler:
204 */
205 DBG_MSG("Got signal %d, calling handler for current thread %p\n",
206 sig, curthread);
207
208 /*
209 * Setup the threads signal mask.
210 *
211 * The mask is changed in the thread's active signal mask
212 * (in the context) and not in the base signal mask because
213 * a thread is allowed to change its signal mask within a
214 * signal handler. If it does, the signal mask restored
215 * after the handler should be the same as that set by the
216 * thread during the handler, not the original mask from
217 * before calling the handler. The thread could also
218 * modify the signal mask in the context and expect this
219 * mask to be used.
220 */
221 THR_SCHED_LOCK(curthread, curthread);
222 saved_mask = curthread->tmbx.tm_context.uc_sigmask;
223 saved_seqno = curthread->sigmask_seqno;
224 SIGSETOR(curthread->tmbx.tm_context.uc_sigmask,
225 _thread_sigact[sig - 1].sa_mask);
226 sigaddset(&curthread->tmbx.tm_context.uc_sigmask, sig);
227 THR_SCHED_UNLOCK(curthread, curthread);
228
229 /*
230 * Check that a custom handler is installed and if
231 * the signal is not blocked:
232 */
233 sigfunc = _thread_sigact[sig - 1].sa_sigaction;
234 ucp->uc_sigmask = _thr_proc_sigmask;
235 if (((__sighandler_t *)sigfunc != SIG_DFL) &&
236 ((__sighandler_t *)sigfunc != SIG_IGN)) {
237 if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) ||
238 (info == NULL))
239 (*(sigfunc))(sig, info, ucp);
240 else
241 (*(sigfunc))(sig, (siginfo_t *)info->si_code, ucp);
242 }
243
244 /*
245 * Restore the thread's signal mask.
246 */
247 if (saved_seqno == curthread->sigmask_seqno)
248 curthread->tmbx.tm_context.uc_sigmask = saved_mask;
249 else
250 curthread->tmbx.tm_context.uc_sigmask = curthread->sigmask;
251}
252
253/*
254 * Find a thread that can handle the signal. This must be called
255 * with upcalls disabled.
256 */
257struct pthread *
258thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
259{
260 int handler_installed;
261 struct pthread *pthread;
262 struct pthread *suspended_thread, *signaled_thread;
263
264 DBG_MSG("Looking for thread to handle signal %d\n", sig);
265
266 handler_installed = (_thread_sigact[sig - 1].sa_handler != SIG_IGN) &&
267 (_thread_sigact[sig - 1].sa_handler != SIG_DFL);
268
269 /* Check if the signal requires a dump of thread information: */
270 if (sig == SIGINFO) {
271 /* Dump thread information to file: */
272 _thread_dump_info();
273 }
274 /*
275 * Enter a loop to look for threads that have the signal
276 * unmasked. POSIX specifies that a thread in a sigwait
277 * will get the signal over any other threads. Second
278 * preference will be threads in in a sigsuspend. Third
279 * preference will be the current thread. If none of the
280 * above, then the signal is delivered to the first thread
281 * that is found. Note that if a custom handler is not
282 * installed, the signal only affects threads in sigwait.
283 */
284 suspended_thread = NULL;
285 signaled_thread = NULL;
286
287 KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
288 TAILQ_FOREACH(pthread, &_thread_list, tle) {
289 /* Take the scheduling lock. */
290 KSE_SCHED_LOCK(curkse, pthread->kseg);
291 if ((pthread->state == PS_SIGWAIT) &&
292 sigismember(pthread->data.sigwait, sig)) {
293 /*
294 * Return the signal number and make the
295 * thread runnable.
296 */
297 pthread->signo = sig;
298 _thr_setrunnable_unlocked(pthread);
299
300 KSE_SCHED_UNLOCK(curkse, pthread->kseg);
301
302 /*
303 * POSIX doesn't doesn't specify which thread
304 * will get the signal if there are multiple
305 * waiters, so we give it to the first thread
306 * we find.
307 *
308 * Do not attempt to deliver this signal
309 * to other threads and do not add the signal
310 * to the process pending set.
311 */
312 KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
313 DBG_MSG("Waking thread %p in sigwait with signal %d\n",
314 pthread, sig);
315 return (NULL);
316 }
317 else if ((pthread->state == PS_DEAD) ||
318 (pthread->state == PS_DEADLOCK) ||
319 THR_IS_EXITING(pthread) || THR_IS_SUSPENDED(pthread))
320 ; /* Skip this thread. */
321 else if ((handler_installed != 0) &&
322 !sigismember(&pthread->tmbx.tm_context.uc_sigmask, sig)) {
323 if (pthread->state == PS_SIGSUSPEND) {
324 if (suspended_thread == NULL)
325 suspended_thread = pthread;
326 } else if (signaled_thread == NULL)
327 signaled_thread = pthread;
328 }
329 KSE_SCHED_UNLOCK(curkse, pthread->kseg);
330 }
331 KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
332
333 /*
334 * Only perform wakeups and signal delivery if there is a
335 * custom handler installed:
336 */
337 if (handler_installed == 0) {
338 /*
339 * There is no handler installed; nothing to do here.
340 */
341 } else if (suspended_thread == NULL &&
342 signaled_thread == NULL) {
343 /*
344 * Add it to the set of signals pending
345 * on the process:
346 */
347 KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
348 if (!sigismember(&_thr_proc_sigpending, sig)) {
349 sigaddset(&_thr_proc_sigpending, sig);
350 if (info == NULL)
351 build_siginfo(&_thr_proc_siginfo[sig], sig);
352 else
353 memcpy(&_thr_proc_siginfo[sig], info,
354 sizeof(*info));
355 }
356 KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
357 } else {
358 /*
359 * We only deliver the signal to one thread;
360 * give preference to the suspended thread:
361 */
362 if (suspended_thread != NULL)
363 pthread = suspended_thread;
364 else
365 pthread = signaled_thread;
366 return (pthread);
367 }
368 return (NULL);
369}
370
371static void
372build_siginfo(siginfo_t *info, int signo)
373{
374 bzero(info, sizeof(*info));
375 info->si_signo = signo;
376 info->si_pid = _thr_pid;
377}
378
379/*
380 * This is called by a thread when it has pending signals to deliver.
381 * It should only be called from the context of the thread.
382 */
383void
384_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
385 struct pthread_sigframe *psf)
386{
387 struct pthread_sigframe psf_save;
388 sigset_t sigset;
389 int i;
390
391 THR_SCHED_LOCK(curthread, curthread);
392 memcpy(&sigset, &curthread->sigpend, sizeof(sigset));
393 sigemptyset(&curthread->sigpend);
394 if (psf != NULL) {
395 memcpy(&psf_save, psf, sizeof(*psf));
396 SIGSETOR(sigset, psf_save.psf_sigset);
397 sigemptyset(&psf->psf_sigset);
398 }
399 THR_SCHED_UNLOCK(curthread, curthread);
400
401 /* Check the threads previous state: */
402 if ((psf != NULL) && (psf_save.psf_state != PS_RUNNING)) {
403 /*
404 * Do a little cleanup handling for those threads in
405 * queues before calling the signal handler. Signals
406 * for these threads are temporarily blocked until
407 * after cleanup handling.
408 */
409 switch (psf_save.psf_state) {
410 case PS_COND_WAIT:
411 _cond_wait_backout(curthread);
412 psf_save.psf_state = PS_RUNNING;
413 break;
414
415 case PS_MUTEX_WAIT:
416 _mutex_lock_backout(curthread);
417 psf_save.psf_state = PS_RUNNING;
418 break;
419
420 default:
421 break;
422 }
423 }
424 /*
425 * Lower the priority before calling the handler in case
426 * it never returns (longjmps back):
427 */
428 curthread->active_priority &= ~THR_SIGNAL_PRIORITY;
429
430 for (i = 1; i < NSIG; i++) {
431 if (sigismember(&sigset, i) != 0) {
432 /* Call the handler: */
433 thr_sig_invoke_handler(curthread, i,
434 &curthread->siginfo[i], ucp);
435 }
436 }
437
438 THR_SCHED_LOCK(curthread, curthread);
439 if (psf != NULL)
440 thr_sigframe_restore(curthread, &psf_save);
441 /* Restore the signal mask. */
442 curthread->tmbx.tm_context.uc_sigmask = curthread->sigmask;
443 THR_SCHED_UNLOCK(curthread, curthread);
444 _thr_sig_check_pending(curthread);
445}
446
447/*
448 * This checks pending signals for the current thread. It should be
449 * called whenever a thread changes its signal mask. Note that this
450 * is called from a thread (using its stack).
451 *
452 * XXX - We might want to just check to see if there are pending
453 * signals for the thread here, but enter the UTS scheduler
454 * to actually install the signal handler(s).
455 */
456void
457_thr_sig_check_pending(struct pthread *curthread)
458{
459 sigset_t sigset;
460 sigset_t pending_process;
461 sigset_t pending_thread;
462 kse_critical_t crit;
463 int i;
464
465 curthread->check_pending = 0;
466
467 /*
468 * Check if there are pending signals for the running
469 * thread or process that aren't blocked:
470 */
471 crit = _kse_critical_enter();
472 KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
473 sigset = _thr_proc_sigpending;
474 KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
475 _kse_critical_leave(crit);
476
477 THR_SCHED_LOCK(curthread, curthread);
478 SIGSETOR(sigset, curthread->sigpend);
479 SIGSETNAND(sigset, curthread->tmbx.tm_context.uc_sigmask);
480 if (SIGNOTEMPTY(sigset)) {
481 ucontext_t uc;
482 volatile int once;
483
484 curthread->check_pending = 0;
485 THR_SCHED_UNLOCK(curthread, curthread);
486
487 /*
488 * Split the pending signals into those that were
489 * pending on the process and those that were pending
490 * on the thread.
491 */
492 sigfillset(&pending_process);
493 sigfillset(&pending_thread);
494 for (i = 1; i < NSIG; i++) {
495 if (sigismember(&sigset, i) != 0) {
496 if (sigismember(&curthread->sigpend, i) != 0) {
497 build_siginfo(&curthread->siginfo[i], i);
498 sigdelset(&pending_thread, i);
499 } else {
500 memcpy(&curthread->siginfo[i],
501 &_thr_proc_siginfo[i],
502 sizeof(siginfo_t));
503 sigdelset(&pending_process, i);
504 }
505 }
506 }
507 /*
508 * Remove any process pending signals that were scheduled
509 * to be delivered from process' pending set.
510 */
511 crit = _kse_critical_enter();
512 KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
513 SIGSETAND(_thr_proc_sigpending, pending_process);
514 KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
515 _kse_critical_leave(crit);
516
517 /*
518 * Remove any thread pending signals that were scheduled
519 * to be delivered from thread's pending set.
520 */
521 THR_SCHED_LOCK(curthread, curthread);
522 SIGSETAND(curthread->sigpend, pending_thread);
523 THR_SCHED_UNLOCK(curthread, curthread);
524
525 once = 0;
526 THR_GETCONTEXT(&uc);
527 if (once == 0) {
528 once = 1;
529 for (i = 1; i < NSIG; i++) {
530 if (sigismember(&sigset, i) != 0) {
531 /* Call the handler: */
532 thr_sig_invoke_handler(curthread, i,
533 &curthread->siginfo[i], &uc);
534 }
535 }
536 }
537 }
538 else
539 THR_SCHED_UNLOCK(curthread, curthread);
540}
541
542/*
543 * This must be called with upcalls disabled.
544 */
545static void
546handle_special_signals(struct kse *curkse, int sig)
547{
548 switch (sig) {
549 /*
550 * POSIX says that pending SIGCONT signals are
551 * discarded when one of these signals occurs.
552 */
553 case SIGTSTP:
554 case SIGTTIN:
555 case SIGTTOU:
556 KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
557 sigdelset(&_thr_proc_sigpending, SIGCONT);
558 KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
559 break;
560
561 default:
562 break;
563 }
564}
565
566/*
567 * Perform thread specific actions in response to a signal.
568 * This function is only called if there is a handler installed
569 * for the signal, and if the target thread has the signal
570 * unmasked.
571 *
572 * This must be called with the thread's scheduling lock held.
573 */
574void
575_thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
576{
577 int restart;
578 int suppress_handler = 0;
579
580 if (pthread->curframe == NULL) {
581 /*
582 * This thread is active. Just add it to the
583 * thread's pending set.
584 */
585 sigaddset(&pthread->sigpend, sig);
586 pthread->check_pending = 1;
587 if (info == NULL)
588 build_siginfo(&pthread->siginfo[sig], sig);
589 else if (info != &pthread->siginfo[sig])
590 memcpy(&pthread->siginfo[sig], info,
591 sizeof(*info));
592 if ((pthread->blocked != 0) && !THR_IN_CRITICAL(pthread))
593 kse_thr_interrupt(&pthread->tmbx /* XXX - restart?!?! */);
594 }
595 else {
596 restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
597
598 /* Make sure this signal isn't still in the pending set: */
599 sigdelset(&pthread->sigpend, sig);
600
601 /*
602 * Process according to thread state:
603 */
604 switch (pthread->state) {
605 /*
606 * States which do not change when a signal is trapped:
607 */
608 case PS_DEAD:
609 case PS_DEADLOCK:
610 case PS_LOCKWAIT:
611 case PS_SUSPENDED:
612 case PS_STATE_MAX:
613 /*
614 * You can't call a signal handler for threads in these
615 * states.
616 */
617 suppress_handler = 1;
618 break;
619
620 /*
621 * States which do not need any cleanup handling when signals
622 * occur:
623 */
624 case PS_RUNNING:
625 /*
626 * Remove the thread from the queue before changing its
627 * priority:
628 */
629 if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0)
630 THR_RUNQ_REMOVE(pthread);
631 break;
632
633 /*
634 * States which cannot be interrupted but still require the
635 * signal handler to run:
636 */
637 case PS_COND_WAIT:
638 case PS_MUTEX_WAIT:
639 /*
640 * Remove the thread from the wait queue. It will
641 * be added back to the wait queue once all signal
642 * handlers have been invoked.
643 */
644 KSE_WAITQ_REMOVE(pthread->kse, pthread);
645 break;
646
647 case PS_SLEEP_WAIT:
648 /*
649 * Unmasked signals always cause sleep to terminate
650 * early regardless of SA_RESTART:
651 */
652 pthread->interrupted = 1;
653 KSE_WAITQ_REMOVE(pthread->kse, pthread);
654 THR_SET_STATE(pthread, PS_RUNNING);
655 break;
656
657 case PS_JOIN:
658 case PS_SIGSUSPEND:
659 KSE_WAITQ_REMOVE(pthread->kse, pthread);
660 THR_SET_STATE(pthread, PS_RUNNING);
661 break;
662
663 case PS_SIGWAIT:
664 /*
665 * The signal handler is not called for threads in
666 * SIGWAIT.
667 */
668 suppress_handler = 1;
669 /* Wake up the thread if the signal is blocked. */
670 if (sigismember(pthread->data.sigwait, sig)) {
671 /* Return the signal number: */
672 pthread->signo = sig;
673
674 /* Make the thread runnable: */
675 _thr_setrunnable_unlocked(pthread);
676 } else
677 /* Increment the pending signal count. */
678 sigaddset(&pthread->sigpend, sig);
679 break;
680 }
681
682 if (suppress_handler == 0) {
683 /*
684 * Setup a signal frame and save the current threads
685 * state:
686 */
687 thr_sigframe_add(pthread, sig, info);
688
689 if (pthread->state != PS_RUNNING)
690 THR_SET_STATE(pthread, PS_RUNNING);
691
692 /*
693 * The thread should be removed from all scheduling
694 * queues at this point. Raise the priority and
695 * place the thread in the run queue. It is also
696 * possible for a signal to be sent to a suspended
697 * thread, mostly via pthread_kill(). If a thread
698 * is suspended, don't insert it into the priority
699 * queue; just set its state to suspended and it
700 * will run the signal handler when it is resumed.
701 */
702 pthread->active_priority |= THR_SIGNAL_PRIORITY;
703 if ((pthread->flags & THR_FLAGS_IN_RUNQ) == 0)
704 THR_RUNQ_INSERT_TAIL(pthread);
705 }
706 }
707}
708
709static void
710thr_sig_check_state(struct pthread *pthread, int sig)
711{
712 /*
713 * Process according to thread state:
714 */
715 switch (pthread->state) {
716 /*
717 * States which do not change when a signal is trapped:
718 */
719 case PS_RUNNING:
720 case PS_LOCKWAIT:
721 case PS_MUTEX_WAIT:
722 case PS_COND_WAIT:
723 case PS_JOIN:
724 case PS_SUSPENDED:
725 case PS_DEAD:
726 case PS_DEADLOCK:
727 case PS_STATE_MAX:
728 break;
729
730 case PS_SIGWAIT:
731 /* Wake up the thread if the signal is blocked. */
732 if (sigismember(pthread->data.sigwait, sig)) {
733 /* Return the signal number: */
734 pthread->signo = sig;
735
736 /* Change the state of the thread to run: */
737 _thr_setrunnable_unlocked(pthread);
738 } else
739 /* Increment the pending signal count. */
740 sigaddset(&pthread->sigpend, sig);
741 break;
742
743 case PS_SIGSUSPEND:
744 case PS_SLEEP_WAIT:
745 /*
746 * Remove the thread from the wait queue and make it
747 * runnable:
748 */
749 _thr_setrunnable_unlocked(pthread);
750
751 /* Flag the operation as interrupted: */
752 pthread->interrupted = 1;
753 break;
754 }
755}
756
757/*
758 * Send a signal to a specific thread (ala pthread_kill):
759 */
760void
761_thr_sig_send(struct pthread *pthread, int sig)
762{
763 struct pthread *curthread = _get_curthread();
764
765 /* Lock the scheduling queue of the target thread. */
766 THR_SCHED_LOCK(curthread, pthread);
767
768 /* Check for signals whose actions are SIG_DFL: */
769 if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) {
770 /*
771 * Check to see if a temporary signal handler is
772 * installed for sigwaiters:
773 */
774 if (_thread_dfl_count[sig] == 0) {
775 /*
776 * Deliver the signal to the process if a handler
777 * is not installed:
778 */
779 THR_SCHED_UNLOCK(curthread, pthread);
780 kill(getpid(), sig);
781 THR_SCHED_LOCK(curthread, pthread);
782 }
783 /*
784 * Assuming we're still running after the above kill(),
785 * make any necessary state changes to the thread:
786 */
787 thr_sig_check_state(pthread, sig);
788 THR_SCHED_UNLOCK(curthread, pthread);
789 }
790 /*
791 * Check that the signal is not being ignored:
792 */
793 else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
794 if (pthread->state == PS_SIGWAIT &&
795 sigismember(pthread->data.sigwait, sig)) {
796 /* Return the signal number: */
797 pthread->signo = sig;
798
799 /* Change the state of the thread to run: */
800 _thr_setrunnable_unlocked(pthread);
801 THR_SCHED_UNLOCK(curthread, pthread);
802 } else if (sigismember(&pthread->tmbx.tm_context.uc_sigmask, sig)) {
803 /* Add the signal to the pending set: */
804 sigaddset(&pthread->sigpend, sig);
805 THR_SCHED_UNLOCK(curthread, pthread);
806 } else if (pthread == curthread) {
807 ucontext_t uc;
808 siginfo_t info;
809 volatile int once;
810
811 THR_SCHED_UNLOCK(curthread, pthread);
812 build_siginfo(&info, sig);
813 once = 0;
814 THR_GETCONTEXT(&uc);
815 if (once == 0) {
816 once = 1;
817 /*
818 * Call the signal handler for the current
819 * thread:
820 */
821 thr_sig_invoke_handler(curthread, sig,
822 &info, &uc);
823 }
824 } else {
825 /*
826 * Perform any state changes due to signal
827 * arrival:
828 */
829 _thr_sig_add(pthread, sig, NULL);
830 THR_SCHED_UNLOCK(curthread, pthread);
831 }
832 }
833}
834
835static void
836thr_sigframe_add(struct pthread *thread, int sig, siginfo_t *info)
837{
838 if (thread->curframe == NULL)
839 PANIC("Thread doesn't have signal frame ");
840
841 if (thread->have_signals == 0) {
842 /*
843 * Multiple signals can be added to the same signal
844 * frame. Only save the thread's state the first time.
845 */
846 thr_sigframe_save(thread, thread->curframe);
847 thread->have_signals = 1;
848 thread->flags &= THR_FLAGS_PRIVATE;
849 }
850 sigaddset(&thread->curframe->psf_sigset, sig);
851 if (info == NULL)
852 build_siginfo(&thread->siginfo[sig], sig);
853 else if (info != &thread->siginfo[sig])
854 memcpy(&thread->siginfo[sig], info, sizeof(*info));
855
856 /* Setup the new signal mask. */
857 SIGSETOR(thread->tmbx.tm_context.uc_sigmask,
858 _thread_sigact[sig - 1].sa_mask);
859 sigaddset(&thread->tmbx.tm_context.uc_sigmask, sig);
860}
861
862void
863thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf)
864{
865 thread->flags = psf->psf_flags;
866 thread->interrupted = psf->psf_interrupted;
867 thread->signo = psf->psf_signo;
868 thread->state = psf->psf_state;
869 thread->data = psf->psf_wait_data;
870 thread->wakeup_time = psf->psf_wakeup_time;
871 if (thread->sigmask_seqno == psf->psf_seqno)
872 thread->tmbx.tm_context.uc_sigmask = psf->psf_sigmask;
873 else
874 thread->tmbx.tm_context.uc_sigmask = thread->sigmask;
875}
876
877static void
878thr_sigframe_save(struct pthread *thread, struct pthread_sigframe *psf)
879{
880 /* This has to initialize all members of the sigframe. */
881 psf->psf_flags = thread->flags & THR_FLAGS_PRIVATE;
882 psf->psf_interrupted = thread->interrupted;
883 psf->psf_signo = thread->signo;
884 psf->psf_state = thread->state;
885 psf->psf_wait_data = thread->data;
886 psf->psf_wakeup_time = thread->wakeup_time;
887 psf->psf_sigmask = thread->tmbx.tm_context.uc_sigmask;
888 psf->psf_seqno = thread->sigmask_seqno;
889 sigemptyset(&psf->psf_sigset);
890}