drm/i915: Set GPU freq to idle_freq initially
[dragonfly.git] / lib / libc_r / uthread / uthread_sig.c
blob9596b62380ee35296e2afdcbc199f975d18c7b26
1 /*
2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3 * All rights reserved.
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.
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.
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>
38 #include <signal.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <setjmp.h>
42 #include <errno.h>
43 #include <pthread.h>
44 #include <string.h>
45 #include "pthread_private.h"
47 /* Prototypes: */
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,
53 int has_args);
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,
57 ucontext_t *ucp);
59 /*#define DEBUG_SIGNAL*/
60 #ifdef DEBUG_SIGNAL
61 #define DBG_MSG stdout_debug
62 #else
63 #define DBG_MSG(x...)
64 #endif
66 #if defined(_PTHREADS_INVARIANTS)
67 #define SIG_SET_ACTIVE() _sig_in_handler = 1
68 #define SIG_SET_INACTIVE() _sig_in_handler = 0
69 #else
70 #define SIG_SET_ACTIVE()
71 #define SIG_SET_INACTIVE()
72 #endif
74 void
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;
80 char c;
82 if (ucp == NULL)
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);
90 _sched_ticks++;
92 if (in_sched != 0) {
94 * The scheduler is already running; ignore this
95 * signal.
99 * Check if the scheduler interrupt has come when
100 * the currently running thread has deferred thread
101 * signals.
103 else if (curthread->sig_defer_count > 0)
104 curthread->yield_on_sig_undefer = 1;
105 else {
106 /* Schedule the next thread: */
107 _thread_kern_sched(ucp);
110 * This point should not be reached, so abort the
111 * process:
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: */
123 c = sig;
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
143 * (ucontext).
145 * XXX - Do we need to copy siginfo and ucp?
147 _thread_sigq[sig - 1].signo = sig;
148 if (info != NULL)
149 memcpy(&_thread_sigq[sig - 1].siginfo, info,
150 sizeof(*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;
164 else
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;
190 if (info != NULL)
191 memcpy(&_thread_sigq[sig - 1].siginfo, info,
192 sizeof(*info));
193 memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
194 SIG_SET_ACTIVE();
196 /* Handle special signals: */
197 thread_sig_handle_special(sig);
199 pthread_h = NULL;
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: */
220 sigreturn(ucp);
221 } else {
222 DBG_MSG("Got signal %d, adding frame to thread %p\n",
223 sig, pthread);
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",
231 pthread_h);
233 SIG_SET_INACTIVE();
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
239 * signal handler.
241 if ((pthread_h != NULL) &&
242 (pthread_h->active_priority > curthread->active_priority)) {
243 /* Enter the kernel scheduler: */
244 _thread_kern_sched(ucp);
247 else {
248 SIG_SET_ACTIVE();
249 thread_sig_handle_special(sig);
250 SIG_SET_INACTIVE();
254 static void
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 *);
259 int saved_seqno;
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",
265 sig, curthread);
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) ||
283 (info == NULL))
284 (*(sigfunc))(sig, info, ucp);
285 else
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.
299 struct pthread *
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: */
311 _thread_dump_info();
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?).
321 } else {
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;
336 else
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;
341 else
342 handler_installed = 1;
344 for (pthread = TAILQ_FIRST(&_waitingq);
345 pthread != NULL; pthread = pthread_next) {
347 * Grab the next thread before possibly destroying
348 * the link entry.
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
359 * flags.
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
371 * we find.
373 * Do not attempt to deliver this signal
374 * to other threads and do not add the signal
375 * to the process pending set.
377 return (NULL);
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;
401 } else {
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,
414 sig)) {
415 signaled_thread = pthread;
416 break;
421 if (suspended_thread == NULL &&
422 signaled_thread == NULL)
424 * Add it to the set of signals pending
425 * on the process:
427 sigaddset(&_process_sigpending, sig);
428 else {
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;
435 else
436 pthread = signaled_thread;
437 return (pthread);
442 /* Returns nothing. */
443 return (NULL);
446 void
447 _thread_sig_check_pending(struct pthread *pthread)
449 sigset_t sigset;
450 int i;
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,
464 /*has_args*/ 0);
465 else {
466 thread_sig_add(pthread, i,
467 /*has_args*/ 1);
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.
480 void
481 _thread_sig_handle_pending(void)
483 struct pthread *pthread;
484 int i, sig;
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
504 * is handled:
506 _thread_sigq[i].blocked = 1;
508 if ((pthread = thread_sig_find(sig)) != NULL) {
510 * Setup the target thread to receive
511 * the signal:
513 thread_sig_add(pthread, sig,
514 /*has_args*/ 1);
521 static void
522 thread_sig_handle_special(int sig)
524 struct pthread *pthread, *pthread_next;
525 int i;
527 switch (sig) {
528 case SIGCHLD:
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;
568 break;
571 * POSIX says that pending SIGCONT signals are
572 * discarded when one of these signals occurs.
574 case SIGTSTP:
575 case SIGTTIN:
576 case SIGTTOU:
578 * Enter a loop to discard pending SIGCONT
579 * signals:
581 TAILQ_FOREACH(pthread, &_thread_list, tle) {
582 sigdelset(&pthread->sigpend, SIGCONT);
584 break;
586 default:
587 break;
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
595 * unmasked.
597 static void
598 thread_sig_add(struct pthread *pthread, int sig, int has_args)
600 int restart;
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:
616 case PS_DEAD:
617 case PS_DEADLOCK:
618 case PS_STATE_MAX:
619 case PS_SIGTHREAD:
621 * You can't call a signal handler for threads in these
622 * states.
624 suppress_handler = 1;
625 break;
628 * States which do not need any cleanup handling when signals
629 * occur:
631 case PS_RUNNING:
633 * Remove the thread from the queue before changing its
634 * priority:
636 if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0)
637 PTHREAD_PRIOQ_REMOVE(pthread);
638 else
640 * This thread is running; avoid placing it in
641 * the run queue:
643 thread_is_active = 1;
644 break;
646 case PS_SUSPENDED:
647 break;
649 case PS_SPINBLOCK:
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);
655 break;
657 case PS_SIGWAIT:
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;
667 } else
668 /* Increment the pending signal count. */
669 sigaddset(&pthread->sigpend, sig);
670 break;
673 * The wait state is a special case due to the handling of
674 * SIGCHLD signals.
676 case PS_WAIT_WAIT:
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;
685 else {
687 * Mark the thread as interrupted only if the
688 * restart flag is not set on the signal action:
690 if (restart == 0)
691 pthread->interrupted = 1;
692 PTHREAD_WAITQ_REMOVE(pthread);
693 PTHREAD_SET_STATE(pthread, PS_RUNNING);
695 break;
698 * States which cannot be interrupted but still require the
699 * signal handler to run:
701 case PS_COND_WAIT:
702 case PS_MUTEX_WAIT:
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);
709 break;
711 case PS_JOIN:
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);
720 break;
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.
729 case PS_FDLR_WAIT:
730 case PS_FDLW_WAIT:
731 if (restart == 0)
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);
740 break;
743 * States which are interruptible:
745 case PS_FDR_WAIT:
746 case PS_FDW_WAIT:
747 if (restart == 0) {
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);
757 break;
759 case PS_POLL_WAIT:
760 case PS_SELECT_WAIT:
761 case PS_SLEEP_WAIT:
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);
772 break;
774 case PS_SIGSUSPEND:
775 PTHREAD_WAITQ_REMOVE(pthread);
776 PTHREAD_SET_STATE(pthread, PS_RUNNING);
777 break;
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);
811 static void
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:
821 case PS_DEAD:
822 case PS_DEADLOCK:
823 case PS_STATE_MAX:
824 case PS_SIGTHREAD:
825 case PS_RUNNING:
826 case PS_SUSPENDED:
827 case PS_SPINBLOCK:
828 case PS_COND_WAIT:
829 case PS_JOIN:
830 case PS_MUTEX_WAIT:
831 break;
833 case PS_SIGWAIT:
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;
841 } else
842 /* Increment the pending signal count. */
843 sigaddset(&pthread->sigpend, sig);
844 break;
847 * The wait state is a special case due to the handling of
848 * SIGCHLD signals.
850 case PS_WAIT_WAIT:
851 if (sig == SIGCHLD) {
853 * Remove the thread from the wait queue and
854 * make it runnable:
856 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
858 /* Return the signal number: */
859 pthread->signo = sig;
861 break;
863 case PS_FDLR_WAIT:
864 case PS_FDLW_WAIT:
865 case PS_SIGSUSPEND:
866 case PS_SLEEP_WAIT:
868 * Remove the thread from the wait queue and make it
869 * runnable:
871 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
873 /* Flag the operation as interrupted: */
874 pthread->interrupted = 1;
875 break;
878 * These states are additionally in the work queue:
880 case PS_FDR_WAIT:
881 case PS_FDW_WAIT:
882 case PS_POLL_WAIT:
883 case PS_SELECT_WAIT:
885 * Remove the thread from the wait and work queues, and
886 * make it runnable:
888 PTHREAD_WORKQ_REMOVE(pthread);
889 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
891 /* Flag the operation as interrupted: */
892 pthread->interrupted = 1;
893 break;
898 * Send a signal to a specific thread (ala pthread_kill):
900 void
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
914 * is not installed:
916 kill(getpid(), sig);
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);
940 else {
941 /* Protect the scheduling queues: */
942 _thread_kern_sig_defer();
944 * Perform any state changes due to signal
945 * arrival:
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
959 void
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
972 * scheduler flag:
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) {
985 case PS_FDLR_WAIT:
986 case PS_FDLW_WAIT:
987 _fd_lock_backout(thread);
988 psf->saved_state.psd_state = PS_RUNNING;
989 break;
991 case PS_COND_WAIT:
992 _cond_wait_backout(thread);
993 psf->saved_state.psd_state = PS_RUNNING;
994 break;
996 case PS_MUTEX_WAIT:
997 _mutex_lock_backout(thread);
998 psf->saved_state.psd_state = PS_RUNNING;
999 break;
1001 default:
1002 break;
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
1017 * context switch:
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);
1026 else
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);
1036 static void
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);
1050 stackp &= ~0x3UL;
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;
1062 psf->signo = sig;
1063 if (has_args) {
1064 /* Copy the signal handler arguments to the signal frame: */
1065 memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc,
1066 sizeof(psf->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);
1088 void
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;
1109 static void
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;