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