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 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
32 * $FreeBSD: src/lib/libc_r/uthread/uthread_sig.c,v 1.25.2.13 2002/10/22 14:44:03 fjoe Exp $
33 * $DragonFly: src/lib/libc_r/uthread/uthread_sig.c,v 1.6 2007/11/25 01:28:23 swildner Exp $
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/signalvar.h>
45 #include "pthread_private.h"
48 static void thread_sig_add(struct pthread
*pthread
, int sig
, int has_args
);
49 static void thread_sig_check_state(struct pthread
*pthread
, int sig
);
50 static struct pthread
*thread_sig_find(int sig
);
51 static void thread_sig_handle_special(int sig
);
52 static void thread_sigframe_add(struct pthread
*thread
, int sig
,
54 static void thread_sigframe_save(struct pthread
*thread
,
55 struct pthread_signal_frame
*psf
);
56 static void thread_sig_invoke_handler(int sig
, siginfo_t
*info
,
59 /*#define DEBUG_SIGNAL*/
61 #define DBG_MSG stdout_debug
66 #if defined(_PTHREADS_INVARIANTS)
67 #define SIG_SET_ACTIVE() _sig_in_handler = 1
68 #define SIG_SET_INACTIVE() _sig_in_handler = 0
70 #define SIG_SET_ACTIVE()
71 #define SIG_SET_INACTIVE()
75 _thread_sig_handler(int sig
, siginfo_t
*info
, ucontext_t
*ucp
)
77 struct pthread
*curthread
= _get_curthread();
78 struct pthread
*pthread
, *pthread_h
;
79 int in_sched
= _thread_kern_in_sched
;
83 PANIC("Thread signal handler received null context");
84 DBG_MSG("Got signal %d, current thread %p\n", sig
, curthread
);
86 /* Check if an interval timer signal: */
87 if (sig
== _SCHED_SIGNAL
) {
88 /* Update the scheduling clock: */
89 gettimeofday((struct timeval
*)&_sched_tod
, NULL
);
94 * The scheduler is already running; ignore this
99 * Check if the scheduler interrupt has come when
100 * the currently running thread has deferred thread
103 else if (curthread
->sig_defer_count
> 0)
104 curthread
->yield_on_sig_undefer
= 1;
106 /* Schedule the next thread: */
107 _thread_kern_sched(ucp
);
110 * This point should not be reached, so abort the
113 PANIC("Returned to signal function from scheduler");
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.
121 else if ((in_sched
!= 0) || (curthread
->sig_defer_count
> 0)) {
122 /* Cast the signal number to a character variable: */
126 * Write the signal number to the kernel pipe so that it will
127 * be ready to read when this signal handler returns.
129 if (_queue_signals
!= 0) {
130 __sys_extpwrite(_thread_kern_pipe
[1], &c
, 1, O_FBLOCKING
, -1);
131 DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig
);
133 if (_thread_sigq
[sig
- 1].blocked
== 0) {
134 DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig
);
136 * Do not block this signal; it will be blocked
137 * when the pending signals are run down.
139 /* _thread_sigq[sig - 1].blocked = 1; */
142 * Queue the signal, saving siginfo and sigcontext
145 * XXX - Do we need to copy siginfo and ucp?
147 _thread_sigq
[sig
- 1].signo
= sig
;
149 memcpy(&_thread_sigq
[sig
- 1].siginfo
, info
,
151 memcpy(&_thread_sigq
[sig
- 1].uc
, ucp
, sizeof(*ucp
));
153 /* Indicate that there are queued signals: */
154 _thread_sigq
[sig
- 1].pending
= 1;
155 _sigq_check_reqd
= 1;
157 /* These signals need special handling: */
158 else if (sig
== SIGCHLD
|| sig
== SIGTSTP
||
159 sig
== SIGTTIN
|| sig
== SIGTTOU
) {
160 _thread_sigq
[sig
- 1].pending
= 1;
161 _thread_sigq
[sig
- 1].signo
= sig
;
162 _sigq_check_reqd
= 1;
165 DBG_MSG("Got signal %d, ignored.\n", sig
);
168 * The signal handlers should have been installed so that they
169 * cannot be interrupted by other signals.
171 else if (_thread_sigq
[sig
- 1].blocked
== 0) {
173 * The signal is not blocked; handle the signal.
175 * Ignore subsequent occurrences of this signal
176 * until the current signal is handled:
178 _thread_sigq
[sig
- 1].blocked
= 1;
180 /* This signal will be handled; clear the pending flag: */
181 _thread_sigq
[sig
- 1].pending
= 0;
184 * Save siginfo and sigcontext (ucontext).
186 * XXX - Do we need to copy siginfo and ucp?
188 _thread_sigq
[sig
- 1].signo
= sig
;
191 memcpy(&_thread_sigq
[sig
- 1].siginfo
, info
,
193 memcpy(&_thread_sigq
[sig
- 1].uc
, ucp
, sizeof(*ucp
));
196 /* Handle special signals: */
197 thread_sig_handle_special(sig
);
200 if ((pthread
= thread_sig_find(sig
)) == NULL
)
201 DBG_MSG("No thread to handle signal %d\n", sig
);
202 else if (pthread
== curthread
) {
204 * Unblock the signal and restore the process signal
205 * mask in case we don't return from the handler:
207 _thread_sigq
[sig
- 1].blocked
= 0;
208 __sys_sigprocmask(SIG_SETMASK
, &_process_sigmask
, NULL
);
210 /* Call the signal handler for the current thread: */
211 thread_sig_invoke_handler(sig
, info
, ucp
);
214 * Set the process signal mask in the context; it
215 * could have changed by the handler.
217 ucp
->uc_sigmask
= _process_sigmask
;
219 /* Resume the interrupted thread: */
222 DBG_MSG("Got signal %d, adding frame to thread %p\n",
225 /* Setup the target thread to receive the signal: */
226 thread_sig_add(pthread
, sig
, /*has_args*/ 1);
228 /* Take a peek at the next ready to run thread: */
229 pthread_h
= PTHREAD_PRIOQ_FIRST();
230 DBG_MSG("Finished adding frame, head of prio list %p\n",
236 * Switch to a different context if the currently running
237 * thread takes a signal, or if another thread takes a
238 * signal and the currently running thread is not in a
241 if ((pthread_h
!= NULL
) &&
242 (pthread_h
->active_priority
> curthread
->active_priority
)) {
243 /* Enter the kernel scheduler: */
244 _thread_kern_sched(ucp
);
249 thread_sig_handle_special(sig
);
255 thread_sig_invoke_handler(int sig
, siginfo_t
*info
, ucontext_t
*ucp
)
257 struct pthread
*curthread
= _get_curthread();
258 void (*sigfunc
)(int, siginfo_t
*, void *);
260 sigset_t saved_sigmask
;
262 /* Invoke the signal handler without going through the scheduler:
264 DBG_MSG("Got signal %d, calling handler for current thread %p\n",
267 /* Save the threads signal mask: */
268 saved_sigmask
= curthread
->sigmask
;
269 saved_seqno
= curthread
->sigmask_seqno
;
271 /* Setup the threads signal mask: */
272 SIGSETOR(curthread
->sigmask
, _thread_sigact
[sig
- 1].sa_mask
);
273 sigaddset(&curthread
->sigmask
, sig
);
276 * Check that a custom handler is installed and if
277 * the signal is not blocked:
279 sigfunc
= _thread_sigact
[sig
- 1].sa_sigaction
;
280 if (((__sighandler_t
*)sigfunc
!= SIG_DFL
) &&
281 ((__sighandler_t
*)sigfunc
!= SIG_IGN
)) {
282 if (((_thread_sigact
[sig
- 1].sa_flags
& SA_SIGINFO
) != 0) ||
284 (*(sigfunc
))(sig
, info
, ucp
);
286 (*(sigfunc
))(sig
, (siginfo_t
*)(intptr_t)info
->si_code
, ucp
);
289 * Only restore the signal mask if it hasn't been changed by the
290 * application during invocation of the signal handler:
292 if (curthread
->sigmask_seqno
== saved_seqno
)
293 curthread
->sigmask
= saved_sigmask
;
297 * Find a thread that can handle the signal.
300 thread_sig_find(int sig
)
302 struct pthread
*curthread
= _get_curthread();
303 int handler_installed
;
304 struct pthread
*pthread
, *pthread_next
;
305 struct pthread
*suspended_thread
, *signaled_thread
;
307 DBG_MSG("Looking for thread to handle signal %d\n", sig
);
308 /* Check if the signal requires a dump of thread information: */
309 if (sig
== SIGINFO
) {
310 /* Dump thread information to file: */
313 /* Unblock this signal to allow further dumps: */
314 _thread_sigq
[sig
- 1].blocked
= 0;
316 /* Check if an interval timer signal: */
317 else if (sig
== _SCHED_SIGNAL
) {
319 * This shouldn't ever occur (should this panic?).
323 * Enter a loop to look for threads that have the signal
324 * unmasked. POSIX specifies that a thread in a sigwait
325 * will get the signal over any other threads. Second
326 * preference will be threads in in a sigsuspend. Third
327 * preference will be the current thread. If none of the
328 * above, then the signal is delivered to the first thread
329 * that is found. Note that if a custom handler is not
330 * installed, the signal only affects threads in sigwait.
332 suspended_thread
= NULL
;
333 if ((curthread
!= &_thread_kern_thread
) &&
334 !sigismember(&curthread
->sigmask
, sig
))
335 signaled_thread
= curthread
;
337 signaled_thread
= NULL
;
338 if ((_thread_sigact
[sig
- 1].sa_handler
== SIG_IGN
) ||
339 (_thread_sigact
[sig
- 1].sa_handler
== SIG_DFL
))
340 handler_installed
= 0;
342 handler_installed
= 1;
344 for (pthread
= TAILQ_FIRST(&_waitingq
);
345 pthread
!= NULL
; pthread
= pthread_next
) {
347 * Grab the next thread before possibly destroying
350 pthread_next
= TAILQ_NEXT(pthread
, pqe
);
352 if ((pthread
->state
== PS_SIGWAIT
) &&
353 sigismember(pthread
->data
.sigwait
, sig
)) {
354 /* Change the state of the thread to run: */
355 PTHREAD_NEW_STATE(pthread
,PS_RUNNING
);
357 * A signal handler is not invoked for threads
358 * in sigwait. Clear the blocked and pending
361 _thread_sigq
[sig
- 1].blocked
= 0;
362 _thread_sigq
[sig
- 1].pending
= 0;
364 /* Return the signal number: */
365 pthread
->signo
= sig
;
368 * POSIX doesn't doesn't specify which thread
369 * will get the signal if there are multiple
370 * waiters, so we give it to the first thread
373 * Do not attempt to deliver this signal
374 * to other threads and do not add the signal
375 * to the process pending set.
379 else if ((handler_installed
!= 0) &&
380 !sigismember(&pthread
->sigmask
, sig
) &&
381 ((pthread
->flags
& PTHREAD_FLAGS_SUSPENDED
) == 0)) {
382 if (pthread
->state
== PS_SIGSUSPEND
) {
383 if (suspended_thread
== NULL
)
384 suspended_thread
= pthread
;
385 } else if (signaled_thread
== NULL
)
386 signaled_thread
= pthread
;
391 * Only perform wakeups and signal delivery if there is a
392 * custom handler installed:
394 if (handler_installed
== 0) {
396 * There is no handler installed. Unblock the
397 * signal so that if a handler _is_ installed, any
398 * subsequent signals can be handled.
400 _thread_sigq
[sig
- 1].blocked
= 0;
403 * If we didn't find a thread in the waiting queue,
404 * check the all threads queue:
406 if (suspended_thread
== NULL
&&
407 signaled_thread
== NULL
) {
409 * Enter a loop to look for other threads
410 * capable of receiving the signal:
412 TAILQ_FOREACH(pthread
, &_thread_list
, tle
) {
413 if (!sigismember(&pthread
->sigmask
,
415 signaled_thread
= pthread
;
421 if (suspended_thread
== NULL
&&
422 signaled_thread
== NULL
)
424 * Add it to the set of signals pending
427 sigaddset(&_process_sigpending
, sig
);
430 * We only deliver the signal to one thread;
431 * give preference to the suspended thread:
433 if (suspended_thread
!= NULL
)
434 pthread
= suspended_thread
;
436 pthread
= signaled_thread
;
442 /* Returns nothing. */
447 _thread_sig_check_pending(struct pthread
*pthread
)
453 * Check if there are pending signals for the running
454 * thread or process that aren't blocked:
456 sigset
= pthread
->sigpend
;
457 SIGSETOR(sigset
, _process_sigpending
);
458 SIGSETNAND(sigset
, pthread
->sigmask
);
459 if (SIGNOTEMPTY(sigset
)) {
460 for (i
= 1; i
< NSIG
; i
++) {
461 if (sigismember(&sigset
, i
) != 0) {
462 if (sigismember(&pthread
->sigpend
, i
) != 0)
463 thread_sig_add(pthread
, i
,
466 thread_sig_add(pthread
, i
,
468 sigdelset(&_process_sigpending
, i
);
476 * This can only be called from the kernel scheduler. It assumes that
477 * all thread contexts are saved and that a signal frame can safely be
478 * added to any user thread.
481 _thread_sig_handle_pending(void)
483 struct pthread
*pthread
;
486 PTHREAD_ASSERT(_thread_kern_in_sched
!= 0,
487 "_thread_sig_handle_pending called from outside kernel schedule");
489 * Check the array of pending signals:
491 for (i
= 0; i
< NSIG
; i
++) {
492 if (_thread_sigq
[i
].pending
!= 0) {
493 /* This signal is no longer pending. */
494 _thread_sigq
[i
].pending
= 0;
496 sig
= _thread_sigq
[i
].signo
;
498 /* Some signals need special handling: */
499 thread_sig_handle_special(sig
);
501 if (_thread_sigq
[i
].blocked
== 0) {
503 * Block future signals until this one
506 _thread_sigq
[i
].blocked
= 1;
508 if ((pthread
= thread_sig_find(sig
)) != NULL
) {
510 * Setup the target thread to receive
513 thread_sig_add(pthread
, sig
,
522 thread_sig_handle_special(int sig
)
524 struct pthread
*pthread
, *pthread_next
;
530 * Go through the file list and set all files
531 * to non-blocking again in case the child
532 * set some of them to block. Sigh.
534 for (i
= 0; i
< _thread_dtablesize
; i
++) {
535 /* Check if this file is used: */
536 if (_thread_fd_table
[i
] != NULL
) {
538 * Set the file descriptor to non-blocking:
540 __sys_fcntl(i
, F_SETFL
,
541 _thread_fd_getflags(i
) | O_NONBLOCK
);
545 * Enter a loop to wake up all threads waiting
546 * for a process to complete:
548 for (pthread
= TAILQ_FIRST(&_waitingq
);
549 pthread
!= NULL
; pthread
= pthread_next
) {
551 * Grab the next thread before possibly
552 * destroying the link entry:
554 pthread_next
= TAILQ_NEXT(pthread
, pqe
);
557 * If this thread is waiting for a child
558 * process to complete, wake it up:
560 if (pthread
->state
== PS_WAIT_WAIT
) {
561 /* Make the thread runnable: */
562 PTHREAD_NEW_STATE(pthread
,PS_RUNNING
);
564 /* Return the signal number: */
565 pthread
->signo
= sig
;
571 * POSIX says that pending SIGCONT signals are
572 * discarded when one of these signals occurs.
578 * Enter a loop to discard pending SIGCONT
581 TAILQ_FOREACH(pthread
, &_thread_list
, tle
) {
582 sigdelset(&pthread
->sigpend
, SIGCONT
);
592 * Perform thread specific actions in response to a signal.
593 * This function is only called if there is a handler installed
594 * for the signal, and if the target thread has the signal
598 thread_sig_add(struct pthread
*pthread
, int sig
, int has_args
)
601 int suppress_handler
= 0;
602 int thread_is_active
= 0;
604 restart
= _thread_sigact
[sig
- 1].sa_flags
& SA_RESTART
;
606 /* Make sure this signal isn't still in the pending set: */
607 sigdelset(&pthread
->sigpend
, sig
);
610 * Process according to thread state:
612 switch (pthread
->state
) {
614 * States which do not change when a signal is trapped:
621 * You can't call a signal handler for threads in these
624 suppress_handler
= 1;
628 * States which do not need any cleanup handling when signals
633 * Remove the thread from the queue before changing its
636 if ((pthread
->flags
& PTHREAD_FLAGS_IN_PRIOQ
) != 0)
637 PTHREAD_PRIOQ_REMOVE(pthread
);
640 * This thread is running; avoid placing it in
643 thread_is_active
= 1;
650 /* Remove the thread from the workq and waitq: */
651 PTHREAD_WORKQ_REMOVE(pthread
);
652 PTHREAD_WAITQ_REMOVE(pthread
);
653 /* Make the thread runnable: */
654 PTHREAD_SET_STATE(pthread
, PS_RUNNING
);
658 /* The signal handler is not called for threads in SIGWAIT. */
659 suppress_handler
= 1;
660 /* Wake up the thread if the signal is blocked. */
661 if (sigismember(pthread
->data
.sigwait
, sig
)) {
662 /* Change the state of the thread to run: */
663 PTHREAD_NEW_STATE(pthread
, PS_RUNNING
);
665 /* Return the signal number: */
666 pthread
->signo
= sig
;
668 /* Increment the pending signal count. */
669 sigaddset(&pthread
->sigpend
, sig
);
673 * The wait state is a special case due to the handling of
677 if (sig
== SIGCHLD
) {
678 /* Change the state of the thread to run: */
679 PTHREAD_WAITQ_REMOVE(pthread
);
680 PTHREAD_SET_STATE(pthread
, PS_RUNNING
);
682 /* Return the signal number: */
683 pthread
->signo
= sig
;
687 * Mark the thread as interrupted only if the
688 * restart flag is not set on the signal action:
691 pthread
->interrupted
= 1;
692 PTHREAD_WAITQ_REMOVE(pthread
);
693 PTHREAD_SET_STATE(pthread
, PS_RUNNING
);
698 * States which cannot be interrupted but still require the
699 * signal handler to run:
704 * Remove the thread from the wait queue. It will
705 * be added back to the wait queue once all signal
706 * handlers have been invoked.
708 PTHREAD_WAITQ_REMOVE(pthread
);
713 * Remove the thread from the wait queue. It will
714 * be added back to the wait queue once all signal
715 * handlers have been invoked.
717 PTHREAD_WAITQ_REMOVE(pthread
);
718 /* Make the thread runnable: */
719 PTHREAD_SET_STATE(pthread
, PS_RUNNING
);
723 * States which are interruptible but may need to be removed
724 * from queues before any signal handler is called.
726 * XXX - We may not need to handle this condition, but will
727 * mark it as a potential problem.
732 pthread
->interrupted
= 1;
734 * Remove the thread from the wait queue. Our
735 * signal handler hook will remove this thread
736 * from the fd or file queue before invoking
737 * the actual handler.
739 PTHREAD_WAITQ_REMOVE(pthread
);
743 * States which are interruptible:
749 * Flag the operation as interrupted and
750 * set the state to running:
752 pthread
->interrupted
= 1;
753 PTHREAD_SET_STATE(pthread
, PS_RUNNING
);
755 PTHREAD_WORKQ_REMOVE(pthread
);
756 PTHREAD_WAITQ_REMOVE(pthread
);
763 * Unmasked signals always cause poll, select, and sleep
764 * to terminate early, regardless of SA_RESTART:
766 pthread
->interrupted
= 1;
767 /* Remove threads in poll and select from the workq: */
768 if ((pthread
->flags
& PTHREAD_FLAGS_IN_WORKQ
) != 0)
769 PTHREAD_WORKQ_REMOVE(pthread
);
770 PTHREAD_WAITQ_REMOVE(pthread
);
771 PTHREAD_SET_STATE(pthread
, PS_RUNNING
);
775 PTHREAD_WAITQ_REMOVE(pthread
);
776 PTHREAD_SET_STATE(pthread
, PS_RUNNING
);
780 if (suppress_handler
== 0) {
781 /* Setup a signal frame and save the current threads state: */
782 thread_sigframe_add(pthread
, sig
, has_args
);
785 * Signals are deferred until just before the threads
786 * signal handler is invoked:
788 pthread
->sig_defer_count
= 1;
790 /* Make sure the thread is runnable: */
791 if (pthread
->state
!= PS_RUNNING
)
792 PTHREAD_SET_STATE(pthread
, PS_RUNNING
);
794 * The thread should be removed from all scheduling
795 * queues at this point. Raise the priority and place
796 * the thread in the run queue. It is also possible
797 * for a signal to be sent to a suspended thread,
798 * mostly via pthread_kill(). If a thread is suspended,
799 * don't insert it into the priority queue; just set
800 * its state to suspended and it will run the signal
801 * handler when it is resumed.
803 pthread
->active_priority
|= PTHREAD_SIGNAL_PRIORITY
;
804 if ((pthread
->flags
& PTHREAD_FLAGS_SUSPENDED
) != 0)
805 PTHREAD_SET_STATE(pthread
, PS_SUSPENDED
);
806 else if (thread_is_active
== 0)
807 PTHREAD_PRIOQ_INSERT_TAIL(pthread
);
812 thread_sig_check_state(struct pthread
*pthread
, int sig
)
815 * Process according to thread state:
817 switch (pthread
->state
) {
819 * States which do not change when a signal is trapped:
834 /* Wake up the thread if the signal is blocked. */
835 if (sigismember(pthread
->data
.sigwait
, sig
)) {
836 /* Change the state of the thread to run: */
837 PTHREAD_NEW_STATE(pthread
, PS_RUNNING
);
839 /* Return the signal number: */
840 pthread
->signo
= sig
;
842 /* Increment the pending signal count. */
843 sigaddset(&pthread
->sigpend
, sig
);
847 * The wait state is a special case due to the handling of
851 if (sig
== SIGCHLD
) {
853 * Remove the thread from the wait queue and
856 PTHREAD_NEW_STATE(pthread
, PS_RUNNING
);
858 /* Return the signal number: */
859 pthread
->signo
= sig
;
868 * Remove the thread from the wait queue and make it
871 PTHREAD_NEW_STATE(pthread
, PS_RUNNING
);
873 /* Flag the operation as interrupted: */
874 pthread
->interrupted
= 1;
878 * These states are additionally in the work queue:
885 * Remove the thread from the wait and work queues, and
888 PTHREAD_WORKQ_REMOVE(pthread
);
889 PTHREAD_NEW_STATE(pthread
, PS_RUNNING
);
891 /* Flag the operation as interrupted: */
892 pthread
->interrupted
= 1;
898 * Send a signal to a specific thread (ala pthread_kill):
901 _thread_sig_send(struct pthread
*pthread
, int sig
)
903 struct pthread
*curthread
= _get_curthread();
905 /* Check for signals whose actions are SIG_DFL: */
906 if (_thread_sigact
[sig
- 1].sa_handler
== SIG_DFL
) {
908 * Check to see if a temporary signal handler is
909 * installed for sigwaiters:
911 if (_thread_dfl_count
[sig
] == 0)
913 * Deliver the signal to the process if a handler
918 * Assuming we're still running after the above kill(),
919 * make any necessary state changes to the thread:
921 thread_sig_check_state(pthread
, sig
);
924 * Check that the signal is not being ignored:
926 else if (_thread_sigact
[sig
- 1].sa_handler
!= SIG_IGN
) {
927 if (pthread
->state
== PS_SIGWAIT
&&
928 sigismember(pthread
->data
.sigwait
, sig
)) {
929 /* Change the state of the thread to run: */
930 PTHREAD_NEW_STATE(pthread
, PS_RUNNING
);
932 /* Return the signal number: */
933 pthread
->signo
= sig
;
934 } else if (sigismember(&pthread
->sigmask
, sig
))
935 /* Add the signal to the pending set: */
936 sigaddset(&pthread
->sigpend
, sig
);
937 else if (pthread
== curthread
)
938 /* Call the signal handler for the current thread: */
939 thread_sig_invoke_handler(sig
, NULL
, NULL
);
941 /* Protect the scheduling queues: */
942 _thread_kern_sig_defer();
944 * Perform any state changes due to signal
947 thread_sig_add(pthread
, sig
, /* has args */ 0);
948 /* Unprotect the scheduling queues: */
949 _thread_kern_sig_undefer();
955 * User thread signal handler wrapper.
957 * thread - current running thread
960 _thread_sig_wrapper(void)
962 struct pthread_signal_frame
*psf
;
963 struct pthread
*thread
= _get_curthread();
965 /* Get the current frame and state: */
966 psf
= thread
->curframe
;
967 thread
->curframe
= NULL
;
968 PTHREAD_ASSERT(psf
!= NULL
, "Invalid signal frame in signal handler");
971 * We're coming from the kernel scheduler; clear the in
974 _thread_kern_in_sched
= 0;
976 /* Check the threads previous state: */
977 if (psf
->saved_state
.psd_state
!= PS_RUNNING
) {
979 * Do a little cleanup handling for those threads in
980 * queues before calling the signal handler. Signals
981 * for these threads are temporarily blocked until
982 * after cleanup handling.
984 switch (psf
->saved_state
.psd_state
) {
987 _fd_lock_backout(thread
);
988 psf
->saved_state
.psd_state
= PS_RUNNING
;
992 _cond_wait_backout(thread
);
993 psf
->saved_state
.psd_state
= PS_RUNNING
;
997 _mutex_lock_backout(thread
);
998 psf
->saved_state
.psd_state
= PS_RUNNING
;
1006 /* Unblock the signal in case we don't return from the handler: */
1007 _thread_sigq
[psf
->signo
- 1].blocked
= 0;
1010 * Lower the priority before calling the handler in case
1011 * it never returns (longjmps back):
1013 thread
->active_priority
&= ~PTHREAD_SIGNAL_PRIORITY
;
1016 * Reenable interruptions without checking for the need to
1019 thread
->sig_defer_count
= 0;
1022 * Dispatch the signal via the custom signal handler:
1024 if (psf
->sig_has_args
== 0)
1025 thread_sig_invoke_handler(psf
->signo
, NULL
, NULL
);
1027 thread_sig_invoke_handler(psf
->signo
, &psf
->siginfo
, &psf
->uc
);
1030 * Call the kernel scheduler to safely restore the frame and
1031 * schedule the next thread:
1033 _thread_kern_sched_frame(psf
);
1037 thread_sigframe_add(struct pthread
*thread
, int sig
, int has_args
)
1039 struct pthread_signal_frame
*psf
= NULL
;
1040 unsigned long stackp
;
1042 /* Get the top of the threads stack: */
1043 stackp
= GET_STACK_JB(thread
->ctx
.jb
);
1046 * Leave a little space on the stack and round down to the
1047 * nearest aligned word:
1049 stackp
-= sizeof(double);
1052 /* Allocate room on top of the stack for a new signal frame: */
1053 stackp
-= sizeof(struct pthread_signal_frame
);
1055 psf
= (struct pthread_signal_frame
*) stackp
;
1057 /* Save the current context in the signal frame: */
1058 thread_sigframe_save(thread
, psf
);
1060 /* Set handler specific information: */
1061 psf
->sig_has_args
= has_args
;
1064 /* Copy the signal handler arguments to the signal frame: */
1065 memcpy(&psf
->uc
, &_thread_sigq
[psf
->signo
- 1].uc
,
1067 memcpy(&psf
->siginfo
, &_thread_sigq
[psf
->signo
- 1].siginfo
,
1068 sizeof(psf
->siginfo
));
1071 /* Setup the signal mask: */
1072 SIGSETOR(thread
->sigmask
, _thread_sigact
[sig
- 1].sa_mask
);
1073 sigaddset(&thread
->sigmask
, sig
);
1075 /* Set up the new frame: */
1076 thread
->curframe
= psf
;
1077 thread
->flags
&= PTHREAD_FLAGS_PRIVATE
| PTHREAD_FLAGS_TRACE
|
1078 PTHREAD_FLAGS_IN_SYNCQ
;
1080 * Set up the context:
1082 stackp
-= sizeof(double);
1083 _setjmp(thread
->ctx
.jb
);
1084 SET_STACK_JB(thread
->ctx
.jb
, stackp
);
1085 SET_RETURN_ADDR_JB(thread
->ctx
.jb
, _thread_sig_wrapper
);
1089 _thread_sigframe_restore(struct pthread
*thread
,
1090 struct pthread_signal_frame
*psf
)
1092 memcpy(&thread
->ctx
, &psf
->ctx
, sizeof(thread
->ctx
));
1094 * Only restore the signal mask if it hasn't been changed
1095 * by the application during invocation of the signal handler:
1097 if (thread
->sigmask_seqno
== psf
->saved_state
.psd_sigmask_seqno
)
1098 thread
->sigmask
= psf
->saved_state
.psd_sigmask
;
1099 thread
->curframe
= psf
->saved_state
.psd_curframe
;
1100 thread
->wakeup_time
= psf
->saved_state
.psd_wakeup_time
;
1101 thread
->data
= psf
->saved_state
.psd_wait_data
;
1102 thread
->state
= psf
->saved_state
.psd_state
;
1103 thread
->flags
= psf
->saved_state
.psd_flags
;
1104 thread
->interrupted
= psf
->saved_state
.psd_interrupted
;
1105 thread
->signo
= psf
->saved_state
.psd_signo
;
1106 thread
->sig_defer_count
= psf
->saved_state
.psd_sig_defer_count
;
1110 thread_sigframe_save(struct pthread
*thread
, struct pthread_signal_frame
*psf
)
1112 memcpy(&psf
->ctx
, &thread
->ctx
, sizeof(thread
->ctx
));
1113 psf
->saved_state
.psd_sigmask
= thread
->sigmask
;
1114 psf
->saved_state
.psd_curframe
= thread
->curframe
;
1115 psf
->saved_state
.psd_wakeup_time
= thread
->wakeup_time
;
1116 psf
->saved_state
.psd_wait_data
= thread
->data
;
1117 psf
->saved_state
.psd_state
= thread
->state
;
1118 psf
->saved_state
.psd_flags
= thread
->flags
&
1119 (PTHREAD_FLAGS_PRIVATE
| PTHREAD_FLAGS_TRACE
);
1120 psf
->saved_state
.psd_interrupted
= thread
->interrupted
;
1121 psf
->saved_state
.psd_sigmask_seqno
= thread
->sigmask_seqno
;
1122 psf
->saved_state
.psd_signo
= thread
->signo
;
1123 psf
->saved_state
.psd_sig_defer_count
= thread
->sig_defer_count
;