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