(sigaction): Correct last patch. Don't select pthread_sighandler_rt
[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 #include <sigcontextinfo.h>
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 /* User-provided signal handlers */
72 typedef void (*arch_sighandler_t) __PMT ((int, SIGCONTEXT));
73 static union
74 {
75   arch_sighandler_t old;
76   void (*rt) (int, struct siginfo *, struct ucontext *);
77 } sighandler[NSIG];
78
79 /* The wrapper around user-provided signal handlers */
80 static void pthread_sighandler(int signo, SIGCONTEXT ctx)
81 {
82   pthread_descr self = thread_self();
83   char * in_sighandler;
84   /* If we're in a sigwait operation, just record the signal received
85      and return without calling the user's handler */
86   if (THREAD_GETMEM(self, p_sigwaiting)) {
87     THREAD_SETMEM(self, p_sigwaiting, 0);
88     THREAD_SETMEM(self, p_signal, signo);
89     return;
90   }
91   /* Record that we're in a signal handler and call the user's
92      handler function */
93   in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
94   if (in_sighandler == NULL)
95     THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
96   sighandler[signo].old(signo, SIGCONTEXT_EXTRA_ARGS ctx);
97   if (in_sighandler == NULL)
98     THREAD_SETMEM(self, p_in_sighandler, NULL);
99 }
100
101 /* The same, this time for real-time signals.  */
102 static void pthread_sighandler_rt(int signo, struct siginfo *si,
103                                   struct ucontext *uc)
104 {
105   pthread_descr self = thread_self();
106   char * in_sighandler;
107   /* If we're in a sigwait operation, just record the signal received
108      and return without calling the user's handler */
109   if (THREAD_GETMEM(self, p_sigwaiting)) {
110     THREAD_SETMEM(self, p_sigwaiting, 0);
111     THREAD_SETMEM(self, p_signal, signo);
112     return;
113   }
114   /* Record that we're in a signal handler and call the user's
115      handler function */
116   in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
117   if (in_sighandler == NULL)
118     THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
119   sighandler[signo].rt(signo, si, uc);
120   if (in_sighandler == NULL)
121     THREAD_SETMEM(self, p_in_sighandler, NULL);
122 }
123
124 /* The wrapper around sigaction.  Install our own signal handler
125    around the signal. */
126 int sigaction(int sig, const struct sigaction * act,
127               struct sigaction * oact)
128 {
129   struct sigaction newact;
130   struct sigaction *newactp;
131
132   if (sig == __pthread_sig_restart ||
133       sig == __pthread_sig_cancel ||
134       (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
135     return EINVAL;
136   if (act)
137     {
138       newact = *act;
139       if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
140           && sig > 0 && sig < NSIG)
141         {
142           if (act->sa_flags & SA_SIGINFO)
143             newact.sa_handler = (__sighandler_t) pthread_sighandler_rt;
144           else
145             newact.sa_handler = (__sighandler_t) pthread_sighandler;
146         }
147       newactp = &newact;
148     }
149   else
150     newactp = NULL;
151   if (__sigaction(sig, newactp, oact) == -1)
152     return -1;
153   if (sig > 0 && sig < NSIG)
154     {
155       if (oact != NULL)
156         oact->sa_handler = (__sighandler_t) sighandler[sig].old;
157       if (act)
158         /* For the assignment is does not matter whether it's a normal
159            or real-time signal.  */
160         sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
161     }
162   return 0;
163 }
164
165 /* A signal handler that does nothing */
166 static void pthread_null_sighandler(int sig) { }
167
168 /* sigwait -- synchronously wait for a signal */
169 int sigwait(const sigset_t * set, int * sig)
170 {
171   volatile pthread_descr self = thread_self();
172   sigset_t mask;
173   int s;
174   sigjmp_buf jmpbuf;
175   struct sigaction sa;
176
177   /* Get ready to block all signals except those in set
178      and the cancellation signal.
179      Also check that handlers are installed on all signals in set,
180      and if not, install our dummy handler.  This is conformant to
181      POSIX: "The effect of sigwait() on the signal actions for the
182      signals in set is unspecified." */
183   sigfillset(&mask);
184   sigdelset(&mask, __pthread_sig_cancel);
185   for (s = 1; s <= NSIG; s++) {
186     if (sigismember(set, s) &&
187         s != __pthread_sig_restart &&
188         s != __pthread_sig_cancel &&
189         s != __pthread_sig_debug) {
190       sigdelset(&mask, s);
191       if (sighandler[s].old == NULL ||
192           sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
193           sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
194         sa.sa_handler = pthread_null_sighandler;
195         sigemptyset(&sa.sa_mask);
196         sa.sa_flags = 0;
197         sigaction(s, &sa, NULL);
198       }
199     }
200   }
201   /* Test for cancellation */
202   if (sigsetjmp(jmpbuf, 1) == 0) {
203     THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
204     if (! (THREAD_GETMEM(self, p_canceled)
205            && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
206       /* Reset the signal count */
207       THREAD_SETMEM(self, p_signal, 0);
208       /* Say we're in sigwait */
209       THREAD_SETMEM(self, p_sigwaiting, 1);
210       /* Unblock the signals and wait for them */
211       sigsuspend(&mask);
212     }
213   }
214   THREAD_SETMEM(self, p_cancel_jmp, NULL);
215   /* The signals are now reblocked.  Check for cancellation */
216   pthread_testcancel();
217   /* We should have self->p_signal != 0 and equal to the signal received */
218   *sig = THREAD_GETMEM(self, p_signal);
219   return 0;
220 }
221
222 /* Redefine raise() to send signal to calling thread only,
223    as per POSIX 1003.1c */
224 int raise (int sig)
225 {
226   int retcode = pthread_kill(pthread_self(), sig);
227   if (retcode == 0)
228     return 0;
229   else {
230     errno = retcode;
231     return -1;
232   }
233 }