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