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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
use alloc::{borrow::Cow, sync::Arc};
use core::{
mem,
sync::atomic::{AtomicBool, Ordering},
task::Context,
};
use ax_errno::{AxError, AxResult};
use ax_kspin::SpinNoIrq;
use ax_task::{
current,
future::{block_on, poll_io},
};
use axpoll::{IoEvents, PollSet, Pollable};
use starry_signal::{SignalInfo, SignalSet};
use zerocopy::{Immutable, IntoBytes};
use crate::{
file::{FileLike, IoDst, IoSrc},
task::AsThread,
};
/// The size of signalfd_siginfo structure (128 bytes as per Linux
/// specification)
const SIGNALFD_SIGINFO_SIZE: usize = 128;
/// signalfd_siginfo structure layout
/// This matches the Linux signalfd_siginfo structure (128 bytes)
#[repr(C)]
#[derive(Immutable, IntoBytes)]
struct SignalfdSiginfo {
ssi_signo: u32, // Signal number
ssi_errno: i32, // Error number (unused)
ssi_code: i32, // Signal code
ssi_pid: u32, // PID of sender
ssi_uid: u32, // Real UID of sender
ssi_fd: i32, // File descriptor (SIGIO)
ssi_tid: u32, // Kernel timer ID (POSIX timers)
ssi_band: u32, // Band event (SIGIO)
ssi_overrun: u32, // POSIX timer overrun count
ssi_trapno: u32, // Trap number that caused signal
ssi_status: i32, // Exit status or signal (SIGCHLD)
ssi_int: i32, // Integer sent by sigqueue(2)
ssi_ptr: u64, // Pointer sent by sigqueue(2)
ssi_utime: u64, // User CPU time consumed (SIGCHLD)
ssi_stime: u64, // System CPU time consumed (SIGCHLD)
ssi_addr: u64, // Address that generated signal
ssi_addr_lsb: u16, // Least significant bit of address
_pad: [u8; 46], // Padding to make it 128 bytes
}
const _: [(); SIGNALFD_SIGINFO_SIZE] = [(); mem::size_of::<SignalfdSiginfo>()];
impl SignalfdSiginfo {
/// Convert from SignalInfo to signalfd_siginfo
fn from_signal_info(sig_info: &SignalInfo) -> Self {
let errno = sig_info.errno();
SignalfdSiginfo {
ssi_signo: sig_info.signo() as u32,
ssi_errno: errno,
ssi_code: sig_info.code(),
ssi_pid: sig_info.pid(),
ssi_uid: sig_info.uid(),
ssi_fd: -1,
ssi_tid: 0,
ssi_band: 0,
ssi_overrun: 0,
ssi_trapno: 0,
ssi_status: 0,
ssi_int: 0,
ssi_ptr: 0,
ssi_utime: 0,
ssi_stime: 0,
ssi_addr: 0,
ssi_addr_lsb: 0,
_pad: [0u8; 46],
}
}
}
pub struct Signalfd {
// SignalSet is a single Copy bitset, so a short project-visible spin lock
// is enough for now. Revisit this when a lockdep-aware project RwLock exists.
mask: SpinNoIrq<SignalSet>,
non_blocking: AtomicBool,
poll_rx: PollSet,
}
impl Signalfd {
pub fn new(mask: SignalSet) -> Arc<Self> {
Arc::new(Self {
mask: SpinNoIrq::new(mask),
non_blocking: AtomicBool::new(false),
poll_rx: PollSet::new(),
})
}
pub fn update_mask(&self, mask: SignalSet) {
{
*self.mask.lock() = mask;
}
// The signal mask update is visible before waking readers.
unsafe { self.poll_rx.wake(IoEvents::IN) };
}
fn mask(&self) -> SignalSet {
*self.mask.lock()
}
/// Check if there are any pending signals matching the mask
fn has_pending_signals(&self) -> bool {
let mask = self.mask();
let curr = current();
let signal = &curr.as_thread().signal;
let pending = signal.pending();
!(pending & mask).is_empty()
}
/// Dequeue a signal matching the mask
fn dequeue_signal(&self) -> Option<SignalInfo> {
let mask = self.mask();
let curr = current();
let signal = &curr.as_thread().signal;
signal.dequeue_signal(&mask)
}
}
impl FileLike for Signalfd {
fn read(&self, dst: &mut IoDst) -> AxResult<usize> {
if dst.remaining_mut() < SIGNALFD_SIGINFO_SIZE {
return Err(AxError::InvalidInput);
}
block_on(poll_io(self, IoEvents::IN, self.nonblocking(), || {
if let Some(sig_info) = self.dequeue_signal() {
// Convert SignalInfo to SignalfdSiginfo
let sfd_info = SignalfdSiginfo::from_signal_info(&sig_info);
// Write the structure to the destination buffer
let bytes = sfd_info.as_bytes();
dst.write(bytes)?;
// Wake up other waiters if there are more signals pending
if self.has_pending_signals() {
// Remaining pending signals are visible before re-wake.
unsafe { self.poll_rx.wake(IoEvents::IN) };
}
Ok(SIGNALFD_SIGINFO_SIZE)
} else {
Err(AxError::WouldBlock)
}
}))
}
fn write(&self, _src: &mut IoSrc) -> AxResult<usize> {
// signalfd is read-only
Err(AxError::BadFileDescriptor)
}
fn nonblocking(&self) -> bool {
self.non_blocking.load(Ordering::Acquire)
}
fn set_nonblocking(&self, non_blocking: bool) -> AxResult {
self.non_blocking.store(non_blocking, Ordering::Release);
Ok(())
}
fn path(&self) -> Cow<'_, str> {
"anon_inode:[signalfd]".into()
}
}
impl Pollable for Signalfd {
fn poll(&self) -> IoEvents {
let mut events = IoEvents::empty();
events.set(IoEvents::IN, self.has_pending_signals());
events
}
fn register(&self, context: &mut Context<'_>, events: IoEvents) {
if events.contains(IoEvents::IN) {
// The private poll set covers mask updates and additional queued
// signals. New signal delivery wakes the current thread's shared
// signalfd poll set, so an already-blocked epoll waiter must be
// registered with both sources.
unsafe {
self.poll_rx.register(context.waker(), IoEvents::IN);
current()
.as_thread()
.signalfd_waker
.register(context.waker(), IoEvents::IN);
}
}
}
}