(main): Rewrite initializers to avoid warnings.
[glibc.git] / linuxthreads / signals.c
blob452d860f92f45229ffb0d6870439dfc114aebe0a
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];
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 #ifdef __i386__
85 asm volatile ("movw %w0,%%gs" : : "r" (ctx.gs));
86 #endif
87 self = thread_self();
88 /* If we're in a sigwait operation, just record the signal received
89 and return without calling the user's handler */
90 if (THREAD_GETMEM(self, p_sigwaiting)) {
91 THREAD_SETMEM(self, p_sigwaiting, 0);
92 THREAD_SETMEM(self, p_signal, signo);
93 return;
95 /* Record that we're in a signal handler and call the user's
96 handler function */
97 in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
98 if (in_sighandler == NULL)
99 THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
100 sighandler[signo].old(signo, SIGCONTEXT_EXTRA_ARGS ctx);
101 if (in_sighandler == NULL)
102 THREAD_SETMEM(self, p_in_sighandler, NULL);
105 /* The same, this time for real-time signals. */
106 static void pthread_sighandler_rt(int signo, struct siginfo *si,
107 struct ucontext *uc)
109 pthread_descr self;
110 char * in_sighandler;
111 #ifdef __i386__
112 asm volatile ("movw %w0,%%gs" : : "r" (uc->uc_mcontext.gregs[REG_GS]));
113 #endif
114 self = thread_self();
115 /* If we're in a sigwait operation, just record the signal received
116 and return without calling the user's handler */
117 if (THREAD_GETMEM(self, p_sigwaiting)) {
118 THREAD_SETMEM(self, p_sigwaiting, 0);
119 THREAD_SETMEM(self, p_signal, signo);
120 return;
122 /* Record that we're in a signal handler and call the user's
123 handler function */
124 in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
125 if (in_sighandler == NULL)
126 THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
127 sighandler[signo].rt(signo, si, uc);
128 if (in_sighandler == NULL)
129 THREAD_SETMEM(self, p_in_sighandler, NULL);
132 /* The wrapper around sigaction. Install our own signal handler
133 around the signal. */
134 int sigaction(int sig, const struct sigaction * act,
135 struct sigaction * oact)
137 struct sigaction newact;
138 struct sigaction *newactp;
140 if (sig == __pthread_sig_restart ||
141 sig == __pthread_sig_cancel ||
142 (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
144 __set_errno (EINVAL);
145 return -1;
147 if (act)
149 newact = *act;
150 if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
151 && sig > 0 && sig < NSIG)
153 if (act->sa_flags & SA_SIGINFO)
154 newact.sa_handler = (__sighandler_t) pthread_sighandler_rt;
155 else
156 newact.sa_handler = (__sighandler_t) pthread_sighandler;
158 newactp = &newact;
160 else
161 newactp = NULL;
162 if (__sigaction(sig, newactp, oact) == -1)
163 return -1;
164 if (sig > 0 && sig < NSIG)
166 if (oact != NULL)
167 oact->sa_handler = (__sighandler_t) sighandler[sig].old;
168 if (act)
169 /* For the assignment is does not matter whether it's a normal
170 or real-time signal. */
171 sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
173 return 0;
176 /* A signal handler that does nothing */
177 static void pthread_null_sighandler(int sig) { }
179 /* sigwait -- synchronously wait for a signal */
180 int sigwait(const sigset_t * set, int * sig)
182 volatile pthread_descr self = thread_self();
183 sigset_t mask;
184 int s;
185 sigjmp_buf jmpbuf;
186 struct sigaction sa;
188 /* Get ready to block all signals except those in set
189 and the cancellation signal.
190 Also check that handlers are installed on all signals in set,
191 and if not, install our dummy handler. This is conformant to
192 POSIX: "The effect of sigwait() on the signal actions for the
193 signals in set is unspecified." */
194 sigfillset(&mask);
195 sigdelset(&mask, __pthread_sig_cancel);
196 for (s = 1; s <= NSIG; s++) {
197 if (sigismember(set, s) &&
198 s != __pthread_sig_restart &&
199 s != __pthread_sig_cancel &&
200 s != __pthread_sig_debug) {
201 sigdelset(&mask, s);
202 if (sighandler[s].old == NULL ||
203 sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
204 sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
205 sa.sa_handler = pthread_null_sighandler;
206 sigemptyset(&sa.sa_mask);
207 sa.sa_flags = 0;
208 sigaction(s, &sa, NULL);
212 /* Test for cancellation */
213 if (sigsetjmp(jmpbuf, 1) == 0) {
214 THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
215 if (! (THREAD_GETMEM(self, p_canceled)
216 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
217 /* Reset the signal count */
218 THREAD_SETMEM(self, p_signal, 0);
219 /* Say we're in sigwait */
220 THREAD_SETMEM(self, p_sigwaiting, 1);
221 /* Unblock the signals and wait for them */
222 sigsuspend(&mask);
225 THREAD_SETMEM(self, p_cancel_jmp, NULL);
226 /* The signals are now reblocked. Check for cancellation */
227 pthread_testcancel();
228 /* We should have self->p_signal != 0 and equal to the signal received */
229 *sig = THREAD_GETMEM(self, p_signal);
230 return 0;
233 /* Redefine raise() to send signal to calling thread only,
234 as per POSIX 1003.1c */
235 int raise (int sig)
237 int retcode = pthread_kill(pthread_self(), sig);
238 if (retcode == 0)
239 return 0;
240 else {
241 errno = retcode;
242 return -1;