Coverage Report

Created: 2025-12-12 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/nix-0.28.0/src/sys/signalfd.rs
Line
Count
Source
1
//! Interface for the `signalfd` syscall.
2
//!
3
//! # Signal discarding
4
//! When a signal can't be delivered to a process (or thread), it will become a pending signal.
5
//! Failure to deliver could happen if the signal is blocked by every thread in the process or if
6
//! the signal handler is still handling a previous signal.
7
//!
8
//! If a signal is sent to a process (or thread) that already has a pending signal of the same
9
//! type, it will be discarded. This means that if signals of the same type are received faster than
10
//! they are processed, some of those signals will be dropped. Because of this limitation,
11
//! `signalfd` in itself cannot be used for reliable communication between processes or threads.
12
//!
13
//! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending
14
//! (ie. not consumed from a signalfd) it will be delivered to the signal handler.
15
//!
16
//! Please note that signal discarding is not specific to `signalfd`, but also happens with regular
17
//! signal handlers.
18
use crate::errno::Errno;
19
pub use crate::sys::signal::{self, SigSet};
20
use crate::Result;
21
pub use libc::signalfd_siginfo as siginfo;
22
23
use std::mem;
24
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
25
26
libc_bitflags! {
27
    pub struct SfdFlags: libc::c_int {
28
        SFD_NONBLOCK;
29
        SFD_CLOEXEC;
30
    }
31
}
32
33
#[deprecated(since = "0.23.0", note = "use mem::size_of::<siginfo>() instead")]
34
pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>();
35
36
/// Creates a new file descriptor for reading signals.
37
///
38
/// **Important:** please read the module level documentation about signal discarding before using
39
/// this function!
40
///
41
/// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor.
42
///
43
/// A signal must be blocked on every thread in a process, otherwise it won't be visible from
44
/// signalfd (the default handler will be invoked instead).
45
///
46
/// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html)
47
#[deprecated(since = "0.27.0", note = "Use SignalFd instead")]
48
0
pub fn signalfd<F: AsFd>(
49
0
    fd: Option<F>,
50
0
    mask: &SigSet,
51
0
    flags: SfdFlags,
52
0
) -> Result<OwnedFd> {
53
0
    _signalfd(fd, mask, flags)
54
0
}
55
56
0
fn _signalfd<F: AsFd>(
57
0
    fd: Option<F>,
58
0
    mask: &SigSet,
59
0
    flags: SfdFlags,
60
0
) -> Result<OwnedFd> {
61
0
    let raw_fd = fd.map_or(-1, |x| x.as_fd().as_raw_fd());
62
    unsafe {
63
0
        Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits()))
64
0
            .map(|raw_fd| FromRawFd::from_raw_fd(raw_fd))
65
    }
66
0
}
67
68
/// A helper struct for creating, reading and closing a `signalfd` instance.
69
///
70
/// **Important:** please read the module level documentation about signal discarding before using
71
/// this struct!
72
///
73
/// # Examples
74
///
75
/// ```
76
/// # use nix::sys::signalfd::*;
77
/// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used
78
/// let mut mask = SigSet::empty();
79
/// mask.add(signal::SIGUSR1);
80
/// mask.thread_block().unwrap();
81
///
82
/// // Signals are queued up on the file descriptor
83
/// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
84
///
85
/// match sfd.read_signal() {
86
///     // we caught a signal
87
///     Ok(Some(sig)) => (),
88
///     // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set,
89
///     // otherwise the read_signal call blocks)
90
///     Ok(None) => (),
91
///     Err(err) => (), // some error happend
92
/// }
93
/// ```
94
#[derive(Debug)]
95
pub struct SignalFd(OwnedFd);
96
97
impl SignalFd {
98
0
    pub fn new(mask: &SigSet) -> Result<SignalFd> {
99
0
        Self::with_flags(mask, SfdFlags::empty())
100
0
    }
101
102
0
    pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> {
103
0
        let fd = _signalfd(None::<OwnedFd>, mask, flags)?;
104
105
0
        Ok(SignalFd(fd))
106
0
    }
107
108
0
    pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
109
0
        self.update(mask, SfdFlags::empty())
110
0
    }
111
112
0
    pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
113
0
        let mut buffer = mem::MaybeUninit::<siginfo>::uninit();
114
115
0
        let size = mem::size_of_val(&buffer);
116
0
        let res = Errno::result(unsafe {
117
0
            libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr().cast(), size)
118
        })
119
0
        .map(|r| r as usize);
120
0
        match res {
121
0
            Ok(x) if x == size => Ok(Some(unsafe { buffer.assume_init() })),
122
0
            Ok(_) => unreachable!("partial read on signalfd"),
123
0
            Err(Errno::EAGAIN) => Ok(None),
124
0
            Err(error) => Err(error),
125
        }
126
0
    }
127
128
0
    fn update(&self, mask: &SigSet, flags: SfdFlags) -> Result<()> {
129
0
        let raw_fd = self.0.as_raw_fd();
130
        unsafe {
131
0
            Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits()))
132
0
                .map(drop)
133
        }
134
0
    }
135
}
136
137
impl AsFd for SignalFd {
138
0
    fn as_fd(&self) -> BorrowedFd {
139
0
        self.0.as_fd()
140
0
    }
141
}
142
impl AsRawFd for SignalFd {
143
0
    fn as_raw_fd(&self) -> RawFd {
144
0
        self.0.as_raw_fd()
145
0
    }
146
}
147
148
impl Iterator for SignalFd {
149
    type Item = siginfo;
150
151
0
    fn next(&mut self) -> Option<Self::Item> {
152
0
        match self.read_signal() {
153
0
            Ok(Some(sig)) => Some(sig),
154
0
            Ok(None) | Err(_) => None,
155
        }
156
0
    }
157
}