blob: 61b411aba3af2f466794bf912b7ad36d39aee998 [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 "pthread.h"
20#include "internals.h"
21#include "spinlock.h"
22
23/* mods for uClibc: __libc_sigaction is not in any standard headers */
24extern __typeof(sigaction) __libc_sigaction;
25
26int 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
58int 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
76union sighandler __sighandler[NSIG] =
77 { [1 ... NSIG - 1] = { (arch_sighandler_t) SIG_ERR } };
78
79/* The wrapper around sigaction. Install our own signal handler
80 around the signal. */
81int __pthread_sigaction(int sig, const struct sigaction * act,
82 struct sigaction * oact)
83{
84 struct sigaction newact;
85 struct sigaction *newactp;
86 __sighandler_t old = SIG_DFL;
87
88 if (sig == __pthread_sig_restart ||
89 sig == __pthread_sig_cancel ||
90 (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
91 {
92 __set_errno (EINVAL);
93 return -1;
94 }
95 if (sig > 0 && sig < NSIG)
96 old = (__sighandler_t) __sighandler[sig].old;
97 if (act)
98 {
99 newact = *act;
100 if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
101 && sig > 0 && sig < NSIG)
102 {
103 if (act->sa_flags & SA_SIGINFO)
104 newact.sa_handler = (__sighandler_t) __pthread_sighandler_rt;
105 else
106 newact.sa_handler = (__sighandler_t) __pthread_sighandler;
107 if (old == SIG_IGN || old == SIG_DFL || old == SIG_ERR)
108 __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
109 }
110 newactp = &newact;
111 }
112 else
113 newactp = NULL;
114 if (__libc_sigaction(sig, newactp, oact) == -1)
115 {
116 if (act && (sig > 0 && sig < NSIG))
117 __sighandler[sig].old = (arch_sighandler_t) old;
118 return -1;
119 }
120 if (sig > 0 && sig < NSIG)
121 {
122 if (oact != NULL
123 /* We may have inherited SIG_IGN from the parent, so return the
124 kernel's idea of the signal handler the first time
125 through. */
126 && old != SIG_ERR)
127 oact->sa_handler = old;
128 if (act)
129 /* For the assignment it does not matter whether it's a normal
130 or real-time signal. */
131 __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
132 }
133 return 0;
134}
135#ifdef SHARED
136strong_alias(__pthread_sigaction, __sigaction)
137strong_alias(__pthread_sigaction, sigaction)
138#endif
139
140/* sigwait -- synchronously wait for a signal */
141int __pthread_sigwait(const sigset_t * set, int * sig)
142{
143 __volatile__ pthread_descr self = thread_self();
144 sigset_t mask;
145 int s;
146 sigjmp_buf jmpbuf;
147 struct sigaction sa;
148
149 /* Get ready to block all signals except those in set
150 and the cancellation signal.
151 Also check that handlers are installed on all signals in set,
152 and if not, install our dummy handler. This is conformant to
153 POSIX: "The effect of sigwait() on the signal actions for the
154 signals in set is unspecified." */
155 __sigfillset(&mask);
156 sigdelset(&mask, __pthread_sig_cancel);
157 for (s = 1; s < NSIG; s++) {
158 if (sigismember(set, s) &&
159 s != __pthread_sig_restart &&
160 s != __pthread_sig_cancel &&
161 s != __pthread_sig_debug) {
162 sigdelset(&mask, s);
163 if (__sighandler[s].old == (arch_sighandler_t) SIG_ERR ||
164 __sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
165 __sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
166 sa.sa_handler = __pthread_null_sighandler;
167 __sigfillset(&sa.sa_mask);
168 sa.sa_flags = 0;
169 sigaction(s, &sa, NULL);
170 }
171 }
172 }
173 /* Test for cancellation */
174 if (sigsetjmp(jmpbuf, 1) == 0) {
175 THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
176 if (! (THREAD_GETMEM(self, p_canceled)
177 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
178 /* Reset the signal count */
179 THREAD_SETMEM(self, p_signal, 0);
180 /* Say we're in sigwait */
181 THREAD_SETMEM(self, p_sigwaiting, 1);
182 /* Unblock the signals and wait for them */
183 sigsuspend(&mask);
184 }
185 }
186 THREAD_SETMEM(self, p_cancel_jmp, NULL);
187 /* The signals are now reblocked. Check for cancellation */
188 pthread_testcancel();
189 /* We should have self->p_signal != 0 and equal to the signal received */
190 *sig = THREAD_GETMEM(self, p_signal);
191 return 0;
192}
193#ifdef SHARED
194strong_alias (__pthread_sigwait, sigwait)
195#endif
196
197/* Redefine raise() to send signal to calling thread only,
198 as per POSIX 1003.1c */
199int __pthread_raise (int sig)
200{
201 int retcode = pthread_kill(pthread_self(), sig);
202 if (retcode == 0)
203 return 0;
204 else {
205 errno = retcode;
206 return -1;
207 }
208}
209#ifdef SHARED
210strong_alias (__pthread_raise, raise)
211#endif
212
213/* This files handles cancellation internally. */
214LIBC_CANCEL_HANDLED ();