Update.
[glibc.git] / linuxthreads / signals.c
blob5a1025ee7a27dc9db3d0c39bfa7effe08cc2b692
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. */
15 /* Handling of signals */
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>
25 int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
27 sigset_t mask;
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;
45 newmask = &mask;
47 if (sigprocmask(how, newmask, oldmask) == -1)
48 return errno;
49 else
50 return 0;
53 int pthread_kill(pthread_t thread, int signo)
55 pthread_handle handle = thread_handle(thread);
56 int pid;
58 __pthread_lock(&handle->h_lock, NULL);
59 if (invalid_handle(handle, thread)) {
60 __pthread_unlock(&handle->h_lock);
61 return ESRCH;
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;
71 /* User-provided signal handlers */
72 typedef void (*arch_sighandler_t) (int, SIGCONTEXT);
73 static union
75 arch_sighandler_t old;
76 void (*rt) (int, struct siginfo *, struct ucontext *);
77 } sighandler[NSIG] = { [1 ... NSIG - 1] = { (arch_sighandler_t) SIG_ERR } };
79 /* The wrapper around user-provided signal handlers */
80 static void pthread_sighandler(int signo, SIGCONTEXT ctx)
82 pthread_descr self;
83 char * in_sighandler;
84 self = thread_self();
85 /* If we're in a sigwait operation, just record the signal received
86 and return without calling the user's handler */
87 if (THREAD_GETMEM(self, p_sigwaiting)) {
88 THREAD_SETMEM(self, p_sigwaiting, 0);
89 THREAD_SETMEM(self, p_signal, signo);
90 return;
92 /* Record that we're in a signal handler and call the user's
93 handler function */
94 in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
95 if (in_sighandler == NULL)
96 THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
97 CALL_SIGHANDLER(sighandler[signo].old, signo, ctx);
98 if (in_sighandler == NULL)
99 THREAD_SETMEM(self, p_in_sighandler, NULL);
102 /* The same, this time for real-time signals. */
103 static void pthread_sighandler_rt(int signo, struct siginfo *si,
104 struct ucontext *uc)
106 pthread_descr self;
107 char * in_sighandler;
108 self = thread_self();
109 /* If we're in a sigwait operation, just record the signal received
110 and return without calling the user's handler */
111 if (THREAD_GETMEM(self, p_sigwaiting)) {
112 THREAD_SETMEM(self, p_sigwaiting, 0);
113 THREAD_SETMEM(self, p_signal, signo);
114 return;
116 /* Record that we're in a signal handler and call the user's
117 handler function */
118 in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
119 if (in_sighandler == NULL)
120 THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
121 sighandler[signo].rt(signo, si, uc);
122 if (in_sighandler == NULL)
123 THREAD_SETMEM(self, p_in_sighandler, NULL);
126 /* The wrapper around sigaction. Install our own signal handler
127 around the signal. */
128 int __sigaction(int sig, const struct sigaction * act,
129 struct sigaction * oact)
131 struct sigaction newact;
132 struct sigaction *newactp;
134 if (sig == __pthread_sig_restart ||
135 sig == __pthread_sig_cancel ||
136 (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
138 __set_errno (EINVAL);
139 return -1;
141 if (act)
143 newact = *act;
144 if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
145 && sig > 0 && sig < NSIG)
147 if (act->sa_flags & SA_SIGINFO)
148 newact.sa_handler = (__sighandler_t) pthread_sighandler_rt;
149 else
150 newact.sa_handler = (__sighandler_t) pthread_sighandler;
152 newactp = &newact;
154 else
155 newactp = NULL;
156 if (__libc_sigaction(sig, newactp, oact) == -1)
157 return -1;
158 if (sig > 0 && sig < NSIG)
160 if (oact != NULL
161 /* We may have inherited SIG_IGN from the parent, so return the
162 kernel's idea of the signal handler the first time
163 through. */
164 && (__sighandler_t) sighandler[sig].old != SIG_ERR)
165 oact->sa_handler = (__sighandler_t) sighandler[sig].old;
166 if (act)
167 /* For the assignment it does not matter whether it's a normal
168 or real-time signal. */
169 sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
171 return 0;
173 strong_alias(__sigaction, sigaction)
175 /* A signal handler that does nothing */
176 static void pthread_null_sighandler(int sig) { }
178 /* sigwait -- synchronously wait for a signal */
179 int sigwait(const sigset_t * set, int * sig)
181 volatile pthread_descr self = thread_self();
182 sigset_t mask;
183 int s;
184 sigjmp_buf jmpbuf;
185 struct sigaction sa;
187 /* Get ready to block all signals except those in set
188 and the cancellation signal.
189 Also check that handlers are installed on all signals in set,
190 and if not, install our dummy handler. This is conformant to
191 POSIX: "The effect of sigwait() on the signal actions for the
192 signals in set is unspecified." */
193 sigfillset(&mask);
194 sigdelset(&mask, __pthread_sig_cancel);
195 for (s = 1; s < NSIG; s++) {
196 if (sigismember(set, s) &&
197 s != __pthread_sig_restart &&
198 s != __pthread_sig_cancel &&
199 s != __pthread_sig_debug) {
200 sigdelset(&mask, s);
201 if (sighandler[s].old == NULL ||
202 sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
203 sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
204 sa.sa_handler = pthread_null_sighandler;
205 sigfillset(&sa.sa_mask);
206 sa.sa_flags = 0;
207 sigaction(s, &sa, NULL);
211 /* Test for cancellation */
212 if (sigsetjmp(jmpbuf, 1) == 0) {
213 THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
214 if (! (THREAD_GETMEM(self, p_canceled)
215 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
216 /* Reset the signal count */
217 THREAD_SETMEM(self, p_signal, 0);
218 /* Say we're in sigwait */
219 THREAD_SETMEM(self, p_sigwaiting, 1);
220 /* Unblock the signals and wait for them */
221 sigsuspend(&mask);
224 THREAD_SETMEM(self, p_cancel_jmp, NULL);
225 /* The signals are now reblocked. Check for cancellation */
226 pthread_testcancel();
227 /* We should have self->p_signal != 0 and equal to the signal received */
228 *sig = THREAD_GETMEM(self, p_signal);
229 return 0;
232 /* Redefine raise() to send signal to calling thread only,
233 as per POSIX 1003.1c */
234 int raise (int sig)
236 int retcode = pthread_kill(pthread_self(), sig);
237 if (retcode == 0)
238 return 0;
239 else {
240 errno = retcode;
241 return -1;