1 /* Linuxthreads - a simple clone()-based implementation of Posix */
2 /* threads for Linux. */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
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. */
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 */
20 #include <sys/syscall.h>
22 #include "internals.h"
24 #include <bits/sigcontextinfo.h>
26 int pthread_sigmask(int how
, const sigset_t
* newmask
, sigset_t
* oldmask
)
30 if (newmask
!= NULL
) {
32 /* Don't allow __pthread_sig_restart to be unmasked.
33 Don't allow __pthread_sig_cancel to be masked. */
36 sigaddset(&mask
, __pthread_sig_restart
);
37 sigdelset(&mask
, __pthread_sig_cancel
);
38 if (__pthread_sig_debug
> 0)
39 sigdelset(&mask
, __pthread_sig_debug
);
42 sigdelset(&mask
, __pthread_sig_cancel
);
43 if (__pthread_sig_debug
> 0)
44 sigdelset(&mask
, __pthread_sig_debug
);
47 sigdelset(&mask
, __pthread_sig_restart
);
52 if (sigprocmask(how
, newmask
, oldmask
) == -1)
58 int pthread_kill(pthread_t thread
, int signo
)
60 pthread_handle handle
= thread_handle(thread
);
63 __pthread_lock(&handle
->h_lock
, NULL
);
64 if (invalid_handle(handle
, thread
)) {
65 __pthread_unlock(&handle
->h_lock
);
68 pid
= handle
->h_descr
->p_pid
;
69 __pthread_unlock(&handle
->h_lock
);
70 if (kill(pid
, signo
) == -1)
76 /* User-provided signal handlers */
77 typedef void (*arch_sighandler_t
) __PMT ((int, SIGCONTEXT
));
80 arch_sighandler_t old
;
81 void (*rt
) (int, struct siginfo
*, struct ucontext
*);
84 /* The wrapper around user-provided signal handlers */
85 static void pthread_sighandler(int signo
, SIGCONTEXT ctx
)
87 pthread_descr self
= thread_self();
89 /* If we're in a sigwait operation, just record the signal received
90 and return without calling the user's handler */
91 if (THREAD_GETMEM(self
, p_sigwaiting
)) {
92 THREAD_SETMEM(self
, p_sigwaiting
, 0);
93 THREAD_SETMEM(self
, p_signal
, signo
);
96 /* Record that we're in a signal handler and call the user's
98 in_sighandler
= THREAD_GETMEM(self
, p_in_sighandler
);
99 if (in_sighandler
== NULL
)
100 THREAD_SETMEM(self
, p_in_sighandler
, CURRENT_STACK_FRAME
);
101 sighandler
[signo
].old(signo
, SIGCONTEXT_EXTRA_ARGS ctx
);
102 if (in_sighandler
== NULL
)
103 THREAD_SETMEM(self
, p_in_sighandler
, NULL
);
106 /* The same, this time for real-time signals. */
107 static void pthread_sighandler_rt(int signo
, struct siginfo
*si
,
110 pthread_descr self
= thread_self();
111 char * in_sighandler
;
112 /* If we're in a sigwait operation, just record the signal received
113 and return without calling the user's handler */
114 if (THREAD_GETMEM(self
, p_sigwaiting
)) {
115 THREAD_SETMEM(self
, p_sigwaiting
, 0);
116 THREAD_SETMEM(self
, p_signal
, signo
);
119 /* Record that we're in a signal handler and call the user's
121 in_sighandler
= THREAD_GETMEM(self
, p_in_sighandler
);
122 if (in_sighandler
== NULL
)
123 THREAD_SETMEM(self
, p_in_sighandler
, CURRENT_STACK_FRAME
);
124 sighandler
[signo
].rt(signo
, si
, uc
);
125 if (in_sighandler
== NULL
)
126 THREAD_SETMEM(self
, p_in_sighandler
, NULL
);
129 /* The wrapper around sigaction. Install our own signal handler
130 around the signal. */
131 libpthread_hidden_proto(sigaction
)
132 int sigaction(int sig
, const struct sigaction
* act
,
133 struct sigaction
* oact
)
135 struct sigaction newact
;
136 struct sigaction
*newactp
;
139 printf(__FUNCTION__
": pthreads wrapper!\n");
141 if (sig
== __pthread_sig_restart
||
142 sig
== __pthread_sig_cancel
||
143 (sig
== __pthread_sig_debug
&& __pthread_sig_debug
> 0))
148 if (act
->sa_handler
!= SIG_IGN
&& act
->sa_handler
!= SIG_DFL
149 && sig
> 0 && sig
< NSIG
)
151 if (act
->sa_flags
& SA_SIGINFO
)
152 newact
.sa_handler
= (__sighandler_t
) pthread_sighandler_rt
;
154 newact
.sa_handler
= (__sighandler_t
) pthread_sighandler
;
160 if (__libc_sigaction(sig
, newactp
, oact
) == -1)
163 printf(__FUNCTION__
": sighandler installed, sigaction successful\n");
165 if (sig
> 0 && sig
< NSIG
)
168 oact
->sa_handler
= (__sighandler_t
) sighandler
[sig
].old
;
170 /* For the assignment is does not matter whether it's a normal
171 or real-time signal. */
172 sighandler
[sig
].old
= (arch_sighandler_t
) act
->sa_handler
;
176 libpthread_hidden_def(sigaction
)
178 /* A signal handler that does nothing */
179 static void pthread_null_sighandler(int sig attribute_unused
) { }
181 /* sigwait -- synchronously wait for a signal */
182 int sigwait(const sigset_t
* set
, int * sig
)
184 volatile pthread_descr self
= thread_self();
190 /* Get ready to block all signals except those in set
191 and the cancellation signal.
192 Also check that handlers are installed on all signals in set,
193 and if not, install our dummy handler. This is conformant to
194 POSIX: "The effect of sigwait() on the signal actions for the
195 signals in set is unspecified." */
197 sigdelset(&mask
, __pthread_sig_cancel
);
198 for (s
= 1; s
<= NSIG
; s
++) {
199 if (sigismember(set
, s
) &&
200 s
!= __pthread_sig_restart
&&
201 s
!= __pthread_sig_cancel
&&
202 s
!= __pthread_sig_debug
) {
204 if (sighandler
[s
].old
== NULL
||
205 sighandler
[s
].old
== (arch_sighandler_t
) SIG_DFL
||
206 sighandler
[s
].old
== (arch_sighandler_t
) SIG_IGN
) {
207 memset(&sa
, 0, sizeof(sa
));
208 sa
.sa_handler
= pthread_null_sighandler
;
209 sigaction(s
, &sa
, NULL
);
213 /* Test for cancellation */
214 if (sigsetjmp(jmpbuf
, 1) == 0) {
215 THREAD_SETMEM(self
, p_cancel_jmp
, &jmpbuf
);
216 if (! (THREAD_GETMEM(self
, p_canceled
)
217 && THREAD_GETMEM(self
, p_cancelstate
) == PTHREAD_CANCEL_ENABLE
)) {
218 /* Reset the signal count */
219 THREAD_SETMEM(self
, p_signal
, 0);
220 /* Say we're in sigwait */
221 THREAD_SETMEM(self
, p_sigwaiting
, 1);
222 /* Unblock the signals and wait for them */
226 THREAD_SETMEM(self
, p_cancel_jmp
, NULL
);
227 /* The signals are now reblocked. Check for cancellation */
228 pthread_testcancel();
229 /* We should have self->p_signal != 0 and equal to the signal received */
230 *sig
= THREAD_GETMEM(self
, p_signal
);
234 /* Redefine raise() to send signal to calling thread only,
235 as per POSIX 1003.1c */
236 libpthread_hidden_proto(raise
)
237 int raise (int sig
) {
241 tid
= INLINE_SYSCALL(gettid
, 0);
242 ret
= INLINE_SYSCALL(tkill
, 2, tid
, sig
);
246 libpthread_hidden_def(raise
)