]>
Commit | Line | Data |
---|---|---|
28f540f4 | 1 | /* Implementing POSIX.1 signals under the Hurd. |
dff8da6b | 2 | Copyright (C) 1993-2024 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> */ |
28f540f4 RM |
43 | |
44 | ||
93a470c7 RM |
45 | /* Full details of a signal. */ |
46 | struct hurd_signal_detail | |
47 | { | |
48 | /* Codes from origination Mach exception_raise message. */ | |
d8ee5d61 SB |
49 | integer_t exc, exc_code; |
50 | long_integer_t exc_subcode; | |
93a470c7 | 51 | /* Sigcode as passed or computed from exception codes. */ |
d8ee5d61 | 52 | long_integer_t code; |
93a470c7 RM |
53 | /* Error code as passed or extracted from exception codes. */ |
54 | error_t error; | |
55 | }; | |
56 | ||
57 | ||
28f540f4 RM |
58 | /* Per-thread signal state. */ |
59 | ||
60 | struct hurd_sigstate | |
61 | { | |
8f0c527e | 62 | spin_lock_t critical_section_lock; /* Held if in critical section. */ |
28f540f4 | 63 | |
8f0c527e | 64 | spin_lock_t lock; /* Locks most of the rest of the structure. */ |
28f540f4 | 65 | |
5c06743c | 66 | /* The signal state holds a reference on the thread port. */ |
28f540f4 | 67 | thread_t thread; |
5c06743c | 68 | |
28f540f4 RM |
69 | struct hurd_sigstate *next; /* Linked-list of thread sigstates. */ |
70 | ||
71 | sigset_t blocked; /* What signals are blocked. */ | |
72 | sigset_t pending; /* Pending signals, possibly blocked. */ | |
653d74f1 JK |
73 | |
74 | /* Signal handlers. ACTIONS[0] is used to mark the threads with POSIX | |
75 | semantics: if sa_handler is SIG_IGN instead of SIG_DFL, this thread | |
76 | will receive global signals and use the process-wide action vector | |
77 | instead of this one. */ | |
ba89615d | 78 | struct sigaction actions[_NSIG]; |
653d74f1 | 79 | |
75531318 | 80 | stack_t sigaltstack; |
71733723 | 81 | |
10dc2a90 | 82 | /* Chain of thread-local signal preemptors; see <hurd/sigpreempt.h>. |
71733723 RM |
83 | Each element of this chain is in local stack storage, and the chain |
84 | parallels the stack: the head of this chain is in the innermost | |
85 | stack frame, and each next element in an outermore frame. */ | |
10dc2a90 | 86 | struct hurd_signal_preemptor *preemptors; |
71733723 | 87 | |
93a470c7 | 88 | /* For each signal that may be pending, the details to deliver it with. */ |
ba89615d | 89 | struct hurd_signal_detail pending_data[_NSIG]; |
28f540f4 RM |
90 | |
91 | /* If `suspended' is set when this thread gets a signal, | |
92 | the signal thread sends an empty message to it. */ | |
93 | mach_port_t suspended; | |
94 | ||
95 | /* The following members are not locked. They are used only by this | |
96 | thread, or by the signal thread with this thread suspended. */ | |
97 | ||
98 | volatile mach_port_t intr_port; /* Port interruptible RPC was sent on. */ | |
99 | ||
100 | /* If this is not null, the thread is in sigreturn awaiting delivery of | |
101 | pending signals. This context (the machine-dependent portions only) | |
102 | will be passed to sigreturn after running the handler for a pending | |
103 | signal, instead of examining the thread state. */ | |
104 | struct sigcontext *context; | |
1474b80f RM |
105 | |
106 | /* This is the head of the thread's list of active resources; see | |
107 | <hurd/userlink.h> for details. This member is only used by the | |
108 | thread itself, and always inside a critical section. */ | |
109 | struct hurd_userlink *active_resources; | |
54da5be3 | 110 | |
207eb76a RM |
111 | /* These are locked normally. */ |
112 | int cancel; /* Flag set by hurd_thread_cancel. */ | |
113 | void (*cancel_hook) (void); /* Called on cancellation. */ | |
28f540f4 RM |
114 | }; |
115 | ||
116 | /* Linked list of states of all threads whose state has been asked for. */ | |
117 | ||
118 | extern struct hurd_sigstate *_hurd_sigstates; | |
119 | ||
5c06743c RB |
120 | /* Get the sigstate of a given thread. If there was no sigstate for |
121 | the thread, one is created, and the thread gains a reference. If | |
122 | the given thread is MACH_PORT_NULL, return the global sigstate. */ | |
28f540f4 RM |
123 | |
124 | extern struct hurd_sigstate *_hurd_thread_sigstate (thread_t); | |
125 | ||
126 | /* Get the sigstate of the current thread. | |
127 | This uses a per-thread variable to optimize the lookup. */ | |
d6e2f671 RM |
128 | |
129 | extern struct hurd_sigstate *_hurd_self_sigstate (void) | |
130 | /* This declaration tells the compiler that the value is constant. | |
131 | We assume this won't be called twice from the same stack frame | |
132 | by different threads. */ | |
133 | __attribute__ ((__const__)); | |
134 | ||
653d74f1 JK |
135 | /* Process-wide signal state. */ |
136 | ||
137 | extern struct hurd_sigstate *_hurd_global_sigstate; | |
138 | ||
139 | /* Mark the given thread as a process-wide signal receiver. */ | |
140 | ||
141 | extern void _hurd_sigstate_set_global_rcv (struct hurd_sigstate *ss); | |
142 | ||
143 | /* A thread can either use its own action vector and pending signal set | |
7f0d9e61 | 144 | or use the global ones, depending on whether it has been marked as a |
653d74f1 JK |
145 | global receiver. The accessors below take that into account. */ |
146 | ||
147 | extern void _hurd_sigstate_lock (struct hurd_sigstate *ss); | |
148 | extern struct sigaction *_hurd_sigstate_actions (struct hurd_sigstate *ss); | |
149 | extern sigset_t _hurd_sigstate_pending (const struct hurd_sigstate *ss); | |
150 | extern void _hurd_sigstate_unlock (struct hurd_sigstate *ss); | |
151 | ||
152 | /* Used by libpthread to remove stale sigstate structures. */ | |
153 | extern void _hurd_sigstate_delete (thread_t thread); | |
154 | ||
4be91365 | 155 | struct machine_thread_all_state; |
97369209 ST |
156 | extern mach_port_t |
157 | _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread, | |
158 | struct machine_thread_all_state *state, int *state_change, | |
159 | void (*reply) (void)); | |
28f540f4 RM |
160 | \f |
161 | /* Thread listening on our message port; also called the "signal thread". */ | |
162 | ||
163 | extern thread_t _hurd_msgport_thread; | |
164 | ||
165 | /* Our message port. We hold the receive right and _hurd_msgport_thread | |
166 | listens for messages on it. We also hold a send right, for convenience. */ | |
167 | ||
168 | extern mach_port_t _hurd_msgport; | |
169 | ||
28f540f4 RM |
170 | /* Resource limit on core file size. Enforced by hurdsig.c. */ |
171 | extern int _hurd_core_limit; | |
172 | \f | |
173 | /* Critical sections. | |
174 | ||
175 | A critical section is a section of code which cannot safely be interrupted | |
176 | to run a signal handler; for example, code that holds any lock cannot be | |
177 | interrupted lest the signal handler try to take the same lock and | |
e87d8ada ST |
178 | deadlock result. |
179 | ||
180 | As a consequence, a critical section will see its RPCs return EINTR, even if | |
181 | SA_RESTART is set! In that case, the critical section should be left, so | |
182 | that the handler can run, and the whole critical section be tried again, to | |
066ae81e | 183 | avoid unexpectingly exposing EINTR to the application. */ |
28f540f4 | 184 | |
28f6186f | 185 | extern void *_hurd_critical_section_lock (void); |
28f6186f ST |
186 | extern void _hurd_critical_section_unlock (void *our_lock); |
187 | ||
28f540f4 RM |
188 | /* Convenient macros for simple uses of critical sections. |
189 | These two must be used as a pair at the same C scoping level. */ | |
190 | ||
191 | #define HURD_CRITICAL_BEGIN \ | |
192 | { void *__hurd_critical__ = _hurd_critical_section_lock () | |
193 | #define HURD_CRITICAL_END \ | |
194 | _hurd_critical_section_unlock (__hurd_critical__); } while (0) | |
c3b287be ST |
195 | |
196 | /* This one can be used inside the C scoping level, for early exits. */ | |
197 | #define HURD_CRITICAL_UNLOCK \ | |
198 | _hurd_critical_section_unlock (__hurd_critical__); | |
28f540f4 | 199 | \f |
62495816 RM |
200 | /* Initialize the signal code, and start the signal thread. |
201 | Arguments give the "init ints" from exec_startup. */ | |
28f540f4 | 202 | |
62495816 | 203 | extern void _hurdsig_init (const int *intarray, size_t intarraysize); |
28f540f4 RM |
204 | |
205 | /* Initialize proc server-assisted fault recovery for the signal thread. */ | |
206 | ||
207 | extern void _hurdsig_fault_init (void); | |
208 | ||
93a470c7 RM |
209 | /* Raise a signal as described by SIGNO an DETAIL, on the thread whose |
210 | sigstate SS points to. If SS is a null pointer, this instead affects | |
211 | the calling thread. */ | |
28f540f4 | 212 | |
ee0976f7 ST |
213 | extern int _hurd_raise_signal (struct hurd_sigstate *ss, int signo, |
214 | const struct hurd_signal_detail *detail); | |
28f540f4 RM |
215 | |
216 | /* Translate a Mach exception into a signal (machine-dependent). */ | |
217 | ||
0e3426bb RM |
218 | extern void _hurd_exception2signal (struct hurd_signal_detail *detail, |
219 | int *signo); | |
28f540f4 | 220 | |
d865ff74 JK |
221 | /* Translate a Mach exception into a signal with a legacy sigcode. */ |
222 | ||
223 | extern void _hurd_exception2signal_legacy (struct hurd_signal_detail *detail, | |
224 | int *signo); | |
225 | ||
28f540f4 RM |
226 | |
227 | /* Make the thread described by SS take the signal described by SIGNO and | |
93a470c7 | 228 | DETAIL. If the process is traced, this will in fact stop with a SIGNO |
28f540f4 RM |
229 | as the stop signal unless UNTRACED is nonzero. When the signal can be |
230 | considered delivered, sends a sig_post reply message on REPLY_PORT | |
231 | indicating success. SS is not locked. */ | |
232 | ||
233 | extern void _hurd_internal_post_signal (struct hurd_sigstate *ss, | |
93a470c7 RM |
234 | int signo, |
235 | struct hurd_signal_detail *detail, | |
28f540f4 RM |
236 | mach_port_t reply_port, |
237 | mach_msg_type_name_t reply_port_type, | |
238 | int untraced); | |
239 | ||
240 | /* Set up STATE and SS to handle signal SIGNO by running HANDLER. If | |
241 | RPC_WAIT is nonzero, the thread needs to wait for a pending RPC to | |
242 | finish before running the signal handler. The handler is passed SIGNO, | |
243 | SIGCODE, and the returned `struct sigcontext' (which resides on the | |
244 | stack the handler will use, and which describes the state of the thread | |
245 | encoded in STATE before running the handler). */ | |
246 | ||
28f540f4 | 247 | extern struct sigcontext * |
e42efa01 ST |
248 | _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action, |
249 | __sighandler_t handler, | |
0e3426bb | 250 | int signo, struct hurd_signal_detail *detail, |
28f540f4 RM |
251 | int rpc_wait, struct machine_thread_all_state *state); |
252 | ||
253 | /* Function run by the signal thread to receive from the signal port. */ | |
254 | ||
9446e02b | 255 | extern void *_hurd_msgport_receive (void *arg); |
28f540f4 | 256 | |
28f540f4 RM |
257 | /* Set up STATE with a thread state that, when resumed, is |
258 | like `longjmp (_hurd_sigthread_fault_env, 1)'. */ | |
259 | ||
260 | extern void _hurd_initialize_fault_recovery_state (void *state); | |
261 | ||
54da5be3 RM |
262 | /* Set up STATE to do the equivalent of `longjmp (ENV, VAL);'. */ |
263 | ||
264 | extern void _hurd_longjmp_thread_state (void *state, jmp_buf env, int value); | |
28f540f4 RM |
265 | |
266 | /* Function run for SIGINFO when its action is SIG_DFL and the current | |
267 | process is the session leader. */ | |
268 | ||
269 | extern void _hurd_siginfo_handler (int); | |
270 | ||
3d46e1cd TBB |
271 | /* Replacement for mach_msg used in RPCs to provide Hurd interruption |
272 | semantics. Args are all the same as for mach_msg. intr-rpc.h arranges | |
273 | for this version to be used automatically by the RPC stubs the library | |
274 | builds in place of the normal mach_msg. */ | |
275 | error_t _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg, | |
276 | mach_msg_option_t option, | |
277 | mach_msg_size_t send_size, | |
278 | mach_msg_size_t rcv_size, | |
279 | mach_port_t rcv_name, | |
280 | mach_msg_timeout_t timeout, | |
281 | mach_port_t notify); | |
282 | ||
28f540f4 | 283 | |
54da5be3 RM |
284 | /* Milliseconds to wait for an interruptible RPC to return after |
285 | `interrupt_operation'. */ | |
286 | ||
287 | extern mach_msg_timeout_t _hurd_interrupted_rpc_timeout; | |
28f540f4 RM |
288 | |
289 | ||
290 | /* Mask of signals that cannot be caught, blocked, or ignored. */ | |
291 | #define _SIG_CANT_MASK (__sigmask (SIGSTOP) | __sigmask (SIGKILL)) | |
292 | ||
293 | /* Do an RPC to a process's message port. | |
294 | ||
295 | Each argument is an expression which returns an error code; each | |
296 | expression may be evaluated several times. FETCH_MSGPORT_EXPR should | |
297 | fetch the appropriate message port and store it in the local variable | |
298 | `msgport'; it will be deallocated after use. FETCH_REFPORT_EXPR should | |
299 | fetch the appropriate message port and store it in the local variable | |
300 | `refport' (if no reference port is needed in the call, then | |
301 | FETCH_REFPORT_EXPR should be simply KERN_SUCCESS or 0); if | |
302 | DEALLOC_REFPORT evaluates to nonzero it will be deallocated after use, | |
303 | otherwise the FETCH_REFPORT_EXPR must take care of user references to | |
304 | `refport'. RPC_EXPR should perform the desired RPC operation using | |
305 | `msgport' and `refport'. | |
306 | ||
307 | The reason for the complexity is that a process's message port and | |
308 | reference port may change between fetching those ports and completing an | |
309 | RPC using them (usually they change only when a process execs). The RPC | |
310 | will fail with MACH_SEND_INVALID_DEST if the msgport dies before we can | |
311 | send the RPC request; or with MIG_SERVER_DIED if the msgport was | |
312 | destroyed after we sent the RPC request but before it was serviced. In | |
313 | either of these cases, we retry the entire operation, discarding the old | |
314 | message and reference ports and fetch them anew. */ | |
315 | ||
316 | #define HURD_MSGPORT_RPC(fetch_msgport_expr, \ | |
317 | fetch_refport_expr, dealloc_refport, \ | |
318 | rpc_expr) \ | |
319 | ({ \ | |
320 | error_t __err; \ | |
321 | mach_port_t msgport, refport = MACH_PORT_NULL; \ | |
322 | do \ | |
323 | { \ | |
324 | /* Get the message port. */ \ | |
2dacdc5e | 325 | __err = (error_t) (fetch_msgport_expr); \ |
1c6e82ec | 326 | if (__err) \ |
28f540f4 RM |
327 | break; \ |
328 | /* Get the reference port. */ \ | |
2dacdc5e | 329 | __err = (error_t) (fetch_refport_expr); \ |
1c6e82ec | 330 | if (__err) \ |
28f540f4 RM |
331 | { \ |
332 | /* Couldn't get it; deallocate MSGPORT and fail. */ \ | |
333 | __mach_port_deallocate (__mach_task_self (), msgport); \ | |
334 | break; \ | |
335 | } \ | |
2dacdc5e | 336 | __err = (error_t) (rpc_expr); \ |
28f540f4 RM |
337 | __mach_port_deallocate (__mach_task_self (), msgport); \ |
338 | if ((dealloc_refport) && refport != MACH_PORT_NULL) \ | |
339 | __mach_port_deallocate (__mach_task_self (), refport); \ | |
34a5a146 JM |
340 | } while (__err == MACH_SEND_INVALID_DEST \ |
341 | || __err == MIG_SERVER_DIED); \ | |
28f540f4 RM |
342 | __err; \ |
343 | }) | |
f2149f69 | 344 | |
28f540f4 RM |
345 | |
346 | #endif /* hurd/signal.h */ |