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