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