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 "internals.h"
23 #include <sigcontextinfo.h>
25 int pthread_sigmask(int how
, const sigset_t
* newmask
, sigset_t
* oldmask
)
29 if (newmask
!= NULL
) {
31 /* Don't allow __pthread_sig_restart to be unmasked.
32 Don't allow __pthread_sig_cancel to be masked. */
35 sigaddset(&mask
, __pthread_sig_restart
);
36 sigdelset(&mask
, __pthread_sig_cancel
);
39 sigdelset(&mask
, __pthread_sig_cancel
);
42 sigdelset(&mask
, __pthread_sig_restart
);
47 if (sigprocmask(how
, newmask
, oldmask
) == -1)
53 int pthread_kill(pthread_t thread
, int signo
)
55 pthread_handle handle
= thread_handle(thread
);
58 __pthread_lock(&handle
->h_lock
, NULL
);
59 if (invalid_handle(handle
, thread
)) {
60 __pthread_unlock(&handle
->h_lock
);
63 pid
= handle
->h_descr
->p_pid
;
64 __pthread_unlock(&handle
->h_lock
);
65 if (kill(pid
, signo
) == -1)
71 /* User-provided signal handlers */
72 typedef void (*arch_sighandler_t
) (int, SIGCONTEXT
);
75 arch_sighandler_t old
;
76 void (*rt
) (int, struct siginfo
*, struct ucontext
*);
79 /* The wrapper around user-provided signal handlers */
80 static void pthread_sighandler(int signo
, SIGCONTEXT ctx
)
85 asm volatile ("movw %w0,%%gs" : : "r" (ctx
.gs
));
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
);
95 /* Record that we're in a signal handler and call the user's
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
,
110 char * in_sighandler
;
112 asm volatile ("movw %w0,%%gs" : : "r" (uc
->uc_mcontext
.gregs
[GS
]));
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
);
122 /* Record that we're in a signal handler and call the user's
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))
147 if (act
->sa_handler
!= SIG_IGN
&& act
->sa_handler
!= SIG_DFL
148 && sig
> 0 && sig
< NSIG
)
150 if (act
->sa_flags
& SA_SIGINFO
)
151 newact
.sa_handler
= (__sighandler_t
) pthread_sighandler_rt
;
153 newact
.sa_handler
= (__sighandler_t
) pthread_sighandler
;
159 if (__sigaction(sig
, newactp
, oact
) == -1)
161 if (sig
> 0 && sig
< NSIG
)
164 oact
->sa_handler
= (__sighandler_t
) sighandler
[sig
].old
;
166 /* For the assignment is does not matter whether it's a normal
167 or real-time signal. */
168 sighandler
[sig
].old
= (arch_sighandler_t
) act
->sa_handler
;
173 /* A signal handler that does nothing */
174 static void pthread_null_sighandler(int sig
) { }
176 /* sigwait -- synchronously wait for a signal */
177 int sigwait(const sigset_t
* set
, int * sig
)
179 volatile pthread_descr self
= thread_self();
185 /* Get ready to block all signals except those in set
186 and the cancellation signal.
187 Also check that handlers are installed on all signals in set,
188 and if not, install our dummy handler. This is conformant to
189 POSIX: "The effect of sigwait() on the signal actions for the
190 signals in set is unspecified." */
192 sigdelset(&mask
, __pthread_sig_cancel
);
193 for (s
= 1; s
<= NSIG
; s
++) {
194 if (sigismember(set
, s
) &&
195 s
!= __pthread_sig_restart
&&
196 s
!= __pthread_sig_cancel
&&
197 s
!= __pthread_sig_debug
) {
199 if (sighandler
[s
].old
== NULL
||
200 sighandler
[s
].old
== (arch_sighandler_t
) SIG_DFL
||
201 sighandler
[s
].old
== (arch_sighandler_t
) SIG_IGN
) {
202 sa
.sa_handler
= pthread_null_sighandler
;
203 sigemptyset(&sa
.sa_mask
);
205 sigaction(s
, &sa
, NULL
);
209 /* Test for cancellation */
210 if (sigsetjmp(jmpbuf
, 1) == 0) {
211 THREAD_SETMEM(self
, p_cancel_jmp
, &jmpbuf
);
212 if (! (THREAD_GETMEM(self
, p_canceled
)
213 && THREAD_GETMEM(self
, p_cancelstate
) == PTHREAD_CANCEL_ENABLE
)) {
214 /* Reset the signal count */
215 THREAD_SETMEM(self
, p_signal
, 0);
216 /* Say we're in sigwait */
217 THREAD_SETMEM(self
, p_sigwaiting
, 1);
218 /* Unblock the signals and wait for them */
222 THREAD_SETMEM(self
, p_cancel_jmp
, NULL
);
223 /* The signals are now reblocked. Check for cancellation */
224 pthread_testcancel();
225 /* We should have self->p_signal != 0 and equal to the signal received */
226 *sig
= THREAD_GETMEM(self
, p_signal
);
230 /* Redefine raise() to send signal to calling thread only,
231 as per POSIX 1003.1c */
234 int retcode
= pthread_kill(pthread_self(), sig
);