1 | /* Implementing POSIX.1 signals under the Hurd. |
2 | Copyright (C) 1993-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
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. |
9 | |
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 |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #ifndef _HURD_SIGNAL_H |
20 | |
21 | #define _HURD_SIGNAL_H 1 |
22 | #include <features.h> |
23 | |
24 | #define __need_size_t |
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> |
34 | #include <bits/types/error_t.h> |
35 | #include <bits/types/stack_t.h> |
36 | #include <bits/types/sigset_t.h> |
37 | #include <bits/sigaction.h> |
38 | #include <hurd/msg.h> |
39 | |
40 | #include <setjmp.h> /* For `jmp_buf'. */ |
41 | #include <spin-lock.h> |
42 | struct hurd_signal_preemptor; /* <hurd/sigpreempt.h> */ |
43 | #if defined __USE_EXTERN_INLINES && defined _LIBC |
44 | # if IS_IN (libc) || IS_IN (libpthread) |
45 | # include <sigsetops.h> |
46 | # endif |
47 | #endif |
48 | |
49 | |
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 | |
62 | /* Per-thread signal state. */ |
63 | |
64 | struct hurd_sigstate |
65 | { |
66 | spin_lock_t critical_section_lock; /* Held if in critical section. */ |
67 | |
68 | spin_lock_t lock; /* Locks most of the rest of the structure. */ |
69 | |
70 | /* The signal state holds a reference on the thread port. */ |
71 | thread_t thread; |
72 | |
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. */ |
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. */ |
82 | struct sigaction actions[_NSIG]; |
83 | |
84 | stack_t sigaltstack; |
85 | |
86 | /* Chain of thread-local signal preemptors; see <hurd/sigpreempt.h>. |
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. */ |
90 | struct hurd_signal_preemptor *preemptors; |
91 | |
92 | /* For each signal that may be pending, the details to deliver it with. */ |
93 | struct hurd_signal_detail pending_data[_NSIG]; |
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; |
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; |
114 | |
115 | /* These are locked normally. */ |
116 | int cancel; /* Flag set by hurd_thread_cancel. */ |
117 | void (*cancel_hook) (void); /* Called on cancellation. */ |
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 | |
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. */ |
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. */ |
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 | |
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 | |
159 | #ifndef _HURD_SIGNAL_H_EXTERN_INLINE |
160 | #define _HURD_SIGNAL_H_EXTERN_INLINE __extern_inline |
161 | #endif |
162 | |
163 | #if defined __USE_EXTERN_INLINES && defined _LIBC |
164 | # if IS_IN (libc) |
165 | _HURD_SIGNAL_H_EXTERN_INLINE struct hurd_sigstate * |
166 | _hurd_self_sigstate (void) |
167 | { |
168 | if (THREAD_GETMEM (THREAD_SELF, _hurd_sigstate) == NULL) |
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 | } |
174 | return THREAD_GETMEM (THREAD_SELF, _hurd_sigstate); |
175 | } |
176 | # endif |
177 | #endif |
178 | |
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 | |
188 | /* Resource limit on core file size. Enforced by hurdsig.c. */ |
189 | extern int _hurd_core_limit; |
190 | |
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 |
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 |
201 | avoid unexpectingly exposing EINTR to the application. */ |
202 | |
203 | extern void *_hurd_critical_section_lock (void); |
204 | |
205 | #if defined __USE_EXTERN_INLINES && defined _LIBC |
206 | # if IS_IN (libc) |
207 | _HURD_SIGNAL_H_EXTERN_INLINE void * |
208 | _hurd_critical_section_lock (void) |
209 | { |
210 | struct hurd_sigstate *ss; |
211 | |
212 | #ifdef __LIBC_NO_TLS |
213 | if (__LIBC_NO_TLS ()) |
214 | /* TLS is currently initializing, no need to enter critical section. */ |
215 | return NULL; |
216 | #endif |
217 | |
218 | ss = THREAD_GETMEM (THREAD_SELF, _hurd_sigstate); |
219 | if (ss == NULL) |
220 | { |
221 | thread_t self = __mach_thread_self (); |
222 | |
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 |
226 | way. */ |
227 | ss = _hurd_thread_sigstate (self); |
228 | THREAD_SETMEM (THREAD_SELF, _hurd_sigstate, ss); |
229 | __mach_port_deallocate (__mach_task_self (), self); |
230 | } |
231 | |
232 | if (! __spin_try_lock (&ss->critical_section_lock)) |
233 | /* We are already in a critical section, so do nothing. */ |
234 | return NULL; |
235 | |
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. */ |
239 | return ss; |
240 | } |
241 | # endif |
242 | #endif |
243 | |
244 | extern void _hurd_critical_section_unlock (void *our_lock); |
245 | |
246 | #if defined __USE_EXTERN_INLINES && defined _LIBC |
247 | # if IS_IN (libc) |
248 | _HURD_SIGNAL_H_EXTERN_INLINE void |
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 | { |
256 | /* It was us who acquired the critical section lock. Unlock it. */ |
257 | struct hurd_sigstate *ss = (struct hurd_sigstate *) our_lock; |
258 | sigset_t pending; |
259 | _hurd_sigstate_lock (ss); |
260 | __spin_unlock (&ss->critical_section_lock); |
261 | pending = _hurd_sigstate_pending(ss) & ~ss->blocked; |
262 | _hurd_sigstate_unlock (ss); |
263 | if (! __sigisemptyset (&pending)) |
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. */ |
267 | __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ()); |
268 | } |
269 | } |
270 | # endif |
271 | #endif |
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) |
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__); |
284 | |
285 | /* Initialize the signal code, and start the signal thread. |
286 | Arguments give the "init ints" from exec_startup. */ |
287 | |
288 | extern void _hurdsig_init (const int *intarray, size_t intarraysize); |
289 | |
290 | /* Initialize proc server-assisted fault recovery for the signal thread. */ |
291 | |
292 | extern void _hurdsig_fault_init (void); |
293 | |
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. */ |
297 | |
298 | extern int _hurd_raise_signal (struct hurd_sigstate *ss, int signo, |
299 | const struct hurd_signal_detail *detail); |
300 | |
301 | /* Translate a Mach exception into a signal (machine-dependent). */ |
302 | |
303 | extern void _hurd_exception2signal (struct hurd_signal_detail *detail, |
304 | int *signo); |
305 | |
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 | |
311 | |
312 | /* Make the thread described by SS take the signal described by SIGNO and |
313 | DETAIL. If the process is traced, this will in fact stop with a SIGNO |
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, |
319 | int signo, |
320 | struct hurd_signal_detail *detail, |
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 * |
334 | _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action, |
335 | __sighandler_t handler, |
336 | int signo, struct hurd_signal_detail *detail, |
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 | |
341 | extern void *_hurd_msgport_receive (void *arg); |
342 | |
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 | |
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); |
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 | |
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 | |
369 | |
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; |
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. */ \ |
411 | __err = (error_t) (fetch_msgport_expr); \ |
412 | if (__err) \ |
413 | break; \ |
414 | /* Get the reference port. */ \ |
415 | __err = (error_t) (fetch_refport_expr); \ |
416 | if (__err) \ |
417 | { \ |
418 | /* Couldn't get it; deallocate MSGPORT and fail. */ \ |
419 | __mach_port_deallocate (__mach_task_self (), msgport); \ |
420 | break; \ |
421 | } \ |
422 | __err = (error_t) (rpc_expr); \ |
423 | __mach_port_deallocate (__mach_task_self (), msgport); \ |
424 | if ((dealloc_refport) && refport != MACH_PORT_NULL) \ |
425 | __mach_port_deallocate (__mach_task_self (), refport); \ |
426 | } while (__err == MACH_SEND_INVALID_DEST \ |
427 | || __err == MIG_SERVER_DIED); \ |
428 | __err; \ |
429 | }) |
430 | |
431 | |
432 | #endif /* hurd/signal.h */ |
433 | |