Update.
[glibc.git] / linuxthreads / signals.c
bloba352eb951db3b0a36df1dcedd8b6314c404560c4
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"
23 int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
25 sigset_t mask;
27 if (newmask != NULL) {
28 mask = *newmask;
29 /* Don't allow __pthread_sig_restart to be unmasked.
30 Don't allow __pthread_sig_cancel to be masked. */
31 switch(how) {
32 case SIG_SETMASK:
33 sigaddset(&mask, __pthread_sig_restart);
34 sigdelset(&mask, __pthread_sig_cancel);
35 break;
36 case SIG_BLOCK:
37 sigdelset(&mask, __pthread_sig_cancel);
38 break;
39 case SIG_UNBLOCK:
40 sigdelset(&mask, __pthread_sig_restart);
41 break;
43 newmask = &mask;
45 if (sigprocmask(how, newmask, oldmask) == -1)
46 return errno;
47 else
48 return 0;
51 int pthread_kill(pthread_t thread, int signo)
53 pthread_handle handle = thread_handle(thread);
54 int pid;
56 __pthread_lock(&handle->h_lock, NULL);
57 if (invalid_handle(handle, thread)) {
58 __pthread_unlock(&handle->h_lock);
59 return ESRCH;
61 pid = handle->h_descr->p_pid;
62 __pthread_unlock(&handle->h_lock);
63 if (kill(pid, signo) == -1)
64 return errno;
65 else
66 return 0;
69 /* User-provided signal handlers */
70 static __sighandler_t sighandler[NSIG];
72 /* The wrapper around user-provided signal handlers */
73 static void pthread_sighandler(int signo)
75 pthread_descr self = thread_self();
76 char * in_sighandler;
77 /* If we're in a sigwait operation, just record the signal received
78 and return without calling the user's handler */
79 if (THREAD_GETMEM(self, p_sigwaiting)) {
80 THREAD_SETMEM(self, p_sigwaiting, 0);
81 THREAD_SETMEM(self, p_signal, signo);
82 return;
84 /* Record that we're in a signal handler and call the user's
85 handler function */
86 in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
87 if (in_sighandler == NULL)
88 THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
89 sighandler[signo](signo);
90 if (in_sighandler == NULL)
91 THREAD_SETMEM(self, p_in_sighandler, NULL);
94 /* The wrapper around sigaction. Install our own signal handler
95 around the signal. */
96 int sigaction(int sig, const struct sigaction * act,
97 struct sigaction * oact)
99 struct sigaction newact;
100 struct sigaction *newactp;
102 if (sig == __pthread_sig_restart ||
103 sig == __pthread_sig_cancel ||
104 (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
105 return EINVAL;
106 if (act)
108 newact = *act;
109 if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
110 && sig > 0 && sig < NSIG)
111 newact.sa_handler = pthread_sighandler;
112 newactp = &newact;
114 else
115 newactp = NULL;
116 if (__sigaction(sig, newactp, oact) == -1)
117 return -1;
118 if (sig > 0 && sig < NSIG)
120 if (oact != NULL)
121 oact->sa_handler = sighandler[sig];
122 if (act)
123 sighandler[sig] = act->sa_handler;
125 return 0;
128 /* A signal handler that does nothing */
129 static void pthread_null_sighandler(int sig) { }
131 /* sigwait -- synchronously wait for a signal */
132 int sigwait(const sigset_t * set, int * sig)
134 volatile pthread_descr self = thread_self();
135 sigset_t mask;
136 int s;
137 sigjmp_buf jmpbuf;
138 struct sigaction sa;
140 /* Get ready to block all signals except those in set
141 and the cancellation signal.
142 Also check that handlers are installed on all signals in set,
143 and if not, install our dummy handler. This is conformant to
144 POSIX: "The effect of sigwait() on the signal actions for the
145 signals in set is unspecified." */
146 sigfillset(&mask);
147 sigdelset(&mask, __pthread_sig_cancel);
148 for (s = 1; s <= NSIG; s++) {
149 if (sigismember(set, s) &&
150 s != __pthread_sig_restart &&
151 s != __pthread_sig_cancel &&
152 s != __pthread_sig_debug) {
153 sigdelset(&mask, s);
154 if (sighandler[s] == NULL ||
155 sighandler[s] == SIG_DFL ||
156 sighandler[s] == SIG_IGN) {
157 sa.sa_handler = pthread_null_sighandler;
158 sigemptyset(&sa.sa_mask);
159 sa.sa_flags = 0;
160 sigaction(s, &sa, NULL);
164 /* Test for cancellation */
165 if (sigsetjmp(jmpbuf, 1) == 0) {
166 THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
167 if (! (THREAD_GETMEM(self, p_canceled)
168 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
169 /* Reset the signal count */
170 THREAD_SETMEM(self, p_signal, 0);
171 /* Say we're in sigwait */
172 THREAD_SETMEM(self, p_sigwaiting, 1);
173 /* Unblock the signals and wait for them */
174 sigsuspend(&mask);
177 THREAD_SETMEM(self, p_cancel_jmp, NULL);
178 /* The signals are now reblocked. Check for cancellation */
179 pthread_testcancel();
180 /* We should have self->p_signal != 0 and equal to the signal received */
181 *sig = THREAD_GETMEM(self, p_signal);
182 return 0;
185 /* Redefine raise() to send signal to calling thread only,
186 as per POSIX 1003.1c */
187 int raise (int sig)
189 int retcode = pthread_kill(pthread_self(), sig);
190 if (retcode == 0)
191 return 0;
192 else {
193 errno = retcode;
194 return -1;