devela/sys/os/linux/structs/
sigaction.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// devela::sys::os::linux::structs::sigaction

#![cfg_attr(not(feature = "unsafe_syscall"), allow(dead_code))]

/// Represents the [`sigaction`] structure from libc.
/// Examine and change a signal action.
///
/// [`sigaction`]: https://man7.org/linux/man-pages/man2/sigaction.2.html
#[derive(Debug)]
#[repr(C)]
pub struct LinuxSigaction {
    /// A pointer to a signal handling function.
    ///
    /// This function receives the signal number as its only argument.
    pub sa_handler: extern "C" fn(i32),

    /// A set of flags which modify the behavior of the signal.
    pub sa_flags: usize,

    /// A legacy field that is not used on modern Linux systems, but must be
    /// filled in for compatibility
    pub sa_restorer: Option<extern "C" fn()>,

    /// A mask of signals that should be blocked.
    pub sa_mask: LinuxSigset,
}

impl LinuxSigaction {
    /// Retuns a new `LinuxSigation`.
    #[must_use]
    pub fn new(handler: extern "C" fn(i32), flags: usize, mask: LinuxSigset) -> Self {
        Self {
            sa_handler: handler,
            sa_flags: flags,
            sa_restorer: None,
            sa_mask: mask,
        }
    }
}

/// [`sa_handler`][Self::sa_handler] field constants.
impl LinuxSigaction {
    /// The default signal handling.
    pub const SIG_DFL: isize = 0;

    /// Ignore this signal.
    pub const SIG_IGN: isize = 1;

    // /// Error return from signal.
    // pub const SIG_ERR: isize = -1;
}

/// A set of signals.
#[repr(C)]
#[derive(Debug, Default, Clone, Copy)]
pub struct LinuxSigset {
    /// An array of signals.
    ///
    /// Its lenght is calculated from the number of signals divided by the bits of a usize.
    pub sig: [usize; Self::LEN],
}
impl LinuxSigset {
    const BITS_PER_USIZE: usize = usize::BITS as usize;
    // The hardcoded number of system signals defined in `LINUX_SIGNAL`.
    const NSIG: usize = 36;
    // The size of the array is the number of signals divided by the bits of an usize.
    const LEN: usize = { Self::NSIG.div_ceil(Self::BITS_PER_USIZE) };

    /// Returns the size in bytes of `LinuxSigset`.
    #[must_use]
    pub const fn size() -> usize {
        core::mem::size_of::<Self>()
    }
}
impl LinuxSigset {
    /// Sets the bit corresponding to a `signal` in the `sig` array.
    ///
    /// # Arguments
    /// * `signum` - The number of the signal. This should be between 1 and `NSIG`.
    ///
    /// # Panics
    /// Panics if `signum` < 1 or > 36.
    pub fn set_signal(&mut self, signal: i32) {
        let signal = signal as usize;
        assert![(1..=Self::NSIG).contains(&signal)];

        // Subtract 1 from the signal number because signal numbers start from 1
        // but array indices start from 0
        let signal_index = (signal - 1) / Self::BITS_PER_USIZE;
        let bit_position = (signal - 1) % Self::BITS_PER_USIZE;
        self.sig[signal_index] |= 1 << bit_position;
    }
}