Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/linux/signalfd.rs
5394 views
1
// Copyright 2017 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::fs::File;
6
use std::mem;
7
use std::os::raw::c_int;
8
use std::os::unix::io::AsRawFd;
9
use std::os::unix::io::FromRawFd;
10
use std::os::unix::io::RawFd;
11
use std::result;
12
13
use libc::c_void;
14
use libc::read;
15
use libc::signalfd;
16
use libc::signalfd_siginfo;
17
use libc::EAGAIN;
18
use libc::SFD_CLOEXEC;
19
use libc::SFD_NONBLOCK;
20
use log::error;
21
use remain::sorted;
22
use thiserror::Error;
23
24
use super::signal;
25
use super::Error as ErrnoError;
26
use super::RawDescriptor;
27
use crate::descriptor::AsRawDescriptor;
28
29
#[sorted]
30
#[derive(Error, Debug)]
31
pub enum Error {
32
/// Failed to block the signal when creating signalfd.
33
#[error("failed to block the signal when creating signalfd: {0}")]
34
CreateBlockSignal(signal::Error),
35
/// Failed to create a new signalfd.
36
#[error("failed to create a new signalfd: {0}")]
37
CreateSignalFd(ErrnoError),
38
/// Failed to construct sigset when creating signalfd.
39
#[error("failed to construct sigset when creating signalfd: {0}")]
40
CreateSigset(ErrnoError),
41
/// Signalfd could be read, but didn't return a full siginfo struct.
42
/// This wraps the number of bytes that were actually read.
43
#[error("signalfd failed to return a full siginfo struct, read only {0} bytes")]
44
SignalFdPartialRead(usize),
45
/// Unable to read from signalfd.
46
#[error("unable to read from signalfd: {0}")]
47
SignalFdRead(ErrnoError),
48
}
49
50
pub type Result<T> = result::Result<T, Error>;
51
52
/// A safe wrapper around a Linux signalfd (man 2 signalfd).
53
///
54
/// A signalfd can be used for non-synchronous signals (such as SIGCHLD) so that
55
/// signals can be processed without the use of a signal handler.
56
pub struct SignalFd {
57
signalfd: File,
58
signal: c_int,
59
}
60
61
impl SignalFd {
62
/// Creates a new SignalFd for the given signal, blocking the normal handler
63
/// for the signal as well. Since we mask out the normal handler, this is
64
/// a risky operation - signal masking will persist across fork and even
65
/// **exec** so the user of SignalFd should think long and hard about
66
/// when to mask signals.
67
pub fn new(signal: c_int) -> Result<SignalFd> {
68
let sigset = signal::create_sigset(&[signal]).map_err(Error::CreateSigset)?;
69
70
// SAFETY:
71
// This is safe as we check the return value and know that fd is valid.
72
let fd = unsafe { signalfd(-1, &sigset, SFD_CLOEXEC | SFD_NONBLOCK) };
73
if fd < 0 {
74
return Err(Error::CreateSignalFd(ErrnoError::last()));
75
}
76
77
// Mask out the normal handler for the signal.
78
signal::block_signal(signal).map_err(Error::CreateBlockSignal)?;
79
80
// SAFETY:
81
// This is safe because we checked fd for success and know the
82
// kernel gave us an fd that we own.
83
unsafe {
84
Ok(SignalFd {
85
signalfd: File::from_raw_fd(fd),
86
signal,
87
})
88
}
89
}
90
91
/// Read a siginfo struct from the signalfd, if available.
92
pub fn read(&self) -> Result<Option<signalfd_siginfo>> {
93
// SAFETY:
94
// signalfd_siginfo doesn't have a default, so just zero it.
95
let mut siginfo: signalfd_siginfo = unsafe { mem::zeroed() };
96
let siginfo_size = mem::size_of::<signalfd_siginfo>();
97
98
// SAFETY:
99
// This read is safe since we've got the space allocated for a
100
// single signalfd_siginfo, and that's exactly how much we're
101
// reading. Handling of EINTR is not required since SFD_NONBLOCK
102
// was specified. signalfds will always read in increments of
103
// sizeof(signalfd_siginfo); see man 2 signalfd.
104
let ret = unsafe {
105
read(
106
self.signalfd.as_raw_fd(),
107
&mut siginfo as *mut signalfd_siginfo as *mut c_void,
108
siginfo_size,
109
)
110
};
111
112
if ret < 0 {
113
let err = ErrnoError::last();
114
if err.errno() == EAGAIN {
115
Ok(None)
116
} else {
117
Err(Error::SignalFdRead(err))
118
}
119
} else if ret == (siginfo_size as isize) {
120
Ok(Some(siginfo))
121
} else {
122
Err(Error::SignalFdPartialRead(ret as usize))
123
}
124
}
125
}
126
127
impl AsRawFd for SignalFd {
128
fn as_raw_fd(&self) -> RawFd {
129
self.signalfd.as_raw_fd()
130
}
131
}
132
133
impl AsRawDescriptor for SignalFd {
134
fn as_raw_descriptor(&self) -> RawDescriptor {
135
self.signalfd.as_raw_descriptor()
136
}
137
}
138
139
impl Drop for SignalFd {
140
fn drop(&mut self) {
141
// This is thread-safe and safe in the sense that we're doing what
142
// was promised - unmasking the signal when we go out of scope.
143
let res = signal::unblock_signal(self.signal);
144
if let Err(e) = res {
145
error!("signalfd failed to unblock signal {}: {}", self.signal, e);
146
}
147
}
148
}
149
150
#[cfg(test)]
151
mod tests {
152
use std::mem;
153
use std::ptr::null;
154
155
use libc::pthread_sigmask;
156
use libc::raise;
157
use libc::sigismember;
158
use libc::sigset_t;
159
160
use super::super::signal::SIGRTMIN;
161
use super::*;
162
163
#[test]
164
fn new() {
165
SignalFd::new(SIGRTMIN()).unwrap();
166
}
167
168
#[test]
169
fn read() {
170
let sigid = SIGRTMIN() + 1;
171
let sigrt_fd = SignalFd::new(sigid).unwrap();
172
173
// SAFETY: Safe because sigid is valid and return value is checked.
174
let ret = unsafe { raise(sigid) };
175
assert_eq!(ret, 0);
176
177
let siginfo = sigrt_fd.read().unwrap().unwrap();
178
assert_eq!(siginfo.ssi_signo, sigid as u32);
179
}
180
181
#[test]
182
fn drop() {
183
let sigid = SIGRTMIN() + 2;
184
185
let sigrt_fd = SignalFd::new(sigid).unwrap();
186
// SAFETY: Safe because sigset and sigid are valid and return value is checked.
187
unsafe {
188
let mut sigset: sigset_t = mem::zeroed();
189
pthread_sigmask(0, null(), &mut sigset as *mut sigset_t);
190
assert_eq!(sigismember(&sigset, sigid), 1);
191
}
192
193
mem::drop(sigrt_fd);
194
195
// The signal should no longer be masked.
196
// SAFETY: Safe because sigset and sigid are valid and return value is checked.
197
unsafe {
198
let mut sigset: sigset_t = mem::zeroed();
199
pthread_sigmask(0, null(), &mut sigset as *mut sigset_t);
200
assert_eq!(sigismember(&sigset, sigid), 0);
201
}
202
}
203
}
204
205