* sysdeps/unix/sysv/linux/alpha/rt_sigaction.S: Fix typo.
[glibc.git] / linuxthreads / signals.c
blob667754aa3752b4f485604084174c12d459b603e8
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>
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 union sighandler __sighandler[NSIG] =
72 { [1 ... NSIG - 1] = { (arch_sighandler_t) SIG_ERR } };
74 /* The wrapper around sigaction. Install our own signal handler
75 around the signal. */
76 int __pthread_sigaction(int sig, const struct sigaction * act,
77 struct sigaction * oact)
79 struct sigaction newact;
80 struct sigaction *newactp;
81 __sighandler_t old = SIG_DFL;
83 if (sig == __pthread_sig_restart ||
84 sig == __pthread_sig_cancel ||
85 (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
87 __set_errno (EINVAL);
88 return -1;
90 if (sig > 0 && sig < NSIG)
91 old = (__sighandler_t) __sighandler[sig].old;
92 if (act)
94 newact = *act;
95 if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
96 && sig > 0 && sig < NSIG)
98 if (act->sa_flags & SA_SIGINFO)
99 newact.sa_handler = (__sighandler_t) __pthread_sighandler_rt;
100 else
101 newact.sa_handler = (__sighandler_t) __pthread_sighandler;
102 if (old == SIG_IGN || old == SIG_DFL || old == SIG_ERR)
103 __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
105 newactp = &newact;
107 else
108 newactp = NULL;
109 if (__libc_sigaction(sig, newactp, oact) == -1)
111 if (act)
112 __sighandler[sig].old = (arch_sighandler_t) old;
113 return -1;
115 if (sig > 0 && sig < NSIG)
117 if (oact != NULL
118 /* We may have inherited SIG_IGN from the parent, so return the
119 kernel's idea of the signal handler the first time
120 through. */
121 && old != SIG_ERR)
122 oact->sa_handler = old;
123 if (act)
124 /* For the assignment it does not matter whether it's a normal
125 or real-time signal. */
126 __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
128 return 0;
130 #ifdef SHARED
131 strong_alias(__pthread_sigaction, __sigaction)
132 strong_alias(__pthread_sigaction, sigaction)
133 #endif
135 /* sigwait -- synchronously wait for a signal */
136 int __pthread_sigwait(const sigset_t * set, int * sig)
138 volatile pthread_descr self = thread_self();
139 sigset_t mask;
140 int s;
141 sigjmp_buf jmpbuf;
142 struct sigaction sa;
144 /* Get ready to block all signals except those in set
145 and the cancellation signal.
146 Also check that handlers are installed on all signals in set,
147 and if not, install our dummy handler. This is conformant to
148 POSIX: "The effect of sigwait() on the signal actions for the
149 signals in set is unspecified." */
150 sigfillset(&mask);
151 sigdelset(&mask, __pthread_sig_cancel);
152 for (s = 1; s < NSIG; s++) {
153 if (sigismember(set, s) &&
154 s != __pthread_sig_restart &&
155 s != __pthread_sig_cancel &&
156 s != __pthread_sig_debug) {
157 sigdelset(&mask, s);
158 if (__sighandler[s].old == (arch_sighandler_t) SIG_ERR ||
159 __sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
160 __sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
161 sa.sa_handler = __pthread_null_sighandler;
162 sigfillset(&sa.sa_mask);
163 sa.sa_flags = 0;
164 sigaction(s, &sa, NULL);
168 /* Test for cancellation */
169 if (sigsetjmp(jmpbuf, 1) == 0) {
170 THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
171 if (! (THREAD_GETMEM(self, p_canceled)
172 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
173 /* Reset the signal count */
174 THREAD_SETMEM(self, p_signal, 0);
175 /* Say we're in sigwait */
176 THREAD_SETMEM(self, p_sigwaiting, 1);
177 /* Unblock the signals and wait for them */
178 sigsuspend(&mask);
181 THREAD_SETMEM(self, p_cancel_jmp, NULL);
182 /* The signals are now reblocked. Check for cancellation */
183 pthread_testcancel();
184 /* We should have self->p_signal != 0 and equal to the signal received */
185 *sig = THREAD_GETMEM(self, p_signal);
186 return 0;
188 #ifdef SHARED
189 strong_alias (__pthread_sigwait, sigwait)
190 #endif
192 /* Redefine raise() to send signal to calling thread only,
193 as per POSIX 1003.1c */
194 int __pthread_raise (int sig)
196 int retcode = pthread_kill(pthread_self(), sig);
197 if (retcode == 0)
198 return 0;
199 else {
200 errno = retcode;
201 return -1;
204 #ifdef SHARED
205 strong_alias (__pthread_raise, raise)
206 #endif
208 /* This files handles cancellation internally. */
209 LIBC_CANCEL_HANDLED ();