task/
signal.rs

1use core::fmt::Debug;
2
3/// POSIX signals enumeration
4#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5#[repr(u8)]
6pub enum Signal {
7    /// Hangup detected on controlling terminal or death of controlling process (SIGHUP)
8    Hangup = 0,
9    /// Interrupt from keyboard (SIGINT)
10    Interrupt,
11    /// Quit from keyboard (SIGQUIT)
12    Quit,
13    /// Unused : Illegal Instruction (SIGILL)
14    IllegalInstruction,
15    /// Trace/breakpoint trap (SIGTRAP)
16    Trap,
17    /// Abort signal from abort(3) (SIGABRT)
18    Abort,
19    /// Bus error (bad memory access) (SIGBUS)
20    BusError,
21    /// Floating-point exception (SIGFPE)
22    FloatingPointException,
23    /// Kill signal (SIGKILL)
24    Kill,
25    /// User-defined signal 1 (SIGUSR1)
26    User1,
27    /// Invalid memory reference (SIGSEGV)
28    SegmentationFault,
29    /// User-defined signal 2 (SIGUSR2)
30    User2,
31    /// Broken pipe: write to pipe with no readers (SIGPIPE)
32    BrokenPipe,
33    /// Timer signal from alarm(2) (SIGALRM)
34    Alarm,
35    /// Termination signal (SIGTERM)
36    Termination,
37    /// Stack fault on coprocessor (unused) (SIGSTKFLT)
38    StackFault,
39    /// Child stopped or terminated (SIGCHLD)
40    Child,
41    /// Continue if stopped (SIGCONT)
42    Continue,
43    /// Stop process (SIGSTOP)
44    Stop,
45    /// Stop typed at terminal (SIGTSTP)
46    TerminalStop,
47    /// Terminal input for background process (SIGTTIN)
48    TerminalInput,
49    /// Terminal output for background process (SIGTTOU)
50    TerminalOutput,
51    /// Urgent condition on socket (4.2BSD) (SIGURG)
52    Urgent,
53    /// CPU time limit exceeded (4.2BSD) (SIGXCPU)
54    CpuTimeLimitExceeded,
55    /// File size limit exceeded (4.2BSD) (SIGXFSZ)
56    FileSizeLimitExceeded,
57    /// Virtual alarm clock (4.2BSD) (SIGVTALRM)
58    VirtualAlarm,
59    /// Profiling timer expired (SIGPROF)
60    ProfilingTimerExpired,
61    /// Window resize signal (4.3BSD, Sun) (SIGWINCH)
62    WindowResize,
63    /// I/O now possible (4.2BSD) (SIGIO)
64    IoPossible,
65    /// Power failure (System V) (SIGPWR)
66    PowerFailure,
67    /// Bad system call (SVr4) (SIGSYS)
68    BadSystemCall,
69}
70
71impl Signal {
72    pub const FIRST: Self = Self::Hangup;
73    pub const LAST: Self = Self::BadSystemCall;
74
75    pub const fn get_discriminant(&self) -> u8 {
76        *self as u8
77    }
78}
79
80#[derive(Debug, Copy, Clone)]
81#[repr(transparent)]
82pub struct SignalAccumulator {
83    accumulator: u32,
84}
85
86impl Default for SignalAccumulator {
87    fn default() -> Self {
88        Self::new()
89    }
90}
91
92impl SignalAccumulator {
93    pub const fn new() -> Self {
94        Self { accumulator: 0 }
95    }
96
97    pub const fn send(&mut self, signal: Signal) {
98        self.accumulator |= 1 << signal as u32;
99    }
100
101    pub const fn clear(&mut self, signal: Signal) {
102        self.accumulator &= !(1 << signal as u32);
103    }
104
105    pub const fn has_signal(&self, signal: Signal) -> bool {
106        self.accumulator & (1 << signal as u32) != 0
107    }
108
109    pub fn peek(&self) -> Option<Signal> {
110        for bit in Signal::FIRST as u8..=Signal::LAST as u8 {
111            let signal = unsafe { core::mem::transmute::<u8, Signal>(bit) };
112
113            if self.has_signal(signal) {
114                return Some(signal);
115            }
116        }
117
118        None
119    }
120
121    pub fn pop(&mut self) -> Option<Signal> {
122        if let Some(signal) = self.peek() {
123            self.clear(signal);
124
125            Some(signal)
126        } else {
127            None
128        }
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    fn test_send_and_has_signal() {
138        let mut acc = SignalAccumulator::new();
139        acc.send(Signal::Interrupt);
140        assert!(acc.has_signal(Signal::Interrupt));
141    }
142
143    #[test]
144    fn test_clear_signal() {
145        let mut acc = SignalAccumulator::new();
146        acc.send(Signal::Quit);
147        acc.clear(Signal::Quit);
148        assert!(!acc.has_signal(Signal::Quit));
149    }
150
151    #[test]
152    fn test_peek_and_pop() {
153        let mut acc = SignalAccumulator::new();
154        acc.send(Signal::Hangup);
155        acc.send(Signal::User1);
156        assert_eq!(acc.peek(), Some(Signal::Hangup));
157        assert_eq!(acc.pop(), Some(Signal::Hangup));
158        assert_eq!(acc.peek(), Some(Signal::User1));
159        assert_eq!(acc.pop(), Some(Signal::User1));
160        assert_eq!(acc.pop(), None);
161    }
162
163    #[test]
164    fn test_signal_discriminant() {
165        assert_eq!(
166            Signal::PowerFailure.get_discriminant(),
167            Signal::PowerFailure as u8
168        );
169    }
170}