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