]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libc_r/uthread/uthread_sig.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libc_r / uthread / uthread_sig.c
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. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/signalvar.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <setjmp.h>
39 #include <string.h>
40 #include <pthread.h>
41 #include "pthread_private.h"
42
43 /* Prototypes: */
44 static void     thread_sig_add(struct pthread *pthread, int sig, int has_args);
45 static void     thread_sig_check_state(struct pthread *pthread, int sig);
46 static struct pthread *thread_sig_find(int sig);
47 static void     thread_sig_handle_special(int sig);
48 static void     thread_sigframe_add(struct pthread *thread, int sig,
49                     int has_args);
50 static void     thread_sigframe_save(struct pthread *thread,
51                     struct pthread_signal_frame *psf);
52 static void     thread_sig_invoke_handler(int sig, siginfo_t *info,
53                     ucontext_t *ucp, int unblock);
54
55 /*#define DEBUG_SIGNAL*/
56 #ifdef DEBUG_SIGNAL
57 #define DBG_MSG         stdout_debug
58 #else
59 #define DBG_MSG(x...)
60 #endif
61
62 #if defined(_PTHREADS_INVARIANTS)
63 #define SIG_SET_ACTIVE()        _sig_in_handler = 1
64 #define SIG_SET_INACTIVE()      _sig_in_handler = 0
65 #else
66 #define SIG_SET_ACTIVE()
67 #define SIG_SET_INACTIVE()
68 #endif
69
70 void
71 _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
72 {
73         struct pthread  *curthread = _get_curthread();
74         struct pthread  *pthread, *pthread_h;
75         int             in_sched = _thread_kern_in_sched;
76         char            c;
77         sigset_t        sigset;
78
79         if (ucp == NULL)
80                 PANIC("Thread signal handler received null context");
81         DBG_MSG("Got signal %d, current thread %p\n", sig, curthread);
82
83         /* Check if an interval timer signal: */
84         if (sig == _SCHED_SIGNAL) {
85                 /* Update the scheduling clock: */
86                 gettimeofday((struct timeval *)&_sched_tod, NULL);
87                 _sched_ticks++;
88
89                 if (in_sched != 0) {
90                         /*
91                          * The scheduler is already running; ignore this
92                          * signal.
93                          */
94                 }
95                 /*
96                  * Check if the scheduler interrupt has come when
97                  * the currently running thread has deferred thread
98                  * signals.
99                  */
100                 else if (curthread->sig_defer_count > 0)
101                         curthread->yield_on_sig_undefer = 1;
102                 else {
103                         /* Schedule the next thread: */
104                         _thread_kern_sched(ucp);
105
106                         /*
107                          * This point should not be reached, so abort the
108                          * process:
109                          */
110                         PANIC("Returned to signal function from scheduler");
111                 }
112         }
113         /*
114          * Check if the kernel has been interrupted while the scheduler
115          * is accessing the scheduling queues or if there is a currently
116          * running thread that has deferred signals.
117          */
118         else if ((in_sched != 0) || (curthread->sig_defer_count > 0)) {
119                 /* Cast the signal number to a character variable: */
120                 c = sig;
121
122                 /*
123                  * Write the signal number to the kernel pipe so that it will
124                  * be ready to read when this signal handler returns.
125                  */
126                 if (_queue_signals != 0) {
127                         ssize_t wgot;
128                         do {
129                                 wgot = __sys_write(_thread_kern_pipe[1], &c,
130                                                    1);
131                         } while (wgot < 0 && errno == EINTR);
132                         if (wgot < 0 && errno != EAGAIN) {
133                                 PANIC("Failed to queue signal");
134                         }
135                         DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig);
136                 }
137                 if (_thread_sigq[sig - 1].blocked == 0) {
138                         DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig);
139                         /*
140                          * Do not block this signal; it will be blocked
141                          * when the pending signals are run down.
142                          */
143                         /* _thread_sigq[sig - 1].blocked = 1; */
144
145                         /*
146                          * Queue the signal, saving siginfo and sigcontext
147                          * (ucontext).
148                          *
149                          * XXX - Do we need to copy siginfo and ucp?
150                          */
151                         _thread_sigq[sig - 1].signo = sig;
152                         if (info != NULL)
153                                 memcpy(&_thread_sigq[sig - 1].siginfo, info,
154                                     sizeof(*info));
155                         memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
156
157                         /* Indicate that there are queued signals: */
158                         _thread_sigq[sig - 1].pending = 1;
159                         _sigq_check_reqd = 1;
160                 }
161                 /* These signals need special handling: */
162                 else if (sig == SIGCHLD || sig == SIGTSTP ||
163                     sig == SIGTTIN || sig == SIGTTOU) {
164                         _thread_sigq[sig - 1].pending = 1;
165                         _thread_sigq[sig - 1].signo = sig;
166                         _sigq_check_reqd = 1;
167                 }
168                 else
169                         DBG_MSG("Got signal %d, ignored.\n", sig);
170         }
171         /*
172          * The signal handlers should have been installed so that they
173          * cannot be interrupted by other signals.
174          */
175         else if (_thread_sigq[sig - 1].blocked == 0) {
176                 /*
177                  * The signal is not blocked; handle the signal.
178                  *
179                  * Ignore subsequent occurrences of this signal
180                  * until the current signal is handled:
181                  */
182                 _thread_sigq[sig - 1].blocked = 1;
183
184                 /* This signal will be handled; clear the pending flag: */
185                 _thread_sigq[sig - 1].pending = 0;
186
187                 /*
188                  * Save siginfo and sigcontext (ucontext).
189                  *
190                  * XXX - Do we need to copy siginfo and ucp?
191                  */
192                 _thread_sigq[sig - 1].signo = sig;
193
194                 if (info != NULL)
195                         memcpy(&_thread_sigq[sig - 1].siginfo, info,
196                             sizeof(*info));
197                 memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
198                 SIG_SET_ACTIVE();
199
200                 /* Handle special signals: */
201                 thread_sig_handle_special(sig);
202
203                 pthread_h = NULL;
204                 if ((pthread = thread_sig_find(sig)) == NULL)
205                         DBG_MSG("No thread to handle signal %d\n", sig);
206                 else if (pthread == curthread) {
207                         /* Call the signal handler for the current thread: */
208                         thread_sig_invoke_handler(sig, info, ucp, 2);
209
210                         /*
211                          * Set the process signal mask in the context; it
212                          * could have changed by the handler.
213                          */
214                         ucp->uc_sigmask = _process_sigmask;
215  
216                         /*
217                          * The signal mask was restored; check for any
218                          * pending signals: 
219                          */
220                         sigset = curthread->sigpend;
221                         SIGSETOR(sigset, _process_sigpending);
222                         SIGSETNAND(sigset, curthread->sigmask);
223                         if (SIGNOTEMPTY(sigset))
224                                 curthread->check_pending = 1;
225
226                         /* Resume the interrupted thread: */
227                         __sys_sigreturn(ucp);
228                 } else {
229                         DBG_MSG("Got signal %d, adding frame to thread %p\n",
230                             sig, pthread);
231
232                         /* Setup the target thread to receive the signal: */
233                         thread_sig_add(pthread, sig, /*has_args*/ 1);
234
235                         /* Take a peek at the next ready to run thread: */
236                         pthread_h = PTHREAD_PRIOQ_FIRST();
237                         DBG_MSG("Finished adding frame, head of prio list %p\n",
238                             pthread_h);
239                 }
240                 SIG_SET_INACTIVE();
241
242                 /*
243                  * Switch to a different context if the currently running
244                  * thread takes a signal, or if another thread takes a
245                  * signal and the currently running thread is not in a
246                  * signal handler.
247                  */
248                 if ((pthread_h != NULL) &&
249                     (pthread_h->active_priority > curthread->active_priority)) {
250                         /* Enter the kernel scheduler: */
251                         _thread_kern_sched(ucp);
252                 }
253         }
254         else {
255                 SIG_SET_ACTIVE();
256                 thread_sig_handle_special(sig);
257                 SIG_SET_INACTIVE();
258         }
259 }
260
261 static void
262 thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp,
263                           int unblock)
264  {
265         struct pthread  *curthread = _get_curthread();
266         void (*sigfunc)(int, siginfo_t *, void *);
267         int             saved_seqno;
268         sigset_t        saved_sigmask;
269
270         /* Invoke the signal handler without going through the scheduler:
271          */
272         DBG_MSG("Got signal %d, calling handler for current thread %p\n",
273             sig, curthread);
274
275         /* Save the threads signal mask: */
276         saved_sigmask = curthread->sigmask;
277         saved_seqno = curthread->sigmask_seqno;
278  
279         /* Setup the threads signal mask: */
280         SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
281         sigaddset(&curthread->sigmask, sig);
282  
283         if (unblock > 0) {
284                 /*
285                  * Unblock the signal and restore the process signal
286                  * mask in case we don't return from the handler:
287                  */
288                 _thread_sigq[sig - 1].blocked = 0;
289                 if (unblock > 1)
290                         __sys_sigprocmask(SIG_SETMASK, &_process_sigmask,
291                                           NULL);
292         }
293
294         /*
295          * Check that a custom handler is installed and if
296          * the signal is not blocked:
297          */
298         sigfunc = _thread_sigact[sig - 1].sa_sigaction;
299         if (((__sighandler_t *)sigfunc != SIG_DFL) &&
300             ((__sighandler_t *)sigfunc != SIG_IGN)) {
301                 if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) ||
302                     (info == NULL))
303                         (*(sigfunc))(sig, info, ucp);
304                 else
305                         (*(sigfunc))(sig, (void*)(intptr_t)info->si_code, ucp);
306         }
307         /*
308          * Only restore the signal mask if it hasn't been changed by the
309          * application during invocation of the signal handler:
310          */
311         if (curthread->sigmask_seqno == saved_seqno)
312                 curthread->sigmask = saved_sigmask;
313 }
314
315 /*
316  * Find a thread that can handle the signal.
317  */
318 struct pthread *
319 thread_sig_find(int sig)
320 {
321         struct pthread  *curthread = _get_curthread();
322         int             handler_installed;
323         struct pthread  *pthread, *pthread_next;
324         struct pthread  *suspended_thread, *signaled_thread;
325
326         DBG_MSG("Looking for thread to handle signal %d\n", sig);
327         /* Check if the signal requires a dump of thread information: */
328         if (sig == SIGINFO) {
329                 /* Dump thread information to file: */
330                 _thread_dump_info();
331
332                 /* Unblock this signal to allow further dumps: */
333                 _thread_sigq[sig - 1].blocked = 0;
334         }
335         /* Check if an interval timer signal: */
336         else if (sig == _SCHED_SIGNAL) {
337                 /*
338                  * This shouldn't ever occur (should this panic?).
339                  */
340         } else {
341                 /*
342                  * Enter a loop to look for threads that have the signal
343                  * unmasked.  POSIX specifies that a thread in a sigwait
344                  * will get the signal over any other threads.  Second
345                  * preference will be threads in a sigsuspend.  Third
346                  * preference will be the current thread.  If none of the
347                  * above, then the signal is delivered to the first thread
348                  * that is found.  Note that if a custom handler is not
349                  * installed, the signal only affects threads in sigwait.
350                  */
351                 suspended_thread = NULL;
352                 if ((curthread != &_thread_kern_thread) &&
353                     !sigismember(&curthread->sigmask, sig))
354                         signaled_thread = curthread;
355                 else
356                         signaled_thread = NULL;
357                 if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) ||
358                     (_thread_sigact[sig - 1].sa_handler == SIG_DFL))
359                         handler_installed = 0;
360                 else
361                         handler_installed = 1;
362
363                 for (pthread = TAILQ_FIRST(&_waitingq);
364                     pthread != NULL; pthread = pthread_next) {
365                         /*
366                          * Grab the next thread before possibly destroying
367                          * the link entry.
368                          */
369                         pthread_next = TAILQ_NEXT(pthread, pqe);
370
371                         if ((pthread->state == PS_SIGWAIT) &&
372                             sigismember(pthread->data.sigwait, sig)) {
373                                 /* Change the state of the thread to run: */
374                                 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
375                                 /*
376                                  * A signal handler is not invoked for threads
377                                  * in sigwait.  Clear the blocked and pending
378                                  * flags.
379                                  */
380                                 _thread_sigq[sig - 1].blocked = 0;
381                                 _thread_sigq[sig - 1].pending = 0;
382
383                                 /* Return the signal number: */
384                                 pthread->signo = sig;
385
386                                 /*
387                                  * POSIX doesn't doesn't specify which thread
388                                  * will get the signal if there are multiple
389                                  * waiters, so we give it to the first thread
390                                  * we find.
391                                  *
392                                  * Do not attempt to deliver this signal
393                                  * to other threads and do not add the signal
394                                  * to the process pending set.
395                                  */
396                                 return (NULL);
397                         }
398                         else if ((handler_installed != 0) &&
399                             !sigismember(&pthread->sigmask, sig) &&
400                             ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) {
401                                 if (pthread->state == PS_SIGSUSPEND) {
402                                         if (suspended_thread == NULL)
403                                                 suspended_thread = pthread;
404                                 } else if (signaled_thread == NULL)
405                                         signaled_thread = pthread;
406                         }
407                 }
408
409                 /*
410                  * Only perform wakeups and signal delivery if there is a
411                  * custom handler installed:
412                  */
413                 if (handler_installed == 0) {
414                         /*
415                          * There is no handler installed.  Unblock the
416                          * signal so that if a handler _is_ installed, any
417                          * subsequent signals can be handled.
418                          */
419                         _thread_sigq[sig - 1].blocked = 0;
420                 } else {
421                         /*
422                          * If we didn't find a thread in the waiting queue,
423                          * check the all threads queue:
424                          */
425                         if (suspended_thread == NULL &&
426                             signaled_thread == NULL) {
427                                 /*
428                                  * Enter a loop to look for other threads
429                                  * capable of receiving the signal:
430                                  */
431                                 TAILQ_FOREACH(pthread, &_thread_list, tle) {
432                                         if (!sigismember(&pthread->sigmask,
433                                             sig)) {
434                                                 signaled_thread = pthread;
435                                                 break;
436                                         }
437                                 }
438                         }
439
440                         if (suspended_thread == NULL &&
441                             signaled_thread == NULL)
442                                 /*
443                                  * Add it to the set of signals pending
444                                  * on the process:
445                                  */
446                                 sigaddset(&_process_sigpending, sig);
447                         else {
448                                 /*
449                                  * We only deliver the signal to one thread;
450                                  * give preference to the suspended thread:
451                                  */
452                                 if (suspended_thread != NULL)
453                                         pthread = suspended_thread;
454                                 else
455                                         pthread = signaled_thread;
456                                 return (pthread);
457                         }
458                 }
459         }
460
461         /* Returns nothing. */
462         return (NULL);
463 }
464
465 void
466 _thread_sig_check_pending(struct pthread *pthread)
467 {
468         sigset_t        sigset;
469         int             i;
470
471         /*
472          * Check if there are pending signals for the running
473          * thread or process that aren't blocked:
474          */
475         sigset = pthread->sigpend;
476         SIGSETOR(sigset, _process_sigpending);
477         SIGSETNAND(sigset, pthread->sigmask);
478         if (SIGNOTEMPTY(sigset)) {
479                 for (i = 1; i < NSIG; i++) {
480                         if (sigismember(&sigset, i) != 0) {
481                                 if (sigismember(&pthread->sigpend, i) != 0)
482                                         thread_sig_add(pthread, i,
483                                             /*has_args*/ 0);
484                                 else {
485                                         thread_sig_add(pthread, i,
486                                             /*has_args*/ 1);
487                                         sigdelset(&_process_sigpending, i);
488                                 }
489                         }
490                 }
491         }
492 }
493
494 /*
495  * This can only be called from the kernel scheduler.  It assumes that
496  * all thread contexts are saved and that a signal frame can safely be
497  * added to any user thread.
498  */
499 void
500 _thread_sig_handle_pending(void)
501 {
502         struct pthread  *pthread;
503         int             i, sig;
504
505         PTHREAD_ASSERT(_thread_kern_in_sched != 0,
506             "_thread_sig_handle_pending called from outside kernel schedule");
507         /*
508          * Check the array of pending signals:
509          */
510         for (i = 0; i < NSIG; i++) {
511                 if (_thread_sigq[i].pending != 0) {
512                         /* This signal is no longer pending. */
513                         _thread_sigq[i].pending = 0;
514
515                         sig = _thread_sigq[i].signo;
516
517                         /* Some signals need special handling: */
518                         thread_sig_handle_special(sig);
519
520                         if (_thread_sigq[i].blocked == 0) {
521                                 /*
522                                  * Block future signals until this one
523                                  * is handled:
524                                  */
525                                 _thread_sigq[i].blocked = 1;
526
527                                 if ((pthread = thread_sig_find(sig)) != NULL) {
528                                         /*
529                                          * Setup the target thread to receive
530                                          * the signal:
531                                          */
532                                         thread_sig_add(pthread, sig,
533                                             /*has_args*/ 1);
534                                 }
535                         }
536                 }
537         }
538 }
539
540 static void
541 thread_sig_handle_special(int sig)
542 {
543         struct pthread  *pthread, *pthread_next;
544         int             i;
545
546         switch (sig) {
547         case SIGCHLD:
548                 /*
549                  * Go through the file list and set all files
550                  * to non-blocking again in case the child
551                  * set some of them to block. Sigh.
552                  */
553                 for (i = 0; i < _thread_dtablesize; i++) {
554                         /* Check if this file is used: */
555                         if (_thread_fd_table[i] != NULL) {
556                                 /*
557                                  * Set the file descriptor to non-blocking:
558                                  */
559                                 __sys_fcntl(i, F_SETFL,
560                                     _thread_fd_getflags(i) | O_NONBLOCK);
561                         }
562                 }
563                 /*
564                  * Enter a loop to wake up all threads waiting
565                  * for a process to complete:
566                  */
567                 for (pthread = TAILQ_FIRST(&_waitingq);
568                     pthread != NULL; pthread = pthread_next) {
569                         /*
570                          * Grab the next thread before possibly
571                          * destroying the link entry:
572                          */
573                         pthread_next = TAILQ_NEXT(pthread, pqe);
574
575                         /*
576                          * If this thread is waiting for a child
577                          * process to complete, wake it up:
578                          */
579                         if (pthread->state == PS_WAIT_WAIT) {
580                                 /* Make the thread runnable: */
581                                 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
582
583                                 /* Return the signal number: */
584                                 pthread->signo = sig;
585                         }
586                 }
587                 break;
588
589         /*
590          * POSIX says that pending SIGCONT signals are
591          * discarded when one of these signals occurs.
592          */
593         case SIGTSTP:
594         case SIGTTIN:
595         case SIGTTOU:
596                 /*
597                  * Enter a loop to discard pending SIGCONT
598                  * signals:
599                  */
600                 TAILQ_FOREACH(pthread, &_thread_list, tle) {
601                         sigdelset(&pthread->sigpend, SIGCONT);
602                 }
603                 break;
604
605         default:
606                 break;
607         }
608 }
609
610 /*
611  * Perform thread specific actions in response to a signal.
612  * This function is only called if there is a handler installed
613  * for the signal, and if the target thread has the signal
614  * unmasked.
615  */
616 static void
617 thread_sig_add(struct pthread *pthread, int sig, int has_args)
618 {
619         int     restart;
620         int     suppress_handler = 0;
621         int     thread_is_active = 0;
622
623         restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
624
625         /* Make sure this signal isn't still in the pending set: */
626         sigdelset(&pthread->sigpend, sig);
627
628         /*
629          * Process according to thread state:
630          */
631         switch (pthread->state) {
632         /*
633          * States which do not change when a signal is trapped:
634          */
635         case PS_DEAD:
636         case PS_DEADLOCK:
637         case PS_STATE_MAX:
638         case PS_SIGTHREAD:
639                 /*
640                  * You can't call a signal handler for threads in these
641                  * states.
642                  */
643                 suppress_handler = 1;
644                 break;
645
646         /*
647          * States which do not need any cleanup handling when signals
648          * occur:
649          */
650         case PS_RUNNING:
651                 /*
652                  * Remove the thread from the queue before changing its
653                  * priority:
654                  */
655                 if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0)
656                         PTHREAD_PRIOQ_REMOVE(pthread);
657                 else
658                         /*
659                          * This thread is running; avoid placing it in
660                          * the run queue:
661                          */
662                         thread_is_active = 1;
663                 break;
664
665         case PS_SUSPENDED:
666                 break;
667
668         case PS_SPINBLOCK:
669                 /* Remove the thread from the workq and waitq: */
670                 PTHREAD_WORKQ_REMOVE(pthread);
671                 PTHREAD_WAITQ_REMOVE(pthread);
672                 /* Make the thread runnable: */
673                 PTHREAD_SET_STATE(pthread, PS_RUNNING);
674                 break;
675
676         case PS_SIGWAIT:
677                 /* The signal handler is not called for threads in SIGWAIT. */
678                 suppress_handler = 1;
679                 /* Wake up the thread if the signal is blocked. */
680                 if (sigismember(pthread->data.sigwait, sig)) {
681                         /* Change the state of the thread to run: */
682                         PTHREAD_NEW_STATE(pthread, PS_RUNNING);
683
684                         /* Return the signal number: */
685                         pthread->signo = sig;
686                 } else
687                         /* Increment the pending signal count. */
688                         sigaddset(&pthread->sigpend, sig);
689                 break;
690
691         /*
692          * The wait state is a special case due to the handling of
693          * SIGCHLD signals.
694          */
695         case PS_WAIT_WAIT:
696                 if (sig == SIGCHLD) {
697                         /* Change the state of the thread to run: */
698                         PTHREAD_WAITQ_REMOVE(pthread);
699                         PTHREAD_SET_STATE(pthread, PS_RUNNING);
700
701                         /* Return the signal number: */
702                         pthread->signo = sig;
703                 }
704                 else {
705                         /*
706                          * Mark the thread as interrupted only if the
707                          * restart flag is not set on the signal action:
708                          */
709                         if (restart == 0)
710                                 pthread->interrupted = 1;
711                         PTHREAD_WAITQ_REMOVE(pthread);
712                         PTHREAD_SET_STATE(pthread, PS_RUNNING);
713                 }
714                 break;
715
716         /*
717          * States which cannot be interrupted but still require the
718          * signal handler to run:
719          */
720         case PS_COND_WAIT:
721         case PS_MUTEX_WAIT:
722                 /*
723                  * Remove the thread from the wait queue.  It will
724                  * be added back to the wait queue once all signal
725                  * handlers have been invoked.
726                  */
727                 PTHREAD_WAITQ_REMOVE(pthread);
728                 break;
729
730         case PS_JOIN:
731                 /*
732                  * Remove the thread from the wait queue.  It will
733                  * be added back to the wait queue once all signal
734                  * handlers have been invoked.
735                  */
736                 PTHREAD_WAITQ_REMOVE(pthread);
737                 /* Make the thread runnable: */
738                 PTHREAD_SET_STATE(pthread, PS_RUNNING);
739                 break;
740
741         /*
742          * States which are interruptible but may need to be removed
743          * from queues before any signal handler is called.
744          *
745          * XXX - We may not need to handle this condition, but will
746          *       mark it as a potential problem.
747          */
748         case PS_FDLR_WAIT:
749         case PS_FDLW_WAIT:
750         case PS_FILE_WAIT:
751                 if (restart == 0)
752                         pthread->interrupted = 1;
753                 /*
754                  * Remove the thread from the wait queue.  Our
755                  * signal handler hook will remove this thread
756                  * from the fd or file queue before invoking
757                  * the actual handler.
758                  */
759                 PTHREAD_WAITQ_REMOVE(pthread);
760                 break;
761
762         /*
763          * States which are interruptible:
764          */
765         case PS_FDR_WAIT:
766         case PS_FDW_WAIT:
767                 if (restart == 0) {
768                         /*
769                          * Flag the operation as interrupted and
770                          * set the state to running:
771                          */
772                         pthread->interrupted = 1;
773                         PTHREAD_SET_STATE(pthread, PS_RUNNING);
774                 }
775                 PTHREAD_WORKQ_REMOVE(pthread);
776                 PTHREAD_WAITQ_REMOVE(pthread);
777                 break;
778
779         case PS_POLL_WAIT:
780         case PS_SELECT_WAIT:
781         case PS_SLEEP_WAIT:
782                 /*
783                  * Unmasked signals always cause poll, select, and sleep
784                  * to terminate early, regardless of SA_RESTART:
785                  */
786                 pthread->interrupted = 1;
787                 /* Remove threads in poll and select from the workq: */
788                 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
789                         PTHREAD_WORKQ_REMOVE(pthread);
790                 PTHREAD_WAITQ_REMOVE(pthread);
791                 PTHREAD_SET_STATE(pthread, PS_RUNNING);
792                 break;
793
794         case PS_SIGSUSPEND:
795                 PTHREAD_WAITQ_REMOVE(pthread);
796                 PTHREAD_SET_STATE(pthread, PS_RUNNING);
797                 break;
798         }
799
800         if (suppress_handler == 0) {
801                 /* Setup a signal frame and save the current threads state: */
802                 thread_sigframe_add(pthread, sig, has_args);
803
804                 /*
805                  * Signals are deferred until just before the threads
806                  * signal handler is invoked:
807                  */
808                 pthread->sig_defer_count = 1;
809
810                 /* Make sure the thread is runnable: */
811                 if (pthread->state != PS_RUNNING)
812                         PTHREAD_SET_STATE(pthread, PS_RUNNING);
813                 /*
814                  * The thread should be removed from all scheduling
815                  * queues at this point.  Raise the priority and place
816                  * the thread in the run queue.  It is also possible
817                  * for a signal to be sent to a suspended thread,
818                  * mostly via pthread_kill().  If a thread is suspended,
819                  * don't insert it into the priority queue; just set
820                  * its state to suspended and it will run the signal
821                  * handler when it is resumed.
822                  */
823                 pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY;
824                 if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
825                         PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
826                 else if (thread_is_active == 0)
827                         PTHREAD_PRIOQ_INSERT_TAIL(pthread);
828         }
829 }
830
831 static void
832 thread_sig_check_state(struct pthread *pthread, int sig)
833 {
834         /*
835          * Process according to thread state:
836          */
837         switch (pthread->state) {
838         /*
839          * States which do not change when a signal is trapped:
840          */
841         case PS_DEAD:
842         case PS_DEADLOCK:
843         case PS_STATE_MAX:
844         case PS_SIGTHREAD:
845         case PS_RUNNING:
846         case PS_SUSPENDED:
847         case PS_SPINBLOCK:
848         case PS_COND_WAIT:
849         case PS_JOIN:
850         case PS_MUTEX_WAIT:
851                 break;
852
853         case PS_SIGWAIT:
854                 /* Wake up the thread if the signal is blocked. */
855                 if (sigismember(pthread->data.sigwait, sig)) {
856                         /* Change the state of the thread to run: */
857                         PTHREAD_NEW_STATE(pthread, PS_RUNNING);
858
859                         /* Return the signal number: */
860                         pthread->signo = sig;
861                 } else
862                         /* Increment the pending signal count. */
863                         sigaddset(&pthread->sigpend, sig);
864                 break;
865
866         /*
867          * The wait state is a special case due to the handling of
868          * SIGCHLD signals.
869          */
870         case PS_WAIT_WAIT:
871                 if (sig == SIGCHLD) {
872                         /*
873                          * Remove the thread from the wait queue and
874                          * make it runnable:
875                          */
876                         PTHREAD_NEW_STATE(pthread, PS_RUNNING);
877
878                         /* Return the signal number: */
879                         pthread->signo = sig;
880                 }
881                 break;
882
883         case PS_FDLR_WAIT:
884         case PS_FDLW_WAIT:
885         case PS_SIGSUSPEND:
886         case PS_SLEEP_WAIT:
887                 /*
888                  * Remove the thread from the wait queue and make it
889                  * runnable:
890                  */
891                 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
892
893                 /* Flag the operation as interrupted: */
894                 pthread->interrupted = 1;
895                 break;
896
897         /*
898          * These states are additionally in the work queue:
899          */
900         case PS_FDR_WAIT:
901         case PS_FDW_WAIT:
902         case PS_FILE_WAIT:
903         case PS_POLL_WAIT:
904         case PS_SELECT_WAIT:
905                 /*
906                  * Remove the thread from the wait and work queues, and
907                  * make it runnable:
908                  */
909                 PTHREAD_WORKQ_REMOVE(pthread);
910                 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
911
912                 /* Flag the operation as interrupted: */
913                 pthread->interrupted = 1;
914                 break;
915         }
916 }
917
918 /*
919  * Send a signal to a specific thread (ala pthread_kill):
920  */
921 void
922 _thread_sig_send(struct pthread *pthread, int sig)
923 {
924         struct pthread  *curthread = _get_curthread();
925
926         /* Check for signals whose actions are SIG_DFL: */
927         if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) {
928                 /*
929                  * Check to see if a temporary signal handler is
930                  * installed for sigwaiters:
931                  */
932                 if (_thread_dfl_count[sig] == 0)
933                         /*
934                          * Deliver the signal to the process if a handler
935                          * is not installed:
936                          */
937                         kill(getpid(), sig);
938                 /*
939                  * Assuming we're still running after the above kill(),
940                  * make any necessary state changes to the thread:
941                  */
942                 thread_sig_check_state(pthread, sig);
943         }
944         /*
945          * Check that the signal is not being ignored:
946          */
947         else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
948                 if (pthread->state == PS_SIGWAIT &&
949                     sigismember(pthread->data.sigwait, sig)) {
950                         /* Change the state of the thread to run: */
951                         PTHREAD_NEW_STATE(pthread, PS_RUNNING);
952         
953                         /* Return the signal number: */
954                         pthread->signo = sig;
955                 } else if (sigismember(&pthread->sigmask, sig))
956                         /* Add the signal to the pending set: */
957                         sigaddset(&pthread->sigpend, sig);
958                 else if (pthread == curthread)
959                         /* Call the signal handler for the current thread: */
960                         thread_sig_invoke_handler(sig, NULL, NULL, 0);
961                 else {
962                         /* Protect the scheduling queues: */
963                         _thread_kern_sig_defer();
964                         /*
965                          * Perform any state changes due to signal
966                          * arrival:
967                          */
968                         thread_sig_add(pthread, sig, /* has args */ 0);
969                         /* Unprotect the scheduling queues: */
970                         _thread_kern_sig_undefer();
971                 }
972         }
973 }
974
975 /*
976  * User thread signal handler wrapper.
977  *
978  *   thread - current running thread
979  */
980 void
981 _thread_sig_wrapper(void)
982 {
983         struct pthread_signal_frame *psf;
984         struct pthread  *thread = _get_curthread();
985
986         /* Get the current frame and state: */
987         psf = thread->curframe;
988         thread->curframe = NULL;
989         PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler");
990
991         /*
992          * We're coming from the kernel scheduler; clear the in
993          * scheduler flag:
994          */
995         _thread_kern_in_sched = 0;
996
997         /* Check the threads previous state: */
998         if (psf->saved_state.psd_state != PS_RUNNING) {
999                 /*
1000                  * Do a little cleanup handling for those threads in
1001                  * queues before calling the signal handler.  Signals
1002                  * for these threads are temporarily blocked until
1003                  * after cleanup handling.
1004                  */
1005                 switch (psf->saved_state.psd_state) {
1006                 case PS_FDLR_WAIT:
1007                 case PS_FDLW_WAIT:
1008                         _fd_lock_backout(thread);
1009                         psf->saved_state.psd_state = PS_RUNNING;
1010                         break;
1011
1012                 case PS_COND_WAIT:
1013                         _cond_wait_backout(thread);
1014                         psf->saved_state.psd_state = PS_RUNNING;
1015                         break;
1016
1017                 case PS_MUTEX_WAIT:
1018                         _mutex_lock_backout(thread);
1019                         psf->saved_state.psd_state = PS_RUNNING;
1020                         break;
1021
1022                 default:
1023                         break;
1024                 }
1025         }
1026
1027         /*
1028          * Lower the priority before calling the handler in case
1029          * it never returns (longjmps back):
1030          */
1031         thread->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
1032
1033         /*
1034          * Reenable interruptions without checking for the need to
1035          * context switch:
1036          */
1037         thread->sig_defer_count = 0;
1038
1039         /*
1040          * Dispatch the signal via the custom signal handler:
1041          */
1042         if (psf->sig_has_args == 0)
1043                 thread_sig_invoke_handler(psf->signo, NULL, NULL, 1);
1044         else
1045                 thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc,
1046                                           1);
1047
1048         /*
1049          * Call the kernel scheduler to safely restore the frame and
1050          * schedule the next thread:
1051          */
1052         _thread_kern_sched_frame(psf);
1053 }
1054
1055 static void
1056 thread_sigframe_add(struct pthread *thread, int sig, int has_args)
1057 {
1058         struct pthread_signal_frame *psf = NULL;
1059         unsigned long   stackp;
1060
1061         /* Get the top of the threads stack: */
1062         stackp = GET_STACK_JB(thread->ctx.jb);
1063
1064 #if !defined(__ia64__)
1065         /*
1066          * Leave a little space on the stack and round down to the
1067          * nearest aligned word:
1068          */
1069 #if defined(__amd64__)
1070         stackp -= 128;          /* Skip over 128 byte red-zone */
1071 #endif
1072         stackp -= sizeof(double);
1073 #if defined(__amd64__)
1074         stackp &= ~0xFUL;
1075 #else
1076         stackp &= ~0x3UL;
1077 #endif
1078 #endif
1079
1080         /* Allocate room on top of the stack for a new signal frame: */
1081         stackp -= sizeof(struct pthread_signal_frame);
1082 #if defined(__ia64__) || defined(__amd64__)
1083         stackp &= ~0xFUL;
1084 #endif
1085
1086         psf = (struct pthread_signal_frame *) stackp;
1087
1088         /* Save the current context in the signal frame: */
1089         thread_sigframe_save(thread, psf);
1090
1091         /* Set handler specific information: */
1092         psf->sig_has_args = has_args;
1093         psf->signo = sig;
1094         if (has_args) {
1095                 /* Copy the signal handler arguments to the signal frame: */
1096                 memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc,
1097                     sizeof(psf->uc));
1098                 memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo,
1099                     sizeof(psf->siginfo));
1100         }
1101
1102         /* Setup the signal mask: */
1103         SIGSETOR(thread->sigmask, _thread_sigact[sig - 1].sa_mask);
1104         sigaddset(&thread->sigmask, sig);
1105
1106         /* Set up the new frame: */
1107         thread->curframe = psf;
1108         thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
1109             PTHREAD_FLAGS_IN_SYNCQ;
1110         /*
1111          * Set up the context:
1112          */
1113 #if !defined(__ia64__)
1114         stackp -= sizeof(double);
1115 #if defined(__amd64__)
1116         stackp &= ~0xFUL;
1117 #endif
1118 #endif
1119         _setjmp(thread->ctx.jb);
1120 #if !defined(__ia64__)
1121         SET_STACK_JB(thread->ctx.jb, stackp);
1122 #else
1123         UPD_STACK_JB(thread->ctx.jb, stackp - 16);
1124 #endif
1125         SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);
1126 }
1127
1128 void
1129 _thread_sigframe_restore(struct pthread *thread,
1130     struct pthread_signal_frame *psf)
1131 {
1132         memcpy(&thread->ctx, &psf->ctx, sizeof(thread->ctx));
1133         /*
1134          * Only restore the signal mask if it hasn't been changed
1135          * by the application during invocation of the signal handler:
1136          */
1137         if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno)
1138                 thread->sigmask = psf->saved_state.psd_sigmask;
1139         thread->curframe = psf->saved_state.psd_curframe;
1140         thread->wakeup_time = psf->saved_state.psd_wakeup_time;
1141         thread->data = psf->saved_state.psd_wait_data;
1142         thread->state = psf->saved_state.psd_state;
1143         thread->flags = psf->saved_state.psd_flags;
1144         thread->interrupted = psf->saved_state.psd_interrupted;
1145         thread->signo = psf->saved_state.psd_signo;
1146         thread->sig_defer_count = psf->saved_state.psd_sig_defer_count;
1147 }
1148
1149 static void
1150 thread_sigframe_save(struct pthread *thread, struct pthread_signal_frame *psf)
1151 {
1152         memcpy(&psf->ctx, &thread->ctx, sizeof(thread->ctx));
1153         psf->saved_state.psd_sigmask = thread->sigmask;
1154         psf->saved_state.psd_curframe = thread->curframe;
1155         psf->saved_state.psd_wakeup_time = thread->wakeup_time;
1156         psf->saved_state.psd_wait_data = thread->data;
1157         psf->saved_state.psd_state = thread->state;
1158         psf->saved_state.psd_flags = thread->flags &
1159             (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
1160         psf->saved_state.psd_interrupted = thread->interrupted;
1161         psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno;
1162         psf->saved_state.psd_signo = thread->signo;
1163         psf->saved_state.psd_sig_defer_count = thread->sig_defer_count;
1164 }
1165