Move sighandler functions to sighandler.c.
[kopensolaris-gnu/glibc.git] / linuxthreads / signals.c
1 /* Linuxthreads - a simple clone()-based implementation of Posix        */
2 /* threads for Linux.                                                   */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
4 /*                                                                      */
5 /* This program is free software; you can redistribute it and/or        */
6 /* modify it under the terms of the GNU Library General Public License  */
7 /* as published by the Free Software Foundation; either version 2       */
8 /* of the License, or (at your option) any later version.               */
9 /*                                                                      */
10 /* This program is distributed in the hope that it will be useful,      */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
13 /* GNU Library General Public License for more details.                 */
14
15 /* Handling of signals */
16
17 #include <errno.h>
18 #include <signal.h>
19 #include "pthread.h"
20 #include "internals.h"
21 #include "spinlock.h"
22 #include <ucontext.h>
23
24
25 int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
26 {
27   sigset_t mask;
28
29   if (newmask != NULL) {
30     mask = *newmask;
31     /* Don't allow __pthread_sig_restart to be unmasked.
32        Don't allow __pthread_sig_cancel to be masked. */
33     switch(how) {
34     case SIG_SETMASK:
35       sigaddset(&mask, __pthread_sig_restart);
36       sigdelset(&mask, __pthread_sig_cancel);
37       break;
38     case SIG_BLOCK:
39       sigdelset(&mask, __pthread_sig_cancel);
40       break;
41     case SIG_UNBLOCK:
42       sigdelset(&mask, __pthread_sig_restart);
43       break;
44     }
45     newmask = &mask;
46   }
47   if (sigprocmask(how, newmask, oldmask) == -1)
48     return errno;
49   else
50     return 0;
51 }
52
53 int pthread_kill(pthread_t thread, int signo)
54 {
55   pthread_handle handle = thread_handle(thread);
56   int pid;
57
58   __pthread_lock(&handle->h_lock, NULL);
59   if (invalid_handle(handle, thread)) {
60     __pthread_unlock(&handle->h_lock);
61     return ESRCH;
62   }
63   pid = handle->h_descr->p_pid;
64   __pthread_unlock(&handle->h_lock);
65   if (kill(pid, signo) == -1)
66     return errno;
67   else
68     return 0;
69 }
70
71 union sighandler __sighandler[NSIG] =
72   { [1 ... NSIG - 1] = { (arch_sighandler_t) SIG_ERR } };
73
74 /* The wrapper around sigaction.  Install our own signal handler
75    around the signal. */
76 int __sigaction(int sig, const struct sigaction * act,
77               struct sigaction * oact)
78 {
79   struct sigaction newact;
80   struct sigaction *newactp;
81
82   if (sig == __pthread_sig_restart ||
83       sig == __pthread_sig_cancel ||
84       (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
85     {
86       __set_errno (EINVAL);
87       return -1;
88     }
89   if (act)
90     {
91       newact = *act;
92       if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
93           && sig > 0 && sig < NSIG)
94         {
95           if (act->sa_flags & SA_SIGINFO)
96             newact.sa_handler = (__sighandler_t) __pthread_sighandler_rt;
97           else
98             newact.sa_handler = (__sighandler_t) __pthread_sighandler;
99         }
100       newactp = &newact;
101     }
102   else
103     newactp = NULL;
104   if (__libc_sigaction(sig, newactp, oact) == -1)
105     return -1;
106   if (sig > 0 && sig < NSIG)
107     {
108       if (oact != NULL
109           /* We may have inherited SIG_IGN from the parent, so return the
110              kernel's idea of the signal handler the first time
111              through.  */
112           && (__sighandler_t) __sighandler[sig].old != SIG_ERR)
113         oact->sa_handler = (__sighandler_t) __sighandler[sig].old;
114       if (act)
115         /* For the assignment it does not matter whether it's a normal
116            or real-time signal.  */
117         __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
118     }
119   return 0;
120 }
121 strong_alias(__sigaction, sigaction)
122
123 /* sigwait -- synchronously wait for a signal */
124 int sigwait(const sigset_t * set, int * sig)
125 {
126   volatile pthread_descr self = thread_self();
127   sigset_t mask;
128   int s;
129   sigjmp_buf jmpbuf;
130   struct sigaction sa;
131
132   /* Get ready to block all signals except those in set
133      and the cancellation signal.
134      Also check that handlers are installed on all signals in set,
135      and if not, install our dummy handler.  This is conformant to
136      POSIX: "The effect of sigwait() on the signal actions for the
137      signals in set is unspecified." */
138   sigfillset(&mask);
139   sigdelset(&mask, __pthread_sig_cancel);
140   for (s = 1; s < NSIG; s++) {
141     if (sigismember(set, s) &&
142         s != __pthread_sig_restart &&
143         s != __pthread_sig_cancel &&
144         s != __pthread_sig_debug) {
145       sigdelset(&mask, s);
146       if (__sighandler[s].old == (arch_sighandler_t) SIG_ERR ||
147           __sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
148           __sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
149         sa.sa_handler = __pthread_null_sighandler;
150         sigfillset(&sa.sa_mask);
151         sa.sa_flags = 0;
152         sigaction(s, &sa, NULL);
153       }
154     }
155   }
156   /* Test for cancellation */
157   if (sigsetjmp(jmpbuf, 1) == 0) {
158     THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
159     if (! (THREAD_GETMEM(self, p_canceled)
160            && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
161       /* Reset the signal count */
162       THREAD_SETMEM(self, p_signal, 0);
163       /* Say we're in sigwait */
164       THREAD_SETMEM(self, p_sigwaiting, 1);
165       /* Unblock the signals and wait for them */
166       sigsuspend(&mask);
167     }
168   }
169   THREAD_SETMEM(self, p_cancel_jmp, NULL);
170   /* The signals are now reblocked.  Check for cancellation */
171   pthread_testcancel();
172   /* We should have self->p_signal != 0 and equal to the signal received */
173   *sig = THREAD_GETMEM(self, p_signal);
174   return 0;
175 }
176
177 /* Redefine raise() to send signal to calling thread only,
178    as per POSIX 1003.1c */
179 int raise (int sig)
180 {
181   int retcode = pthread_kill(pthread_self(), sig);
182   if (retcode == 0)
183     return 0;
184   else {
185     errno = retcode;
186     return -1;
187   }
188 }