]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libpthread/linuxthreads.old/signals.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libpthread / linuxthreads.old / signals.c
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
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
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 */
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.  */
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. */
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 }
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 */
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 */
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)