relibc/header/signal/mod.rs
1//! `signal.h` implementation.
2//!
3//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html>.
4
5use core::{mem, ptr};
6
7use cbitset::BitSet;
8
9#[cfg(target_os = "redox")]
10use crate::platform::types::pthread_attr_t;
11use crate::{
12 error::{Errno, ResultExt},
13 header::{bits_sigset_t::sigset_t, errno, time::timespec},
14 platform::{
15 self, ERRNO, Pal, PalSignal, Sys,
16 types::{c_char, c_int, c_ulonglong, c_void, pid_t, pthread_t, size_t, uid_t},
17 },
18};
19
20pub mod constants;
21pub use self::sys::*;
22pub use constants::*;
23
24use super::{
25 errno::EFAULT,
26 stdio::{fprintf, stderr},
27};
28
29#[cfg(target_os = "linux")]
30#[path = "linux.rs"]
31pub mod sys;
32
33#[cfg(target_os = "redox")]
34#[path = "redox.rs"]
35pub mod sys;
36
37type SigSet = BitSet<[u64; 1]>;
38
39/// cbindgen:ignore
40/// Request for default signal handling.
41pub(crate) const SIG_DFL: usize = 0;
42/// cbindgen:ignore
43/// Request that signal be ignored.
44pub(crate) const SIG_IGN: usize = 1;
45/// cbindgen:ignore
46/// Return value of `signal()` in case of error.
47pub(crate) const SIG_ERR: isize = -1;
48/// cbindgen:ignore
49/// Obsolete in issue 7, removed in issue 8.
50/// Request that signal be held.
51pub(crate) const SIG_HOLD: isize = 2;
52
53/// The resulting set is the union of the current set and the signal set
54/// pointed to by the argument `set`.
55pub const SIG_BLOCK: c_int = 0;
56/// The resulting set is the intersection of the current set and the compliment
57/// of the signal set pointed to by the argument `set`.
58pub const SIG_UNBLOCK: c_int = 1;
59/// The resulting set is the signal set pointed to by the argument `set`.
60pub const SIG_SETMASK: c_int = 2;
61
62/// A queued signal, with an application-defined value, is generated when the
63/// event of interest occurs.
64pub const SIGEV_SIGNAL: c_int = 0;
65/// No asynchronous notification is delivered when the event of interest
66/// occurs.
67pub const SIGEV_NONE: c_int = 1;
68/// A notification function is called to perform notification.
69pub const SIGEV_THREAD: c_int = 2;
70
71/// cbindgen:ignore
72/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html>.
73///
74/// # Implementation
75/// This struct in Rust is missing the `sa_sigaction` field. The stucture in
76/// cbindgen uses a union to combine `sa_handler` and `sa_sigaction`. POSIX
77/// states that both fields shall not be used simultaneously.
78#[repr(C)]
79#[derive(Clone, Debug)]
80pub struct sigaction {
81 /// Pointer to a signal-catching function or one of the `SIG_IGN` or
82 /// `SIG_DFL`.
83 pub sa_handler: Option<extern "C" fn(c_int)>,
84 /// Special flags.
85 pub sa_flags: c_int,
86 /// Non-POSIX, see <https://www.man7.org/linux/man-pages/man2/sigaction.2.html>.
87 ///
88 /// Not intended for application use. A sigaction wrapper function is
89 /// intended to use this to store the location of the trampoline code and
90 /// setting the `SA_RESTORER` flag in `sa_flags`.
91 pub sa_restorer: Option<unsafe extern "C" fn()>,
92 /// Set of signals to be blocked during execution of the signal handling
93 /// function.
94 pub sa_mask: sigset_t,
95}
96
97#[repr(C)]
98#[derive(Clone)]
99pub struct sigaltstack {
100 /// Stack base or pointer.
101 pub ss_sp: *mut c_void,
102 /// Flags,
103 pub ss_flags: c_int,
104 /// Stack size.
105 pub ss_size: size_t,
106}
107
108/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html>.
109#[repr(C)]
110#[derive(Clone)]
111#[cfg(not(target_os = "linux"))]
112pub struct sigevent {
113 /// Signal value.
114 pub sigev_value: sigval,
115 /// Signal number.
116 pub sigev_signo: c_int,
117 /// Notification type.
118 pub sigev_notify: c_int,
119 /// Notification function.
120 pub sigev_notify_function: Option<extern "C" fn(sigval)>,
121 /// Notification attributes.
122 pub sigev_notify_attributes: *mut pthread_attr_t,
123}
124
125/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html>.
126///
127/// # Implementation
128/// Must match with signature from libc.
129/// See <https://docs.rs/libc/0.2.186/src/libc/unix/linux_like/mod.rs.html#300-322>.
130#[repr(C)]
131#[derive(Clone)]
132#[cfg(target_os = "linux")]
133pub struct sigevent {
134 /// Signal value.
135 pub sigev_value: sigval,
136 /// Signal number.
137 pub sigev_signo: c_int,
138 /// Notification type.
139 pub sigev_notify: c_int,
140 // Actually a union. We only expose sigev_notify_thread_id because it's
141 // the most useful member
142 pub sigev_notify_thread_id: c_int,
143 #[cfg(target_pointer_width = "64")]
144 __unused1: [c_int; 11],
145 #[cfg(target_pointer_width = "32")]
146 __unused1: [c_int; 12],
147}
148
149// FIXME: This struct is wrong on Linux
150#[repr(C)]
151#[derive(Clone, Copy)]
152pub struct siginfo {
153 /// Signal number.
154 pub si_signo: c_int,
155 /// If non-zero, an errno value associated with this signal.
156 pub si_errno: c_int,
157 /// Signal code.
158 pub si_code: c_int,
159 /// Sending process ID.
160 pub si_pid: pid_t,
161 /// Real user ID of sending process.
162 pub si_uid: uid_t,
163 /// Address that caused fault.
164 pub si_addr: *mut c_void,
165 /// Exit value or signal.
166 pub si_status: c_int,
167 /// Signal value.
168 pub si_value: sigval,
169}
170
171/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html>.
172///
173/// Signal value.
174#[derive(Clone, Copy)]
175#[repr(C)]
176pub union sigval {
177 /// Integer signal value.
178 pub sival_int: c_int,
179 /// Pointer signal value.
180 pub sival_ptr: *mut c_void,
181}
182
183/// cbindgen:ignore
184/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html>.
185pub type siginfo_t = siginfo;
186
187/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html>
188pub type stack_t = sigaltstack;
189
190//NOTE for the following two functions, to see why they're implemented slightly differently from their intended behavior, read
191// https://git.musl-libc.org/cgit/musl/commit/?id=583e55122e767b1586286a0d9c35e2a4027998ab
192#[unsafe(no_mangle)]
193unsafe extern "C" fn __sigsetjmp_tail(jb: *mut c_ulonglong, ret: c_int) -> c_int {
194 let set = jb.wrapping_add(9);
195 if ret > 0 {
196 unsafe { sigprocmask(SIG_SETMASK, set, ptr::null_mut()) };
197 } else {
198 unsafe { sigprocmask(SIG_SETMASK, ptr::null_mut(), set) };
199 }
200 ret
201}
202
203/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/kill.html>.
204///
205/// Sends a signal to a process or a group of processes specified by `pid`.
206///
207/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
208/// indicate the error. No signal is sent if failed.
209#[unsafe(no_mangle)]
210pub extern "C" fn kill(pid: pid_t, sig: c_int) -> c_int {
211 Sys::kill(pid, sig).map(|()| 0).or_minus_one_errno()
212}
213
214/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigqueue.html>.
215///
216/// Causes the signal specified by `signo` to be sent with the value specified
217/// by `value` to the process specified by `pid`.
218///
219/// Upon success, the specified signal shall have been queued, and returns `0`.
220/// Upon error, returns `-1` and sets errno to indicate the error.
221#[unsafe(no_mangle)]
222pub extern "C" fn sigqueue(pid: pid_t, signo: c_int, value: sigval) -> c_int {
223 Sys::sigqueue(pid, signo, value)
224 .map(|()| 0)
225 .or_minus_one_errno()
226}
227
228/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/killpg.html>.
229///
230/// Sends the signali specified by `sig` to the process group specified by
231/// `pgrp`.
232///
233/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
234/// indicate the error. No signal is sent if failed.
235#[unsafe(no_mangle)]
236pub extern "C" fn killpg(pgrp: pid_t, sig: c_int) -> c_int {
237 Sys::killpg(pgrp, sig).map(|()| 0).or_minus_one_errno()
238}
239
240/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_kill.html>.
241///
242/// Requests that a signal be delivered to the specified thread. It shall not
243/// be an error is `thread` is a zombie thread.
244///
245/// Upon success, returns `0`. Upon failure, returns an error number and does
246/// not send the signal.
247#[unsafe(no_mangle)]
248pub unsafe extern "C" fn pthread_kill(thread: pthread_t, sig: c_int) -> c_int {
249 let os_tid = {
250 let pthread = unsafe { &*(thread as *const crate::pthread::Pthread) };
251 unsafe { pthread.os_tid.get().read() }
252 };
253 crate::header::pthread::e(unsafe { Sys::rlct_kill(os_tid, sig as usize) })
254}
255
256/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_sigmask.html>.
257///
258/// Examines or changes (or both) the calling thread's signal mask.
259///
260/// Upon success, returns `0`. Upon failure, returns an error number.
261#[unsafe(no_mangle)]
262pub unsafe extern "C" fn pthread_sigmask(
263 how: c_int,
264 set: *const sigset_t,
265 oldset: *mut sigset_t,
266) -> c_int {
267 // On Linux and Redox, pthread_sigmask and sigprocmask are equivalent
268 if unsafe { sigprocmask(how, set, oldset) } == 0 {
269 0
270 } else {
271 //TODO: Fix race
272 platform::ERRNO.get()
273 }
274}
275
276/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/raise.html>.
277///
278/// Sends the signal `sig` to the executing thread or process. If a signal
279/// handler is called, this function shall not return until after the signal
280/// handler does.
281///
282/// Upon success, returns `0`. Upon failure, returns a non-zero value and sets
283/// errno to indicate the error.
284#[unsafe(no_mangle)]
285pub extern "C" fn raise(sig: c_int) -> c_int {
286 Sys::raise(sig).map(|()| 0).or_minus_one_errno()
287}
288
289/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigaction.html>.
290///
291/// Allows the calling process to examine and/or specify the action to be
292/// associated with a specific signal.
293///
294/// Upon success, returns `0`. Upon failure, returns `-1`, sets errno to
295/// indicate the error, and no new signal-catching function shall be installed.
296#[unsafe(no_mangle)]
297pub unsafe extern "C" fn sigaction(
298 sig: c_int,
299 act: *const sigaction,
300 oact: *mut sigaction,
301) -> c_int {
302 Sys::sigaction(sig, unsafe { act.as_ref() }, unsafe { oact.as_mut() })
303 .map(|()| 0)
304 .or_minus_one_errno()
305}
306
307/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigaddset.html>.
308///
309/// Adds the individual signal specified by `signo` to the signal set pointed
310/// to by `set`.
311///
312/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
313/// indicate the error.
314///
315/// # Safety
316/// The `sigset_t` pointed to by `set` must be initialized by `sigemptyset()`
317/// or `sigfillset()` before calling this function or undefined behaviour will
318/// occur.
319#[unsafe(no_mangle)]
320pub unsafe extern "C" fn sigaddset(set: *mut sigset_t, signo: c_int) -> c_int {
321 if signo <= 0 || signo as usize > NSIG.max(SIGRTMAX)
322 /* TODO */
323 {
324 platform::ERRNO.set(errno::EINVAL);
325 return -1;
326 }
327
328 if let Some(set) = unsafe { (set.cast::<SigSet>()).as_mut() } {
329 set.insert(signo as usize - 1); // 0-indexed usize, please!
330 }
331 0
332}
333
334/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigaltstack.html>.
335///
336/// Allows a process to define and examine the state of an alternate stack for
337/// signal handlers for the current thread.
338///
339/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
340/// indicate the error.
341///
342/// # Safety
343/// Use of this function by library threads that are not bound to
344/// kernel-scheduled entities results in undefined behaviour.
345#[unsafe(no_mangle)]
346pub unsafe extern "C" fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int {
347 unsafe {
348 Sys::sigaltstack(ss.as_ref(), old_ss.as_mut())
349 .map(|()| 0)
350 .or_minus_one_errno()
351 }
352}
353
354/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigdelset.html>.
355///
356/// Deletes the individual signal specified by `signo` to the signal set
357/// pointed to by `set`.
358///
359/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
360/// indicate the error.
361///
362/// # Safety
363/// The `sigset_t` pointed to by `set` must be initialized by `sigemptyset()`
364/// or `sigfillset()` before calling this function or undefined behaviour will
365/// occur.
366#[unsafe(no_mangle)]
367pub unsafe extern "C" fn sigdelset(set: *mut sigset_t, signo: c_int) -> c_int {
368 if signo <= 0 || signo as usize > NSIG.max(SIGRTMAX)
369 /* TODO */
370 {
371 platform::ERRNO.set(errno::EINVAL);
372 return -1;
373 }
374
375 if let Some(set) = unsafe { (set.cast::<SigSet>()).as_mut() } {
376 set.remove(signo as usize - 1); // 0-indexed usize, please!
377 }
378 0
379}
380
381/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigemptyset.html>.
382///
383/// Initializes the signal set pointed to by `set`, such that all signals
384/// defined in POSIX.1-2024 are excluded.
385///
386/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
387/// indicate the error.
388#[unsafe(no_mangle)]
389pub unsafe extern "C" fn sigemptyset(set: *mut sigset_t) -> c_int {
390 if let Some(set) = unsafe { (set.cast::<SigSet>()).as_mut() } {
391 set.clear();
392 }
393 0
394}
395
396/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigfillset.html>.
397///
398/// Initializes the signal set pointed to by `set`, such that all signals
399/// defined in POSIX.1-2024 are included.
400///
401/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
402/// indicate the error.
403#[unsafe(no_mangle)]
404pub unsafe extern "C" fn sigfillset(set: *mut sigset_t) -> c_int {
405 if let Some(set) = unsafe { (set.cast::<SigSet>()).as_mut() } {
406 set.fill(.., true);
407 }
408 0
409}
410
411/// See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html>.
412///
413/// Adds `sig` to the signal mask of the calling process.
414///
415/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
416/// indicate the error.
417///
418/// # Deprecated
419/// Present in issue 7. Removed in issue 8.
420///
421/// Use of this function is unspecified in a multi-threaded process.
422///
423/// `pthread_sigmask()` or `sigprocmask()` should be used instead.
424///
425/// # Implementation
426/// Calls `sigprocmask()` internally.
427#[deprecated]
428#[unsafe(no_mangle)]
429pub unsafe extern "C" fn sighold(sig: c_int) -> c_int {
430 let mut pset = mem::MaybeUninit::<sigset_t>::uninit();
431 unsafe { sigemptyset(pset.as_mut_ptr()) };
432 let mut set = unsafe { pset.assume_init() };
433 if unsafe { sigaddset(&raw mut set, sig) } < 0 {
434 return -1;
435 }
436 unsafe { sigprocmask(SIG_BLOCK, &raw const set, ptr::null_mut()) }
437}
438
439/// See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html>.
440///
441/// Sets the disposition of `sig` to `SIG_IGN`.
442///
443/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
444/// indicate the error.
445///
446/// # Deprecated
447/// Present in issue 7. Removed in issue 8.
448///
449/// Use of this function is unspecified in a multi-threaded process.
450///
451/// `sigaction()` should be used instead.
452///
453/// # Implementation
454/// Calls `sigaction()` internally.
455#[deprecated]
456#[expect(clippy::missing_transmute_annotations, reason = "too verbose")]
457#[unsafe(no_mangle)]
458pub extern "C" fn sigignore(sig: c_int) -> c_int {
459 let mut psa = mem::MaybeUninit::<sigaction>::uninit();
460 unsafe { sigemptyset(&raw mut (*psa.as_mut_ptr()).sa_mask) };
461 let mut sa = unsafe { psa.assume_init() };
462 sa.sa_handler = unsafe { mem::transmute(SIG_IGN) };
463 sa.sa_flags = 0;
464 unsafe { sigaction(sig, &raw const sa, ptr::null_mut()) }
465}
466
467/// See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/siginterrupt.html>.
468///
469/// Changes the restart behaviour when a function is interrupted by the
470/// specified signal.
471///
472/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
473/// indicate the error.
474///
475/// # Deprecated
476/// Marked obsolescent in issue 7. Removed in issue 8.
477///
478/// Should use `sigaction()` with the `SA_RESTART` flag instead.
479///
480/// # Implementation
481/// Internally uses `sigaction()` with the `SA_RESTART` flag.
482#[deprecated]
483#[unsafe(no_mangle)]
484pub extern "C" fn siginterrupt(sig: c_int, flag: c_int) -> c_int {
485 let mut psa = mem::MaybeUninit::<sigaction>::uninit();
486 unsafe { sigaction(sig, ptr::null_mut(), psa.as_mut_ptr()) };
487 let mut sa = unsafe { psa.assume_init() };
488 if flag != 0 {
489 sa.sa_flags &= !SA_RESTART as c_int;
490 } else {
491 sa.sa_flags |= SA_RESTART as c_int;
492 }
493
494 unsafe { sigaction(sig, &raw const sa, ptr::null_mut()) }
495}
496
497/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigismember.html>.
498///
499/// Tests whether the signal specified by `signo` is a member of the set
500/// pointed to by `set`.
501///
502/// Upon success, return `1` if the specified signal is a member of the
503/// specified set, or `0` if it is not. Upon failure, returns `-1` and sets
504/// errno to indicate the error.
505///
506/// # Safety
507/// The `sigset_t` pointed to by `set` must be initialized by `sigemptyset()`
508/// or `sigfillset()` before calling this function or undefined behaviour will
509/// occur.
510#[unsafe(no_mangle)]
511pub unsafe extern "C" fn sigismember(set: *const sigset_t, signo: c_int) -> c_int {
512 if signo <= 0 || signo as usize > NSIG.max(SIGRTMAX)
513 /* TODO */
514 {
515 platform::ERRNO.set(errno::EINVAL);
516 return -1;
517 }
518
519 if let Some(set) = unsafe { (set as *mut SigSet).as_mut() }
520 && set.contains(signo as usize - 1)
521 {
522 return 1;
523 }
524 0
525}
526
527/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/signal.html>.
528///
529/// Chooses one of three ways in which receipt of the signal number `sig` is to
530/// be subsequently handled.
531///
532/// Upon success, returns the value of `func` for the most recent call to
533/// `signal()` for the specified signal `sig`.Upon failure, returns `SIG_ERR`
534/// and a positive value shall be stored in errno.
535#[expect(clippy::missing_transmute_annotations, reason = "too verbose")]
536#[unsafe(no_mangle)]
537pub extern "C" fn signal(
538 sig: c_int,
539 func: Option<extern "C" fn(c_int)>,
540) -> Option<extern "C" fn(c_int)> {
541 let sa = sigaction {
542 sa_handler: func,
543 sa_flags: SA_RESTART as _,
544 sa_restorer: None, // set by platform if applicable
545 sa_mask: sigset_t::default(),
546 };
547 let mut old_sa = mem::MaybeUninit::uninit();
548 if unsafe { sigaction(sig, &raw const sa, old_sa.as_mut_ptr()) } < 0 {
549 return unsafe { mem::transmute(SIG_ERR) };
550 }
551 unsafe { old_sa.assume_init() }.sa_handler
552}
553
554/// See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html>.
555///
556/// Removes `sig` from the signal mask of the calling process and suspend the
557/// calling process until a signal is received.
558///
559/// Suspends execution of the thread until a signal is received, whereupon it
560/// shall return `-1` and set errno to `EINTR`.
561///
562/// # Deprecated
563/// Present in issue 7. Removed in issue 8.
564///
565/// Use of this function is unspecified in a multi-threaded process.
566///
567/// `sigsuspend()` should be used instead.
568///
569/// # Implementation
570/// Calls `sigsuspend()` internally.
571#[deprecated]
572#[unsafe(no_mangle)]
573pub unsafe extern "C" fn sigpause(sig: c_int) -> c_int {
574 let mut pset = mem::MaybeUninit::<sigset_t>::uninit();
575 unsafe { sigprocmask(0, ptr::null_mut(), pset.as_mut_ptr()) };
576 let mut set = unsafe { pset.assume_init() };
577 if unsafe { sigdelset(&raw mut set, sig) } == -1 {
578 return -1;
579 }
580 unsafe { sigsuspend(&raw const set) }
581}
582
583/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigpending.html>.
584///
585/// Stores, in the location referenced by the `set` argument, the set of
586/// signals that are blocked from delivery to the calling thread and that are
587/// pending on the process or the calling thread.
588///
589/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
590/// indicate the error.
591#[unsafe(no_mangle)]
592pub unsafe extern "C" fn sigpending(set: *mut sigset_t) -> c_int {
593 (|| Sys::sigpending(unsafe { set.as_mut().ok_or(Errno(EFAULT)) }?))()
594 .map(|()| 0)
595 .or_minus_one_errno()
596}
597
598// TODO: Double-check this mask.
599// This prevents the application from blocking the two signals SIGRTMIN - 1 and SIGRTMIN - 2 which
600// are (at least meant to be) used internally for timers and pthread cancellation. On Linux this is
601// 32 and 33 (same as NPTL reserves), whereas this on Redox is 33 and 34 (TODO: could this be
602// changed to 32 and 33 for Redox too, since there's currently no support for "sigqueue" targeting
603// specific threads).
604const RLCT_SIGNAL_MASK: sigset_t = (1 << ((SIGRTMIN - 1) - 1)) | (1 << ((SIGRTMIN - 2) - 1));
605
606/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigprocmask.html>.
607///
608/// Examines or changes (or both) the calling thread's signal mask.
609///
610/// Upon success, returns `0`. Upon failure, returns `-1`, sets errno to
611/// indicate the error, and does not change the signal mask.
612///
613/// Use of this function is unspecified in a multi-threaded process.
614#[unsafe(no_mangle)]
615pub unsafe extern "C" fn sigprocmask(
616 how: c_int,
617 set: *const sigset_t,
618 oset: *mut sigset_t,
619) -> c_int {
620 (|| {
621 let set = unsafe { set.as_ref().map(|&block| block & !RLCT_SIGNAL_MASK) };
622 let mut oset = unsafe { oset.as_mut() };
623
624 Sys::sigprocmask(
625 how,
626 set.as_ref(),
627 oset.as_deref_mut(), // as_deref_mut for lifetime reasons
628 )?;
629
630 if let Some(oset) = oset {
631 *oset &= !RLCT_SIGNAL_MASK;
632 }
633
634 Ok(0)
635 })()
636 .or_minus_one_errno()
637}
638
639/// See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html>.
640///
641/// Removes `sig` from the signal mask of the calling process.
642///
643/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
644/// indicate the error.
645///
646/// # Deprecated
647/// Present in issue 7. Removed in issue 8.
648///
649/// Use of this function is unspecified in a multi-threaded process.
650///
651/// `pthread_sigmask()` or `sigprocmask()` should be used instead.
652///
653/// # Implementation
654/// Calls `sigprocmask()` internally.
655#[deprecated]
656#[unsafe(no_mangle)]
657pub unsafe extern "C" fn sigrelse(sig: c_int) -> c_int {
658 let mut pset = mem::MaybeUninit::<sigset_t>::uninit();
659 unsafe { sigemptyset(pset.as_mut_ptr()) };
660 let mut set = unsafe { pset.assume_init() };
661 if unsafe { sigaddset(&raw mut set, sig) } < 0 {
662 return -1;
663 }
664 unsafe { sigprocmask(SIG_UNBLOCK, &raw const set, ptr::null_mut()) }
665}
666
667/// See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html>.
668///
669/// Modifies signal dispositions.
670///
671/// Upon success, returns `SIG_HOLD` if the signal had been blocked and the
672/// signal's previous disposition if it had not been blocked. Upon failure,
673/// returns `SIG_ERR` and sets errno to indicate the error.
674///
675/// # Deprecated
676/// Present in issue 7. Removed in issue 8.
677///
678/// Use of this function is unspecified in a multi-threaded process.
679///
680/// `sigaction()` should be used instead.
681///
682/// # Implementation
683/// Calls `sigaction()` internally.
684#[deprecated]
685#[unsafe(no_mangle)]
686pub unsafe extern "C" fn sigset(
687 sig: c_int,
688 func: Option<extern "C" fn(c_int)>,
689) -> Option<extern "C" fn(c_int)> {
690 let mut old_sa = mem::MaybeUninit::uninit();
691 let mut pset = mem::MaybeUninit::<sigset_t>::uninit();
692 let sig_hold: Option<extern "C" fn(c_int)> = unsafe { mem::transmute(SIG_HOLD) };
693 let sig_err: Option<extern "C" fn(c_int)> = unsafe { mem::transmute(SIG_ERR) };
694 unsafe { sigemptyset(pset.as_mut_ptr()) };
695 let mut set = unsafe { pset.assume_init() };
696 if unsafe { sigaddset(&raw mut set, sig) } < 0 {
697 return sig_err;
698 } else {
699 let is_equal = {
700 match (func, sig_hold) {
701 (None, None) => true,
702 (Some(_), None) | (None, Some(_)) => false,
703 (Some(f), Some(sh)) => ptr::fn_addr_eq(f, sh),
704 }
705 };
706 if is_equal {
707 if unsafe { sigaction(sig, ptr::null_mut(), old_sa.as_mut_ptr()) } < 0
708 || unsafe { sigprocmask(SIG_BLOCK, &raw const set, &raw mut set) } < 0
709 {
710 return sig_err;
711 }
712 } else {
713 let mut sa = sigaction {
714 sa_handler: func,
715 sa_flags: c_int::from(0),
716 sa_restorer: None, // set by platform if applicable
717 sa_mask: sigset_t::default(),
718 };
719 unsafe { sigemptyset(&raw mut sa.sa_mask) };
720 if unsafe { sigaction(sig, &raw const sa, old_sa.as_mut_ptr()) } < 0
721 || unsafe { sigprocmask(SIG_UNBLOCK, &raw const set, &raw mut set) } < 0
722 {
723 return sig_err;
724 }
725 }
726 }
727 if unsafe { sigismember(&raw const set, sig) } == 1 {
728 return sig_hold;
729 }
730 unsafe { old_sa.assume_init().sa_handler }
731}
732
733/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigsuspend.html>.
734///
735/// Atomically both replace the current signal mask of the calling thread with
736/// the set of signals pointed to by `sigmask` and suspend the thread until
737/// delivery of a signal whose action is either to execute a signal-catching
738/// function or to terminate the process.
739///
740/// Upon success, suspends thread execution and does not return. If the action
741/// is to execute a signal-catching function, returns `-1` after the
742/// signal-catching function returns, and restores the signal mask back to the
743/// set that existed prior to calling this function, then sets errno to
744/// indicate the error. Upon failure, returns `-1` and sets errno to indicate
745/// the error.
746#[unsafe(no_mangle)]
747pub unsafe extern "C" fn sigsuspend(sigmask: *const sigset_t) -> c_int {
748 Err(Sys::sigsuspend(unsafe { &*sigmask })).or_minus_one_errno()
749}
750
751/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigwait.html>.
752///
753/// Selects a pending signal from `set`, atomically clears it from the system's
754/// set of pending signals, and return that signal number in the location
755/// referenced by `sig`.
756///
757/// Upon success, stores the signal number of the received signal at the
758/// location referenced by `sig` and returns `0`. Upon failure, an error number
759/// is returned to indicate the error.
760#[unsafe(no_mangle)]
761pub unsafe extern "C" fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int {
762 let mut pinfo = mem::MaybeUninit::<siginfo_t>::uninit();
763 if unsafe { sigtimedwait(set, pinfo.as_mut_ptr(), ptr::null_mut()) } < 0 {
764 return -1;
765 }
766 let info = unsafe { pinfo.assume_init() };
767 unsafe { (*sig) = info.si_signo };
768 0
769}
770
771/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigtimedwait.html>.
772///
773/// Equivalent to `sigwaitinfo()` except that if none of the signals specified
774/// by `set` are pending, wait for the time interval specified in the
775/// `timespec` structure referenced by `timeout`. Shall return immediately with
776/// an error if `timeout` is zero-valued and none of the signals specified by
777/// `set` are pending.
778///
779/// Upon success, returns the selected signal number. Upon failure, returns
780/// `-1` and sets errno to indicate the error.
781///
782/// # Safety
783/// If `timeout` is the null pointer, behaviour is unspecified.
784#[unsafe(no_mangle)]
785pub unsafe extern "C" fn sigtimedwait(
786 set: *const sigset_t,
787 // s/siginfo_t/siginfo due to https://github.com/mozilla/cbindgen/issues/621
788 sig: *mut siginfo,
789 // POSIX leaves behavior unspecified if this is NULL, but on both Linux and Redox, NULL is used
790 // to differentiate between sigtimedwait and sigwaitinfo internally
791 tp: *const timespec,
792) -> c_int {
793 Sys::sigtimedwait(unsafe { &*set }, unsafe { sig.as_mut() }, unsafe {
794 tp.as_ref()
795 })
796 .or_minus_one_errno()
797}
798
799/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigwaitinfo.html>.
800///
801/// Selects the pending signal from the set specified by `set`.
802///
803/// Upon success, returns the selected signal number. Upon failure, returns
804/// `-1` and sets errno to indicate the error.
805#[unsafe(no_mangle)]
806pub unsafe extern "C" fn sigwaitinfo(set: *const sigset_t, sig: *mut siginfo_t) -> c_int {
807 unsafe { sigtimedwait(set, sig, core::ptr::null()) }
808}
809
810pub(crate) const SIGNAL_STRINGS: [&str; 32] = [
811 "Unknown signal\0",
812 "Hangup\0",
813 "Interrupt\0",
814 "Quit\0",
815 "Illegal instruction\0",
816 "Trace/breakpoint trap\0",
817 "Aborted\0",
818 "Bus error\0",
819 "Arithmetic exception\0",
820 "Killed\0",
821 "User defined signal 1\0",
822 "Segmentation fault\0",
823 "User defined signal 2\0",
824 "Broken pipe\0",
825 "Alarm clock\0",
826 "Terminated\0",
827 "Stack fault\0",
828 "Child process status\0",
829 "Continued\0",
830 "Stopped (signal)\0",
831 "Stopped\0",
832 "Stopped (tty input)\0",
833 "Stopped (tty output)\0",
834 "Urgent I/O condition\0",
835 "CPU time limit exceeded\0",
836 "File size limit exceeded\0",
837 "Virtual timer expired\0",
838 "Profiling timer expired\0",
839 "Window changed\0",
840 "I/O possible\0",
841 "Power failure\0",
842 "Bad system call\0",
843];
844
845/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/psignal.html>.
846///
847/// Writes a language-dependent message associated with a signal number to the
848/// standard error stream.
849#[unsafe(no_mangle)]
850pub unsafe extern "C" fn psignal(sig: c_int, prefix: *const c_char) {
851 let c_description = usize::try_from(sig)
852 .ok()
853 .and_then(|idx| SIGNAL_STRINGS.get(idx))
854 .unwrap_or(&SIGNAL_STRINGS[0])
855 .as_ptr();
856 // fprintf can affect errno, so we save errno and restore it
857 let old_errno = ERRNO.get();
858 // POSIX says that "prefix" shall be written if it isn't null or an empty string.
859 // Otherwise, only the signal description should be written
860 if prefix.is_null() {
861 unsafe {
862 fprintf(stderr, c"%s\n".as_ptr(), c_description);
863 }
864 } else {
865 unsafe {
866 fprintf(stderr, c"%s: %s\n".as_ptr(), prefix, c_description);
867 }
868 }
869 ERRNO.set(old_errno);
870}
871
872/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/psiginfo.html>.
873///
874/// Writes a language-dependent message associated with a signal number to the
875/// standard error stream.
876///
877/// # Implementation
878/// Calls `psignal()` internally.
879#[unsafe(no_mangle)]
880pub unsafe extern "C" fn psiginfo(info: *const siginfo_t, prefix: *const c_char) {
881 unsafe {
882 psignal((*info).si_signo, prefix);
883 }
884}