]>
Commit | Line | Data |
---|---|---|
28f540f4 | 1 | /* Implementing POSIX.1 signals under the Hurd. |
6d7e8eda | 2 | Copyright (C) 1993-2023 Free Software Foundation, Inc. |
10dc2a90 | 3 | This file is part of the GNU C Library. |
28f540f4 | 4 | |
10dc2a90 | 5 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
28f540f4 | 9 | |
10dc2a90 UD |
10 | The GNU C Library 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 GNU | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
28f540f4 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
28f540f4 RM |
18 | |
19 | #ifndef _HURD_SIGNAL_H | |
20 | ||
21 | #define _HURD_SIGNAL_H 1 | |
22 | #include <features.h> | |
28f540f4 | 23 | |
50e16f85 | 24 | #define __need_size_t |
28f540f4 RM |
25 | #define __need_NULL |
26 | #include <stddef.h> | |
27 | ||
28 | #include <mach/mach_types.h> | |
29 | #include <mach/port.h> | |
30 | #include <mach/message.h> | |
31 | #include <hurd/hurd_types.h> | |
32 | #include <signal.h> | |
33 | #include <errno.h> | |
974393ea | 34 | #include <bits/types/error_t.h> |
ba89615d ST |
35 | #include <bits/types/stack_t.h> |
36 | #include <bits/types/sigset_t.h> | |
a1ede3a4 | 37 | #include <bits/sigaction.h> |
28f540f4 RM |
38 | #include <hurd/msg.h> |
39 | ||
21297437 | 40 | #include <setjmp.h> /* For `jmp_buf'. */ |
28f540f4 | 41 | #include <spin-lock.h> |
10dc2a90 | 42 | struct hurd_signal_preemptor; /* <hurd/sigpreempt.h> */ |
625ba81e | 43 | #if defined __USE_EXTERN_INLINES && defined _LIBC |
2f8902cc ST |
44 | # if IS_IN (libc) || IS_IN (libpthread) |
45 | # include <sigsetops.h> | |
46 | # endif | |
625ba81e | 47 | #endif |
28f540f4 RM |
48 | |
49 | ||
93a470c7 RM |
50 | /* Full details of a signal. */ |
51 | struct hurd_signal_detail | |
52 | { | |
53 | /* Codes from origination Mach exception_raise message. */ | |
54 | integer_t exc, exc_code, exc_subcode; | |
55 | /* Sigcode as passed or computed from exception codes. */ | |
56 | integer_t code; | |
57 | /* Error code as passed or extracted from exception codes. */ | |
58 | error_t error; | |
59 | }; | |
60 | ||
61 | ||
28f540f4 RM |
62 | /* Per-thread signal state. */ |
63 | ||
64 | struct hurd_sigstate | |
65 | { | |
8f0c527e | 66 | spin_lock_t critical_section_lock; /* Held if in critical section. */ |
28f540f4 | 67 | |
8f0c527e | 68 | spin_lock_t lock; /* Locks most of the rest of the structure. */ |
28f540f4 | 69 | |
5c06743c | 70 | /* The signal state holds a reference on the thread port. */ |
28f540f4 | 71 | thread_t thread; |
5c06743c | 72 | |
28f540f4 RM |
73 | struct hurd_sigstate *next; /* Linked-list of thread sigstates. */ |
74 | ||
75 | sigset_t blocked; /* What signals are blocked. */ | |
76 | sigset_t pending; /* Pending signals, possibly blocked. */ | |
653d74f1 JK |
77 | |
78 | /* Signal handlers. ACTIONS[0] is used to mark the threads with POSIX | |
79 | semantics: if sa_handler is SIG_IGN instead of SIG_DFL, this thread | |
80 | will receive global signals and use the process-wide action vector | |
81 | instead of this one. */ | |
ba89615d | 82 | struct sigaction actions[_NSIG]; |
653d74f1 | 83 | |
75531318 | 84 | stack_t sigaltstack; |
71733723 | 85 | |
10dc2a90 | 86 | /* Chain of thread-local signal preemptors; see <hurd/sigpreempt.h>. |
71733723 RM |
87 | Each element of this chain is in local stack storage, and the chain |
88 | parallels the stack: the head of this chain is in the innermost | |
89 | stack frame, and each next element in an outermore frame. */ | |
10dc2a90 | 90 | struct hurd_signal_preemptor *preemptors; |
71733723 | 91 | |
93a470c7 | 92 | /* For each signal that may be pending, the details to deliver it with. */ |
ba89615d | 93 | struct hurd_signal_detail pending_data[_NSIG]; |
28f540f4 RM |
94 | |
95 | /* If `suspended' is set when this thread gets a signal, | |
96 | the signal thread sends an empty message to it. */ | |
97 | mach_port_t suspended; | |
98 | ||
99 | /* The following members are not locked. They are used only by this | |
100 | thread, or by the signal thread with this thread suspended. */ | |
101 | ||
102 | volatile mach_port_t intr_port; /* Port interruptible RPC was sent on. */ | |
103 | ||
104 | /* If this is not null, the thread is in sigreturn awaiting delivery of | |
105 | pending signals. This context (the machine-dependent portions only) | |
106 | will be passed to sigreturn after running the handler for a pending | |
107 | signal, instead of examining the thread state. */ | |
108 | struct sigcontext *context; | |
1474b80f RM |
109 | |
110 | /* This is the head of the thread's list of active resources; see | |
111 | <hurd/userlink.h> for details. This member is only used by the | |
112 | thread itself, and always inside a critical section. */ | |
113 | struct hurd_userlink *active_resources; | |
54da5be3 | 114 | |
207eb76a RM |
115 | /* These are locked normally. */ |
116 | int cancel; /* Flag set by hurd_thread_cancel. */ | |
117 | void (*cancel_hook) (void); /* Called on cancellation. */ | |
28f540f4 RM |
118 | }; |
119 | ||
120 | /* Linked list of states of all threads whose state has been asked for. */ | |
121 | ||
122 | extern struct hurd_sigstate *_hurd_sigstates; | |
123 | ||
5c06743c RB |
124 | /* Get the sigstate of a given thread. If there was no sigstate for |
125 | the thread, one is created, and the thread gains a reference. If | |
126 | the given thread is MACH_PORT_NULL, return the global sigstate. */ | |
28f540f4 RM |
127 | |
128 | extern struct hurd_sigstate *_hurd_thread_sigstate (thread_t); | |
129 | ||
130 | /* Get the sigstate of the current thread. | |
131 | This uses a per-thread variable to optimize the lookup. */ | |
d6e2f671 RM |
132 | |
133 | extern struct hurd_sigstate *_hurd_self_sigstate (void) | |
134 | /* This declaration tells the compiler that the value is constant. | |
135 | We assume this won't be called twice from the same stack frame | |
136 | by different threads. */ | |
137 | __attribute__ ((__const__)); | |
138 | ||
653d74f1 JK |
139 | /* Process-wide signal state. */ |
140 | ||
141 | extern struct hurd_sigstate *_hurd_global_sigstate; | |
142 | ||
143 | /* Mark the given thread as a process-wide signal receiver. */ | |
144 | ||
145 | extern void _hurd_sigstate_set_global_rcv (struct hurd_sigstate *ss); | |
146 | ||
147 | /* A thread can either use its own action vector and pending signal set | |
148 | or use the global ones, depending on wether it has been marked as a | |
149 | global receiver. The accessors below take that into account. */ | |
150 | ||
151 | extern void _hurd_sigstate_lock (struct hurd_sigstate *ss); | |
152 | extern struct sigaction *_hurd_sigstate_actions (struct hurd_sigstate *ss); | |
153 | extern sigset_t _hurd_sigstate_pending (const struct hurd_sigstate *ss); | |
154 | extern void _hurd_sigstate_unlock (struct hurd_sigstate *ss); | |
155 | ||
156 | /* Used by libpthread to remove stale sigstate structures. */ | |
157 | extern void _hurd_sigstate_delete (thread_t thread); | |
158 | ||
6f9dc08b | 159 | #ifndef _HURD_SIGNAL_H_EXTERN_INLINE |
b037a293 | 160 | #define _HURD_SIGNAL_H_EXTERN_INLINE __extern_inline |
6f9dc08b RM |
161 | #endif |
162 | ||
28f6186f | 163 | #if defined __USE_EXTERN_INLINES && defined _LIBC |
2f8902cc | 164 | # if IS_IN (libc) |
6f9dc08b | 165 | _HURD_SIGNAL_H_EXTERN_INLINE struct hurd_sigstate * |
28f540f4 RM |
166 | _hurd_self_sigstate (void) |
167 | { | |
b65a82e4 | 168 | if (THREAD_GETMEM (THREAD_SELF, _hurd_sigstate) == NULL) |
5c06743c RB |
169 | { |
170 | thread_t self = __mach_thread_self (); | |
171 | THREAD_SETMEM (THREAD_SELF, _hurd_sigstate, _hurd_thread_sigstate (self)); | |
172 | __mach_port_deallocate (__mach_task_self (), self); | |
173 | } | |
b65a82e4 | 174 | return THREAD_GETMEM (THREAD_SELF, _hurd_sigstate); |
28f540f4 | 175 | } |
2f8902cc | 176 | # endif |
28f6186f | 177 | #endif |
28f540f4 RM |
178 | \f |
179 | /* Thread listening on our message port; also called the "signal thread". */ | |
180 | ||
181 | extern thread_t _hurd_msgport_thread; | |
182 | ||
183 | /* Our message port. We hold the receive right and _hurd_msgport_thread | |
184 | listens for messages on it. We also hold a send right, for convenience. */ | |
185 | ||
186 | extern mach_port_t _hurd_msgport; | |
187 | ||
28f540f4 RM |
188 | /* Resource limit on core file size. Enforced by hurdsig.c. */ |
189 | extern int _hurd_core_limit; | |
190 | \f | |
191 | /* Critical sections. | |
192 | ||
193 | A critical section is a section of code which cannot safely be interrupted | |
194 | to run a signal handler; for example, code that holds any lock cannot be | |
195 | interrupted lest the signal handler try to take the same lock and | |
e87d8ada ST |
196 | deadlock result. |
197 | ||
198 | As a consequence, a critical section will see its RPCs return EINTR, even if | |
199 | SA_RESTART is set! In that case, the critical section should be left, so | |
200 | that the handler can run, and the whole critical section be tried again, to | |
066ae81e | 201 | avoid unexpectingly exposing EINTR to the application. */ |
28f540f4 | 202 | |
28f6186f ST |
203 | extern void *_hurd_critical_section_lock (void); |
204 | ||
205 | #if defined __USE_EXTERN_INLINES && defined _LIBC | |
2f8902cc | 206 | # if IS_IN (libc) |
6f9dc08b | 207 | _HURD_SIGNAL_H_EXTERN_INLINE void * |
28f540f4 RM |
208 | _hurd_critical_section_lock (void) |
209 | { | |
dc33bef3 ST |
210 | struct hurd_sigstate *ss; |
211 | ||
212 | #ifdef __LIBC_NO_TLS | |
6dbe9dca | 213 | if (__LIBC_NO_TLS ()) |
dc33bef3 ST |
214 | /* TLS is currently initializing, no need to enter critical section. */ |
215 | return NULL; | |
216 | #endif | |
217 | ||
b65a82e4 | 218 | ss = THREAD_GETMEM (THREAD_SELF, _hurd_sigstate); |
28f540f4 | 219 | if (ss == NULL) |
28f540f4 | 220 | { |
5c06743c RB |
221 | thread_t self = __mach_thread_self (); |
222 | ||
8f0c527e RM |
223 | /* The thread variable is unset; this must be the first time we've |
224 | asked for it. In this case, the critical section flag cannot | |
225 | possible already be set. Look up our sigstate structure the slow | |
e9a5bc1c | 226 | way. */ |
5c06743c RB |
227 | ss = _hurd_thread_sigstate (self); |
228 | THREAD_SETMEM (THREAD_SELF, _hurd_sigstate, ss); | |
229 | __mach_port_deallocate (__mach_task_self (), self); | |
28f540f4 RM |
230 | } |
231 | ||
8f0c527e RM |
232 | if (! __spin_try_lock (&ss->critical_section_lock)) |
233 | /* We are already in a critical section, so do nothing. */ | |
234 | return NULL; | |
28f540f4 | 235 | |
8f0c527e RM |
236 | /* With the critical section lock held no signal handler will run. |
237 | Return our sigstate pointer; this will be passed to | |
238 | _hurd_critical_section_unlock to unlock it. */ | |
28f540f4 RM |
239 | return ss; |
240 | } | |
2f8902cc | 241 | # endif |
28f6186f | 242 | #endif |
28f540f4 | 243 | |
28f6186f ST |
244 | extern void _hurd_critical_section_unlock (void *our_lock); |
245 | ||
246 | #if defined __USE_EXTERN_INLINES && defined _LIBC | |
2f8902cc | 247 | # if IS_IN (libc) |
6f9dc08b | 248 | _HURD_SIGNAL_H_EXTERN_INLINE void |
28f540f4 RM |
249 | _hurd_critical_section_unlock (void *our_lock) |
250 | { | |
251 | if (our_lock == NULL) | |
252 | /* The critical section lock was held when we began. Do nothing. */ | |
253 | return; | |
254 | else | |
255 | { | |
8f0c527e | 256 | /* It was us who acquired the critical section lock. Unlock it. */ |
f96ec27a | 257 | struct hurd_sigstate *ss = (struct hurd_sigstate *) our_lock; |
28f540f4 | 258 | sigset_t pending; |
653d74f1 | 259 | _hurd_sigstate_lock (ss); |
8f0c527e | 260 | __spin_unlock (&ss->critical_section_lock); |
653d74f1 JK |
261 | pending = _hurd_sigstate_pending(ss) & ~ss->blocked; |
262 | _hurd_sigstate_unlock (ss); | |
21297437 | 263 | if (! __sigisemptyset (&pending)) |
28f540f4 RM |
264 | /* There are unblocked signals pending, which weren't |
265 | delivered because we were in the critical section. | |
266 | Tell the signal thread to deliver them now. */ | |
8f0c527e | 267 | __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ()); |
28f540f4 RM |
268 | } |
269 | } | |
2f8902cc | 270 | # endif |
28f6186f | 271 | #endif |
28f540f4 RM |
272 | |
273 | /* Convenient macros for simple uses of critical sections. | |
274 | These two must be used as a pair at the same C scoping level. */ | |
275 | ||
276 | #define HURD_CRITICAL_BEGIN \ | |
277 | { void *__hurd_critical__ = _hurd_critical_section_lock () | |
278 | #define HURD_CRITICAL_END \ | |
279 | _hurd_critical_section_unlock (__hurd_critical__); } while (0) | |
c3b287be ST |
280 | |
281 | /* This one can be used inside the C scoping level, for early exits. */ | |
282 | #define HURD_CRITICAL_UNLOCK \ | |
283 | _hurd_critical_section_unlock (__hurd_critical__); | |
28f540f4 | 284 | \f |
62495816 RM |
285 | /* Initialize the signal code, and start the signal thread. |
286 | Arguments give the "init ints" from exec_startup. */ | |
28f540f4 | 287 | |
62495816 | 288 | extern void _hurdsig_init (const int *intarray, size_t intarraysize); |
28f540f4 RM |
289 | |
290 | /* Initialize proc server-assisted fault recovery for the signal thread. */ | |
291 | ||
292 | extern void _hurdsig_fault_init (void); | |
293 | ||
93a470c7 RM |
294 | /* Raise a signal as described by SIGNO an DETAIL, on the thread whose |
295 | sigstate SS points to. If SS is a null pointer, this instead affects | |
296 | the calling thread. */ | |
28f540f4 | 297 | |
ee0976f7 ST |
298 | extern int _hurd_raise_signal (struct hurd_sigstate *ss, int signo, |
299 | const struct hurd_signal_detail *detail); | |
28f540f4 RM |
300 | |
301 | /* Translate a Mach exception into a signal (machine-dependent). */ | |
302 | ||
0e3426bb RM |
303 | extern void _hurd_exception2signal (struct hurd_signal_detail *detail, |
304 | int *signo); | |
28f540f4 | 305 | |
d865ff74 JK |
306 | /* Translate a Mach exception into a signal with a legacy sigcode. */ |
307 | ||
308 | extern void _hurd_exception2signal_legacy (struct hurd_signal_detail *detail, | |
309 | int *signo); | |
310 | ||
28f540f4 RM |
311 | |
312 | /* Make the thread described by SS take the signal described by SIGNO and | |
93a470c7 | 313 | DETAIL. If the process is traced, this will in fact stop with a SIGNO |
28f540f4 RM |
314 | as the stop signal unless UNTRACED is nonzero. When the signal can be |
315 | considered delivered, sends a sig_post reply message on REPLY_PORT | |
316 | indicating success. SS is not locked. */ | |
317 | ||
318 | extern void _hurd_internal_post_signal (struct hurd_sigstate *ss, | |
93a470c7 RM |
319 | int signo, |
320 | struct hurd_signal_detail *detail, | |
28f540f4 RM |
321 | mach_port_t reply_port, |
322 | mach_msg_type_name_t reply_port_type, | |
323 | int untraced); | |
324 | ||
325 | /* Set up STATE and SS to handle signal SIGNO by running HANDLER. If | |
326 | RPC_WAIT is nonzero, the thread needs to wait for a pending RPC to | |
327 | finish before running the signal handler. The handler is passed SIGNO, | |
328 | SIGCODE, and the returned `struct sigcontext' (which resides on the | |
329 | stack the handler will use, and which describes the state of the thread | |
330 | encoded in STATE before running the handler). */ | |
331 | ||
332 | struct machine_thread_all_state; | |
333 | extern struct sigcontext * | |
e42efa01 ST |
334 | _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action, |
335 | __sighandler_t handler, | |
0e3426bb | 336 | int signo, struct hurd_signal_detail *detail, |
28f540f4 RM |
337 | int rpc_wait, struct machine_thread_all_state *state); |
338 | ||
339 | /* Function run by the signal thread to receive from the signal port. */ | |
340 | ||
9446e02b | 341 | extern void *_hurd_msgport_receive (void *arg); |
28f540f4 | 342 | |
28f540f4 RM |
343 | /* Set up STATE with a thread state that, when resumed, is |
344 | like `longjmp (_hurd_sigthread_fault_env, 1)'. */ | |
345 | ||
346 | extern void _hurd_initialize_fault_recovery_state (void *state); | |
347 | ||
54da5be3 RM |
348 | /* Set up STATE to do the equivalent of `longjmp (ENV, VAL);'. */ |
349 | ||
350 | extern void _hurd_longjmp_thread_state (void *state, jmp_buf env, int value); | |
28f540f4 RM |
351 | |
352 | /* Function run for SIGINFO when its action is SIG_DFL and the current | |
353 | process is the session leader. */ | |
354 | ||
355 | extern void _hurd_siginfo_handler (int); | |
356 | ||
3d46e1cd TBB |
357 | /* Replacement for mach_msg used in RPCs to provide Hurd interruption |
358 | semantics. Args are all the same as for mach_msg. intr-rpc.h arranges | |
359 | for this version to be used automatically by the RPC stubs the library | |
360 | builds in place of the normal mach_msg. */ | |
361 | error_t _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg, | |
362 | mach_msg_option_t option, | |
363 | mach_msg_size_t send_size, | |
364 | mach_msg_size_t rcv_size, | |
365 | mach_port_t rcv_name, | |
366 | mach_msg_timeout_t timeout, | |
367 | mach_port_t notify); | |
368 | ||
28f540f4 | 369 | |
54da5be3 RM |
370 | /* Milliseconds to wait for an interruptible RPC to return after |
371 | `interrupt_operation'. */ | |
372 | ||
373 | extern mach_msg_timeout_t _hurd_interrupted_rpc_timeout; | |
28f540f4 RM |
374 | |
375 | ||
376 | /* Mask of signals that cannot be caught, blocked, or ignored. */ | |
377 | #define _SIG_CANT_MASK (__sigmask (SIGSTOP) | __sigmask (SIGKILL)) | |
378 | ||
379 | /* Do an RPC to a process's message port. | |
380 | ||
381 | Each argument is an expression which returns an error code; each | |
382 | expression may be evaluated several times. FETCH_MSGPORT_EXPR should | |
383 | fetch the appropriate message port and store it in the local variable | |
384 | `msgport'; it will be deallocated after use. FETCH_REFPORT_EXPR should | |
385 | fetch the appropriate message port and store it in the local variable | |
386 | `refport' (if no reference port is needed in the call, then | |
387 | FETCH_REFPORT_EXPR should be simply KERN_SUCCESS or 0); if | |
388 | DEALLOC_REFPORT evaluates to nonzero it will be deallocated after use, | |
389 | otherwise the FETCH_REFPORT_EXPR must take care of user references to | |
390 | `refport'. RPC_EXPR should perform the desired RPC operation using | |
391 | `msgport' and `refport'. | |
392 | ||
393 | The reason for the complexity is that a process's message port and | |
394 | reference port may change between fetching those ports and completing an | |
395 | RPC using them (usually they change only when a process execs). The RPC | |
396 | will fail with MACH_SEND_INVALID_DEST if the msgport dies before we can | |
397 | send the RPC request; or with MIG_SERVER_DIED if the msgport was | |
398 | destroyed after we sent the RPC request but before it was serviced. In | |
399 | either of these cases, we retry the entire operation, discarding the old | |
400 | message and reference ports and fetch them anew. */ | |
401 | ||
402 | #define HURD_MSGPORT_RPC(fetch_msgport_expr, \ | |
403 | fetch_refport_expr, dealloc_refport, \ | |
404 | rpc_expr) \ | |
405 | ({ \ | |
406 | error_t __err; \ | |
407 | mach_port_t msgport, refport = MACH_PORT_NULL; \ | |
408 | do \ | |
409 | { \ | |
410 | /* Get the message port. */ \ | |
2dacdc5e | 411 | __err = (error_t) (fetch_msgport_expr); \ |
1c6e82ec | 412 | if (__err) \ |
28f540f4 RM |
413 | break; \ |
414 | /* Get the reference port. */ \ | |
2dacdc5e | 415 | __err = (error_t) (fetch_refport_expr); \ |
1c6e82ec | 416 | if (__err) \ |
28f540f4 RM |
417 | { \ |
418 | /* Couldn't get it; deallocate MSGPORT and fail. */ \ | |
419 | __mach_port_deallocate (__mach_task_self (), msgport); \ | |
420 | break; \ | |
421 | } \ | |
2dacdc5e | 422 | __err = (error_t) (rpc_expr); \ |
28f540f4 RM |
423 | __mach_port_deallocate (__mach_task_self (), msgport); \ |
424 | if ((dealloc_refport) && refport != MACH_PORT_NULL) \ | |
425 | __mach_port_deallocate (__mach_task_self (), refport); \ | |
34a5a146 JM |
426 | } while (__err == MACH_SEND_INVALID_DEST \ |
427 | || __err == MIG_SERVER_DIED); \ | |
28f540f4 RM |
428 | __err; \ |
429 | }) | |
f2149f69 | 430 | |
28f540f4 RM |
431 | |
432 | #endif /* hurd/signal.h */ |