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