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