Skip to main content

yash_env/system/
signal.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2025 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! Signal-related functionality for the system module
18
19#[cfg(doc)]
20use super::{Concurrent, SharedSystem};
21use super::{Pid, Result};
22pub use crate::signal::{Name, Number, RawNumber};
23use std::borrow::Cow;
24use std::num::NonZero;
25use std::ops::RangeInclusive;
26use std::rc::Rc;
27
28/// Trait for managing available signals
29pub trait Signals {
30    /// The signal number for `SIGABRT`
31    const SIGABRT: Number;
32    /// The signal number for `SIGALRM`
33    const SIGALRM: Number;
34    /// The signal number for `SIGBUS`
35    const SIGBUS: Number;
36    /// The signal number for `SIGCHLD`
37    const SIGCHLD: Number;
38    /// The signal number for `SIGCLD`, if available on the system
39    const SIGCLD: Option<Number>;
40    /// The signal number for `SIGCONT`
41    const SIGCONT: Number;
42    /// The signal number for `SIGEMT`, if available on the system
43    const SIGEMT: Option<Number>;
44    /// The signal number for `SIGFPE`
45    const SIGFPE: Number;
46    /// The signal number for `SIGHUP`
47    const SIGHUP: Number;
48    /// The signal number for `SIGILL`
49    const SIGILL: Number;
50    /// The signal number for `SIGINFO`, if available on the system
51    const SIGINFO: Option<Number>;
52    /// The signal number for `SIGINT`
53    const SIGINT: Number;
54    /// The signal number for `SIGIO`, if available on the system
55    const SIGIO: Option<Number>;
56    /// The signal number for `SIGIOT`
57    const SIGIOT: Number;
58    /// The signal number for `SIGKILL`
59    const SIGKILL: Number;
60    /// The signal number for `SIGLOST`, if available on the system
61    const SIGLOST: Option<Number>;
62    /// The signal number for `SIGPIPE`
63    const SIGPIPE: Number;
64    /// The signal number for `SIGPOLL`, if available on the system
65    const SIGPOLL: Option<Number>;
66    /// The signal number for `SIGPROF`
67    const SIGPROF: Number;
68    /// The signal number for `SIGPWR`, if available on the system
69    const SIGPWR: Option<Number>;
70    /// The signal number for `SIGQUIT`
71    const SIGQUIT: Number;
72    /// The signal number for `SIGSEGV`
73    const SIGSEGV: Number;
74    /// The signal number for `SIGSTKFLT`, if available on the system
75    const SIGSTKFLT: Option<Number>;
76    /// The signal number for `SIGSTOP`
77    const SIGSTOP: Number;
78    /// The signal number for `SIGSYS`
79    const SIGSYS: Number;
80    /// The signal number for `SIGTERM`
81    const SIGTERM: Number;
82    /// The signal number for `SIGTHR`, if available on the system
83    const SIGTHR: Option<Number>;
84    /// The signal number for `SIGTRAP`
85    const SIGTRAP: Number;
86    /// The signal number for `SIGTSTP`
87    const SIGTSTP: Number;
88    /// The signal number for `SIGTTIN`
89    const SIGTTIN: Number;
90    /// The signal number for `SIGTTOU`
91    const SIGTTOU: Number;
92    /// The signal number for `SIGURG`
93    const SIGURG: Number;
94    /// The signal number for `SIGUSR1`
95    const SIGUSR1: Number;
96    /// The signal number for `SIGUSR2`
97    const SIGUSR2: Number;
98    /// The signal number for `SIGVTALRM`
99    const SIGVTALRM: Number;
100    /// The signal number for `SIGWINCH`
101    const SIGWINCH: Number;
102    /// The signal number for `SIGXCPU`
103    const SIGXCPU: Number;
104    /// The signal number for `SIGXFSZ`
105    const SIGXFSZ: Number;
106
107    /// Returns the range of real-time signals supported by the system.
108    ///
109    /// If the system does not support real-time signals, returns `None`.
110    ///
111    /// The range is provided as a method rather than associated constants
112    /// because some systems determine the range at runtime.
113    #[must_use]
114    fn sigrt_range(&self) -> Option<RangeInclusive<Number>>;
115
116    /// List of all signal names and their numbers, excluding real-time signals
117    ///
118    /// This list contains all named signals declared in this trait, except for
119    /// real-time signals. Each entry is a tuple of the signal name (without the
120    /// `SIG` prefix) and its corresponding signal number. If a signal is not
121    /// available on the system, its number is `None`.
122    ///
123    /// The signals are listed in alphabetical order by name (without the `SIG`
124    /// prefix). Implementations that override this constant must preserve this
125    /// ordering because the default implementation of
126    /// [`str2sig`](Self::str2sig) relies on it to perform a binary search.
127    const NAMED_SIGNALS: &'static [(&'static str, Option<Number>)] = &[
128        ("ABRT", Some(Self::SIGABRT)),
129        ("ALRM", Some(Self::SIGALRM)),
130        ("BUS", Some(Self::SIGBUS)),
131        ("CHLD", Some(Self::SIGCHLD)),
132        ("CLD", Self::SIGCLD),
133        ("CONT", Some(Self::SIGCONT)),
134        ("EMT", Self::SIGEMT),
135        ("FPE", Some(Self::SIGFPE)),
136        ("HUP", Some(Self::SIGHUP)),
137        ("ILL", Some(Self::SIGILL)),
138        ("INFO", Self::SIGINFO),
139        ("INT", Some(Self::SIGINT)),
140        ("IO", Self::SIGIO),
141        ("IOT", Some(Self::SIGIOT)),
142        ("KILL", Some(Self::SIGKILL)),
143        ("LOST", Self::SIGLOST),
144        ("PIPE", Some(Self::SIGPIPE)),
145        ("POLL", Self::SIGPOLL),
146        ("PROF", Some(Self::SIGPROF)),
147        ("PWR", Self::SIGPWR),
148        ("QUIT", Some(Self::SIGQUIT)),
149        ("SEGV", Some(Self::SIGSEGV)),
150        ("STKFLT", Self::SIGSTKFLT),
151        ("STOP", Some(Self::SIGSTOP)),
152        ("SYS", Some(Self::SIGSYS)),
153        ("TERM", Some(Self::SIGTERM)),
154        ("THR", Self::SIGTHR),
155        ("TRAP", Some(Self::SIGTRAP)),
156        ("TSTP", Some(Self::SIGTSTP)),
157        ("TTIN", Some(Self::SIGTTIN)),
158        ("TTOU", Some(Self::SIGTTOU)),
159        ("URG", Some(Self::SIGURG)),
160        ("USR1", Some(Self::SIGUSR1)),
161        ("USR2", Some(Self::SIGUSR2)),
162        ("VTALRM", Some(Self::SIGVTALRM)),
163        ("WINCH", Some(Self::SIGWINCH)),
164        ("XCPU", Some(Self::SIGXCPU)),
165        ("XFSZ", Some(Self::SIGXFSZ)),
166    ];
167
168    /// Returns an iterator over all real-time signals supported by the system.
169    ///
170    /// The iterator yields signal numbers in ascending order. If the system
171    /// does not support real-time signals, the iterator yields no items.
172    fn iter_sigrt(&self) -> impl DoubleEndedIterator<Item = Number> + use<Self> {
173        let range = match self.sigrt_range() {
174            Some(range) => range.start().as_raw()..=range.end().as_raw(),
175            #[allow(clippy::reversed_empty_ranges)]
176            None => 0..=-1,
177        };
178        // If NonZero implemented Step, we could use range.map(...)
179        range.filter_map(|raw| NonZero::new(raw).map(Number::from_raw_unchecked))
180    }
181
182    /// Tests if a signal number is valid and returns its signal number.
183    ///
184    /// This function returns `Some(number)` if the signal number refers to a valid
185    /// signal supported by the system. Otherwise, it returns `None`.
186    #[must_use]
187    fn to_signal_number<N: Into<RawNumber>>(&self, number: N) -> Option<Number> {
188        fn inner<S: Signals + ?Sized>(system: &S, raw_number: RawNumber) -> Option<Number> {
189            let non_zero = NonZero::new(raw_number)?;
190            let number = Number::from_raw_unchecked(non_zero);
191            (S::NAMED_SIGNALS
192                .iter()
193                .any(|signal| signal.1 == Some(number))
194                || system
195                    .sigrt_range()
196                    .is_some_and(|range| range.contains(&number)))
197            .then_some(number)
198        }
199        inner(self, number.into())
200    }
201
202    /// Converts a signal number to its string representation.
203    ///
204    /// This function returns `Some(name)` if the signal number refers to a valid
205    /// signal supported by the system. Otherwise, it returns `None`.
206    ///
207    /// The returned name does not include the `SIG` prefix.
208    /// Note that one signal number can have multiple names, in which case it is
209    /// unspecified which name is returned.
210    #[must_use]
211    fn sig2str<N: Into<RawNumber>>(&self, signal: N) -> Option<Cow<'static, str>> {
212        fn inner<S: Signals + ?Sized>(
213            system: &S,
214            raw_number: RawNumber,
215        ) -> Option<Cow<'static, str>> {
216            let number = Number::from_raw_unchecked(NonZero::new(raw_number)?);
217            // The signals below are ordered roughly by frequency of use
218            // so that common names are preferred for signals with multiple names.
219            match () {
220                () if number == S::SIGABRT => Some(Cow::Borrowed("ABRT")),
221                () if number == S::SIGALRM => Some(Cow::Borrowed("ALRM")),
222                () if number == S::SIGBUS => Some(Cow::Borrowed("BUS")),
223                () if number == S::SIGCHLD => Some(Cow::Borrowed("CHLD")),
224                () if number == S::SIGCONT => Some(Cow::Borrowed("CONT")),
225                () if number == S::SIGFPE => Some(Cow::Borrowed("FPE")),
226                () if number == S::SIGHUP => Some(Cow::Borrowed("HUP")),
227                () if number == S::SIGILL => Some(Cow::Borrowed("ILL")),
228                () if number == S::SIGINT => Some(Cow::Borrowed("INT")),
229                () if number == S::SIGKILL => Some(Cow::Borrowed("KILL")),
230                () if number == S::SIGPIPE => Some(Cow::Borrowed("PIPE")),
231                () if number == S::SIGQUIT => Some(Cow::Borrowed("QUIT")),
232                () if number == S::SIGSEGV => Some(Cow::Borrowed("SEGV")),
233                () if number == S::SIGSTOP => Some(Cow::Borrowed("STOP")),
234                () if number == S::SIGTERM => Some(Cow::Borrowed("TERM")),
235                () if number == S::SIGTSTP => Some(Cow::Borrowed("TSTP")),
236                () if number == S::SIGTTIN => Some(Cow::Borrowed("TTIN")),
237                () if number == S::SIGTTOU => Some(Cow::Borrowed("TTOU")),
238                () if number == S::SIGUSR1 => Some(Cow::Borrowed("USR1")),
239                () if number == S::SIGUSR2 => Some(Cow::Borrowed("USR2")),
240                () if Some(number) == S::SIGPOLL => Some(Cow::Borrowed("POLL")),
241                () if number == S::SIGPROF => Some(Cow::Borrowed("PROF")),
242                () if number == S::SIGSYS => Some(Cow::Borrowed("SYS")),
243                () if number == S::SIGTRAP => Some(Cow::Borrowed("TRAP")),
244                () if number == S::SIGURG => Some(Cow::Borrowed("URG")),
245                () if number == S::SIGVTALRM => Some(Cow::Borrowed("VTALRM")),
246                () if number == S::SIGWINCH => Some(Cow::Borrowed("WINCH")),
247                () if number == S::SIGXCPU => Some(Cow::Borrowed("XCPU")),
248                () if number == S::SIGXFSZ => Some(Cow::Borrowed("XFSZ")),
249                () if Some(number) == S::SIGEMT => Some(Cow::Borrowed("EMT")),
250                () if Some(number) == S::SIGINFO => Some(Cow::Borrowed("INFO")),
251                () if Some(number) == S::SIGIO => Some(Cow::Borrowed("IO")),
252                () if Some(number) == S::SIGLOST => Some(Cow::Borrowed("LOST")),
253                () if Some(number) == S::SIGPWR => Some(Cow::Borrowed("PWR")),
254                () if Some(number) == S::SIGSTKFLT => Some(Cow::Borrowed("STKFLT")),
255                () if Some(number) == S::SIGTHR => Some(Cow::Borrowed("THR")),
256                _ => {
257                    let range = system.sigrt_range()?;
258                    if number == *range.start() {
259                        Some(Cow::Borrowed("RTMIN"))
260                    } else if number == *range.end() {
261                        Some(Cow::Borrowed("RTMAX"))
262                    } else if range.contains(&number) {
263                        let rtmin = range.start().as_raw();
264                        let rtmax = range.end().as_raw();
265                        if raw_number <= rtmin.midpoint(rtmax) {
266                            let offset = raw_number - rtmin;
267                            Some(Cow::Owned(format!("RTMIN+{}", offset)))
268                        } else {
269                            let offset = rtmax - raw_number;
270                            Some(Cow::Owned(format!("RTMAX-{}", offset)))
271                        }
272                    } else {
273                        None
274                    }
275                }
276            }
277        }
278        inner(self, signal.into())
279    }
280
281    /// Converts a string representation of a signal to its signal number.
282    ///
283    /// This function returns `Some(number)` if the signal name is supported by
284    /// the system. Otherwise, it returns `None`.
285    ///
286    /// The input name should not include the `SIG` prefix, and is case-sensitive.
287    #[must_use]
288    fn str2sig(&self, name: &str) -> Option<Number> {
289        // Binary search on NAMED_SIGNALS
290        if let Ok(index) = Self::NAMED_SIGNALS.binary_search_by_key(&name, |s| s.0) {
291            return Self::NAMED_SIGNALS[index].1;
292        }
293
294        // Handle real-time signals
295        enum BaseName {
296            Rtmin,
297            Rtmax,
298        }
299        let (basename, suffix) = if let Some(suffix) = name.strip_prefix("RTMIN") {
300            (BaseName::Rtmin, suffix)
301        } else if let Some(suffix) = name.strip_prefix("RTMAX") {
302            (BaseName::Rtmax, suffix)
303        } else {
304            return None;
305        };
306        if !suffix.is_empty() && !suffix.starts_with(['+', '-']) {
307            return None;
308        }
309        let range = self.sigrt_range()?;
310        let base_raw = match basename {
311            BaseName::Rtmin => range.start().as_raw(),
312            BaseName::Rtmax => range.end().as_raw(),
313        };
314        let raw_number = if suffix.is_empty() {
315            base_raw
316        } else {
317            let offset: RawNumber = suffix.parse().ok()?;
318            base_raw.checked_add(offset)?
319        };
320        let number = Number::from_raw_unchecked(NonZero::new(raw_number)?);
321        range.contains(&number).then_some(number)
322    }
323
324    /// Tests if a signal number is valid and returns its name and number.
325    ///
326    /// This function returns `Some((name, number))` if the signal number refers
327    /// to a valid signal supported by the system. Otherwise, it returns `None`.
328    ///
329    /// Note that one signal number can have multiple names, in which case this
330    /// function returns the name that is considered the most common.
331    ///
332    /// If you only need to tell whether a signal number is valid, use
333    /// [`to_signal_number`](Self::to_signal_number), which is more efficient.
334    #[must_use]
335    fn validate_signal(&self, number: RawNumber) -> Option<(Name, Number)> {
336        let number = Number::from_raw_unchecked(NonZero::new(number)?);
337        let str_name = self.sig2str(number)?;
338        Some((str_name.parse().ok()?, number))
339    }
340
341    /// Returns the signal name for the signal number.
342    ///
343    /// This function returns the signal name for the given signal number.
344    ///
345    /// If the signal number is invalid, this function panics. It may occur if
346    /// the number is from a different system or was created without checking
347    /// the validity.
348    ///
349    /// Note that one signal number can have multiple names, in which case this
350    /// function returns the name that is considered the most common.
351    #[must_use]
352    fn signal_name_from_number(&self, number: Number) -> Name {
353        self.validate_signal(number.as_raw()).unwrap().0
354    }
355
356    /// Gets the signal number from the signal name.
357    ///
358    /// This function returns the signal number corresponding to the signal name
359    /// in the system. If the signal name is not supported, it returns `None`.
360    #[must_use]
361    fn signal_number_from_name(&self, name: Name) -> Option<Number> {
362        self.str2sig(&name.as_string())
363    }
364}
365
366/// Delegates the `Signals` trait to the contained instance of `S`
367impl<S: Signals> Signals for Rc<S> {
368    const SIGABRT: Number = S::SIGABRT;
369    const SIGALRM: Number = S::SIGALRM;
370    const SIGBUS: Number = S::SIGBUS;
371    const SIGCHLD: Number = S::SIGCHLD;
372    const SIGCLD: Option<Number> = S::SIGCLD;
373    const SIGCONT: Number = S::SIGCONT;
374    const SIGEMT: Option<Number> = S::SIGEMT;
375    const SIGFPE: Number = S::SIGFPE;
376    const SIGHUP: Number = S::SIGHUP;
377    const SIGILL: Number = S::SIGILL;
378    const SIGINFO: Option<Number> = S::SIGINFO;
379    const SIGINT: Number = S::SIGINT;
380    const SIGIO: Option<Number> = S::SIGIO;
381    const SIGIOT: Number = S::SIGIOT;
382    const SIGKILL: Number = S::SIGKILL;
383    const SIGLOST: Option<Number> = S::SIGLOST;
384    const SIGPIPE: Number = S::SIGPIPE;
385    const SIGPOLL: Option<Number> = S::SIGPOLL;
386    const SIGPROF: Number = S::SIGPROF;
387    const SIGPWR: Option<Number> = S::SIGPWR;
388    const SIGQUIT: Number = S::SIGQUIT;
389    const SIGSEGV: Number = S::SIGSEGV;
390    const SIGSTKFLT: Option<Number> = S::SIGSTKFLT;
391    const SIGSTOP: Number = S::SIGSTOP;
392    const SIGSYS: Number = S::SIGSYS;
393    const SIGTERM: Number = S::SIGTERM;
394    const SIGTHR: Option<Number> = S::SIGTHR;
395    const SIGTRAP: Number = S::SIGTRAP;
396    const SIGTSTP: Number = S::SIGTSTP;
397    const SIGTTIN: Number = S::SIGTTIN;
398    const SIGTTOU: Number = S::SIGTTOU;
399    const SIGURG: Number = S::SIGURG;
400    const SIGUSR1: Number = S::SIGUSR1;
401    const SIGUSR2: Number = S::SIGUSR2;
402    const SIGVTALRM: Number = S::SIGVTALRM;
403    const SIGWINCH: Number = S::SIGWINCH;
404    const SIGXCPU: Number = S::SIGXCPU;
405    const SIGXFSZ: Number = S::SIGXFSZ;
406
407    #[inline]
408    fn sigrt_range(&self) -> Option<RangeInclusive<Number>> {
409        (self as &S).sigrt_range()
410    }
411
412    const NAMED_SIGNALS: &'static [(&'static str, Option<Number>)] = S::NAMED_SIGNALS;
413
414    #[inline]
415    fn iter_sigrt(&self) -> impl DoubleEndedIterator<Item = Number> + use<S> {
416        (self as &S).iter_sigrt()
417    }
418    #[inline]
419    fn to_signal_number<N: Into<RawNumber>>(&self, number: N) -> Option<Number> {
420        (self as &S).to_signal_number(number)
421    }
422    #[inline]
423    fn sig2str<N: Into<RawNumber>>(&self, signal: N) -> Option<Cow<'static, str>> {
424        (self as &S).sig2str(signal)
425    }
426    #[inline]
427    fn str2sig(&self, name: &str) -> Option<Number> {
428        (self as &S).str2sig(name)
429    }
430    #[inline]
431    fn validate_signal(&self, number: RawNumber) -> Option<(Name, Number)> {
432        (self as &S).validate_signal(number)
433    }
434    #[inline]
435    fn signal_name_from_number(&self, number: Number) -> Name {
436        (self as &S).signal_name_from_number(number)
437    }
438    #[inline]
439    fn signal_number_from_name(&self, name: Name) -> Option<Number> {
440        (self as &S).signal_number_from_name(name)
441    }
442}
443
444/// Operation applied to the signal blocking mask
445///
446/// This enum corresponds to the operations of the `sigprocmask` system call and
447/// is used in the [`Sigmask::sigmask`] method.
448#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
449#[non_exhaustive]
450pub enum SigmaskOp {
451    /// Add signals to the mask (`SIG_BLOCK`)
452    Add,
453    /// Remove signals from the mask (`SIG_UNBLOCK`)
454    Remove,
455    /// Set the mask to the given signals (`SIG_SETMASK`)
456    Set,
457}
458
459/// Trait for managing signal blocking mask
460pub trait Sigmask: Signals {
461    /// Gets and/or sets the signal blocking mask.
462    ///
463    /// This trait is usually not used directly. Instead, it is used by
464    /// [`Concurrent`] and [`SharedSystem`] to configure signal handling
465    /// behavior of the process.
466    ///
467    /// This is a thin wrapper around the [`sigprocmask` system
468    /// call](https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_sigmask.html).
469    /// If `op` is `Some`, this function updates the signal blocking mask by
470    /// applying the given `SigmaskOp` and signal set to the current mask. If
471    /// `op` is `None`, this function does not change the mask.
472    /// If `old_mask` is `Some`, this function sets the previous mask to it.
473    ///
474    /// The return type is a future so that
475    /// [virtual systems](crate::system::virtual) can simulate termination or
476    /// suspension of the process that may be caused by a signal delivered as a
477    /// result of changing (for example, unblocking) the signal mask. In the
478    /// [real system](super::real), this function does not work asynchronously
479    /// and returns a ready `Future` with the result of the underlying system
480    /// call. See the [module-level documentation](super) for details.
481    fn sigmask(
482        &self,
483        op: Option<(SigmaskOp, &[Number])>,
484        old_mask: Option<&mut Vec<Number>>,
485    ) -> impl Future<Output = Result<()>> + use<Self>;
486}
487
488/// Delegates the `Sigmask` trait to the contained instance of `S`
489impl<S: Sigmask> Sigmask for Rc<S> {
490    #[inline]
491    fn sigmask(
492        &self,
493        op: Option<(SigmaskOp, &[Number])>,
494        old_mask: Option<&mut Vec<Number>>,
495    ) -> impl Future<Output = Result<()>> + use<S> {
496        (self as &S).sigmask(op, old_mask)
497    }
498}
499
500/// How the shell process responds to a signal
501#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
502pub enum Disposition {
503    /// Perform the default action for the signal.
504    ///
505    /// The default action depends on the signal. For example, `SIGINT` causes
506    /// the process to terminate, and `SIGTSTP` causes the process to stop.
507    #[default]
508    Default,
509    /// Ignore the signal.
510    Ignore,
511    /// Catch the signal.
512    Catch,
513}
514
515/// Trait for getting signal dispositions
516pub trait GetSigaction: Signals {
517    /// Gets the disposition for a signal.
518    ///
519    /// This is an abstract wrapper around the [`sigaction` system
520    /// call](https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigaction.html).
521    /// This function returns the current disposition if successful.
522    ///
523    /// To change the disposition, use [`Sigaction::sigaction`].
524    fn get_sigaction(&self, signal: Number) -> Result<Disposition>;
525}
526
527/// Delegates the `GetSigaction` trait to the contained instance of `S`
528impl<S: GetSigaction> GetSigaction for Rc<S> {
529    #[inline]
530    fn get_sigaction(&self, signal: Number) -> Result<Disposition> {
531        (self as &S).get_sigaction(signal)
532    }
533}
534
535/// Trait for managing signal dispositions
536pub trait Sigaction: GetSigaction {
537    /// Gets and sets the disposition for a signal.
538    ///
539    /// This trait is usually not used directly. Instead, it is used by
540    /// [`Concurrent`] and [`SharedSystem`] to configure signal handling
541    /// behavior of the process.
542    ///
543    /// This is an abstract wrapper around the [`sigaction` system
544    /// call](https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigaction.html).
545    /// This function returns the previous disposition if successful.
546    ///
547    /// When you set the disposition to `Disposition::Catch`, signals sent to
548    /// this process are accumulated in `self` and made available from
549    /// [`caught_signals`](CaughtSignals::caught_signals).
550    ///
551    /// To get the current disposition without changing it, use
552    /// [`GetSigaction::get_sigaction`].
553    fn sigaction(&self, signal: Number, action: Disposition) -> Result<Disposition>;
554}
555
556/// Delegates the `Sigaction` trait to the contained instance of `S`
557impl<S: Sigaction> Sigaction for Rc<S> {
558    #[inline]
559    fn sigaction(&self, signal: Number, action: Disposition) -> Result<Disposition> {
560        (self as &S).sigaction(signal, action)
561    }
562}
563
564/// Trait for examining signals caught by the process
565///
566/// Implementors of this trait usually also implement [`Sigaction`] to allow
567/// setting which signals are caught.
568pub trait CaughtSignals: Signals {
569    /// Returns signals this process has caught, if any.
570    ///
571    /// This trait is usually not used directly. Instead, it is used by
572    /// [`Concurrent`] and [`SharedSystem`] to collect signals caught by the
573    /// process.
574    ///
575    /// Implementors of this trait usually also implement [`Sigaction`] to allow
576    /// setting which signals are caught.
577    /// To catch a signal, you firstly install a signal handler by calling
578    /// [`Sigaction::sigaction`] with [`Disposition::Catch`]. Once the handler
579    /// is ready, signals sent to the process are accumulated in the
580    /// implementor. Calling this function retrieves the list of caught signals.
581    ///
582    /// This function clears the internal list of caught signals, so a next call
583    /// will return an empty list unless another signal is caught since the
584    /// first call. Because the list size may be limited, you should call this
585    /// function periodically before the list gets full, in which case further
586    /// caught signals are silently ignored.
587    ///
588    /// Note that signals become pending if sent while blocked by
589    /// [`Sigmask::sigmask`]. They must be unblocked so that they are caught and
590    /// made available from this function.
591    fn caught_signals(&self) -> Vec<Number>;
592}
593
594/// Delegates the `CaughtSignals` trait to the contained instance of `S`
595impl<S: CaughtSignals> CaughtSignals for Rc<S> {
596    #[inline]
597    fn caught_signals(&self) -> Vec<Number> {
598        (self as &S).caught_signals()
599    }
600}
601
602/// Trait for sending signals to processes
603pub trait SendSignal: Signals {
604    /// Sends a signal.
605    ///
606    /// This is a thin wrapper around the [`kill` system
607    /// call](https://pubs.opengroup.org/onlinepubs/9799919799/functions/kill.html).
608    /// If `signal` is `None`, permission to send a signal is checked, but no
609    /// signal is sent.
610    ///
611    /// The virtual system version of this function blocks the calling thread if
612    /// the signal stops or terminates the current process, hence returning a
613    /// future. See [`VirtualSystem::kill`] for details.
614    ///
615    /// [`VirtualSystem::kill`]: crate::system::virtual::VirtualSystem::kill
616    fn kill(
617        &self,
618        target: Pid,
619        signal: Option<Number>,
620    ) -> impl Future<Output = Result<()>> + use<Self>;
621
622    /// Sends a signal to the current process.
623    ///
624    /// This is a thin wrapper around the `raise` system call.
625    ///
626    /// The virtual system version of this function blocks the calling thread if
627    /// the signal stops or terminates the current process, hence returning a
628    /// future. See [`VirtualSystem::kill`] for details.
629    ///
630    /// [`VirtualSystem::kill`]: crate::system::virtual::VirtualSystem::kill
631    fn raise(&self, signal: Number) -> impl Future<Output = Result<()>> + use<Self>;
632}
633
634/// Delegates the `SendSignal` trait to the contained instance of `S`
635impl<S: SendSignal> SendSignal for Rc<S> {
636    #[inline]
637    fn kill(
638        &self,
639        target: Pid,
640        signal: Option<Number>,
641    ) -> impl Future<Output = Result<()>> + use<S> {
642        (self as &S).kill(target, signal)
643    }
644    #[inline]
645    fn raise(&self, signal: Number) -> impl Future<Output = Result<()>> + use<S> {
646        (self as &S).raise(signal)
647    }
648}