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. */
14
15 /* Handling of signals */
16
17 #include <errno.h>
18 #include <signal.h>
19 #include <stdio.h>
20 #include <sys/syscall.h>
21 #include "pthread.h"
22 #include "internals.h"
23 #include "spinlock.h"
24 #include <bits/sigcontextinfo.h>
25
pthread_sigmask(int how,const sigset_t * newmask,sigset_t * oldmask)26 int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
27 {
28 sigset_t mask;
29
30 if (newmask != NULL) {
31 mask = *newmask;
32 /* Don't allow __pthread_sig_restart to be unmasked.
33 Don't allow __pthread_sig_cancel to be masked. */
34 switch(how) {
35 case SIG_SETMASK:
36 sigaddset(&mask, __pthread_sig_restart);
37 sigdelset(&mask, __pthread_sig_cancel);
38 if (__pthread_sig_debug > 0)
39 sigdelset(&mask, __pthread_sig_debug);
40 break;
41 case SIG_BLOCK:
42 sigdelset(&mask, __pthread_sig_cancel);
43 if (__pthread_sig_debug > 0)
44 sigdelset(&mask, __pthread_sig_debug);
45 break;
46 case SIG_UNBLOCK:
47 sigdelset(&mask, __pthread_sig_restart);
48 break;
49 }
50 newmask = &mask;
51 }
52 if (sigprocmask(how, newmask, oldmask) == -1)
53 return errno;
54 else
55 return 0;
56 }
57
pthread_kill(pthread_t thread,int signo)58 int pthread_kill(pthread_t thread, int signo)
59 {
60 pthread_handle handle = thread_handle(thread);
61 int pid;
62
63 __pthread_lock(&handle->h_lock, NULL);
64 if (invalid_handle(handle, thread)) {
65 __pthread_unlock(&handle->h_lock);
66 return ESRCH;
67 }
68 pid = handle->h_descr->p_pid;
69 __pthread_unlock(&handle->h_lock);
70 if (kill(pid, signo) == -1)
71 return errno;
72 else
73 return 0;
74 }
75
76 /* User-provided signal handlers */
77 typedef void (*arch_sighandler_t) __PMT ((int, SIGCONTEXT));
78 static union
79 {
80 arch_sighandler_t old;
81 void (*rt) (int, struct siginfo *, struct ucontext *);
82 } sighandler[NSIG];
83
84 /* The wrapper around user-provided signal handlers */
pthread_sighandler(int signo,SIGCONTEXT ctx)85 static void pthread_sighandler(int signo, SIGCONTEXT ctx)
86 {
87 pthread_descr self = thread_self();
88 char * in_sighandler;
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);
94 return;
95 }
96 /* Record that we're in a signal handler and call the user's
97 handler function */
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);
104 }
105
106 /* The same, this time for real-time signals. */
pthread_sighandler_rt(int signo,struct siginfo * si,struct ucontext * uc)107 static void pthread_sighandler_rt(int signo, struct siginfo *si,
108 struct ucontext *uc)
109 {
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);
117 return;
118 }
119 /* Record that we're in a signal handler and call the user's
120 handler function */
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);
127 }
128
129 /* The wrapper around sigaction. Install our own signal handler
130 around the signal. */
libpthread_hidden_proto(sigaction)131 libpthread_hidden_proto(sigaction)
132 int sigaction(int sig, const struct sigaction * act,
133 struct sigaction * oact)
134 {
135 struct sigaction newact;
136 struct sigaction *newactp;
137 void *save = NULL;
138
139 #ifdef DEBUG_PT
140 printf(__FUNCTION__": pthreads wrapper!\n");
141 #endif
142 if (sig == __pthread_sig_restart ||
143 sig == __pthread_sig_cancel ||
144 (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
145 return EINVAL;
146 if (sig > 0 && sig < NSIG)
147 save = sighandler[sig].old;
148 if (act)
149 {
150 newact = *act;
151 if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
152 && sig > 0 && sig < NSIG)
153 {
154 if (act->sa_flags & SA_SIGINFO)
155 newact.sa_handler = (__sighandler_t) pthread_sighandler_rt;
156 else
157 newact.sa_handler = (__sighandler_t) pthread_sighandler;
158 }
159 newactp = &newact;
160 if (sig > 0 && sig < NSIG)
161 sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
162 }
163 else
164 newactp = NULL;
165 if (__libc_sigaction(sig, newactp, oact) == -1)
166 {
167 if (act && sig > 0 && sig < NSIG)
168 sighandler[sig].old = save;
169 return -1;
170 }
171 #ifdef DEBUG_PT
172 printf(__FUNCTION__": sighandler installed, sigaction successful\n");
173 #endif
174 if (sig > 0 && sig < NSIG)
175 {
176 if (oact != NULL)
177 oact->sa_handler = save;
178 }
179 return 0;
180 }
libpthread_hidden_def(sigaction)181 libpthread_hidden_def(sigaction)
182
183 /* A signal handler that does nothing */
184 static void pthread_null_sighandler(int sig attribute_unused) { }
185
186 /* sigwait -- synchronously wait for a signal */
sigwait(const sigset_t * set,int * sig)187 int sigwait(const sigset_t * set, int * sig)
188 {
189 volatile pthread_descr self = thread_self();
190 sigset_t mask;
191 int s;
192 sigjmp_buf jmpbuf;
193 struct sigaction sa;
194
195 /* Get ready to block all signals except those in set
196 and the cancellation signal.
197 Also check that handlers are installed on all signals in set,
198 and if not, install our dummy handler. This is conformant to
199 POSIX: "The effect of sigwait() on the signal actions for the
200 signals in set is unspecified." */
201 __sigfillset(&mask);
202 sigdelset(&mask, __pthread_sig_cancel);
203 for (s = 1; s <= NSIG; s++) {
204 if (sigismember(set, s) &&
205 s != __pthread_sig_restart &&
206 s != __pthread_sig_cancel &&
207 s != __pthread_sig_debug) {
208 sigdelset(&mask, s);
209 if (sighandler[s].old == NULL ||
210 sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
211 sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
212 memset(&sa, 0, sizeof(sa));
213 sa.sa_handler = pthread_null_sighandler;
214 sigaction(s, &sa, NULL);
215 }
216 }
217 }
218 /* Test for cancellation */
219 if (sigsetjmp(jmpbuf, 1) == 0) {
220 THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
221 if (! (THREAD_GETMEM(self, p_canceled)
222 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
223 /* Reset the signal count */
224 THREAD_SETMEM(self, p_signal, 0);
225 /* Say we're in sigwait */
226 THREAD_SETMEM(self, p_sigwaiting, 1);
227 /* Unblock the signals and wait for them */
228 sigsuspend(&mask);
229 }
230 }
231 THREAD_SETMEM(self, p_cancel_jmp, NULL);
232 /* The signals are now reblocked. Check for cancellation */
233 pthread_testcancel();
234 /* We should have self->p_signal != 0 and equal to the signal received */
235 *sig = THREAD_GETMEM(self, p_signal);
236 return 0;
237 }
238
239 /* Redefine raise() to send signal to calling thread only,
240 as per POSIX 1003.1c */
libpthread_hidden_proto(raise)241 libpthread_hidden_proto(raise)
242 int raise (int sig) {
243 int ret;
244 pid_t tid;
245
246 tid = INLINE_SYSCALL(gettid, 0);
247 ret = INLINE_SYSCALL(tkill, 2, tid, sig);
248
249 return ret;
250 }
251 libpthread_hidden_def(raise)
252