1use crate::socket_table::SocketId;
2use event_listener::Event;
3use std::ops::{BitOr, BitOrAssign};
4use std::sync::{Arc, Condvar, Mutex, MutexGuard};
5use std::time::Duration;
6use web_time::Instant;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9pub struct PollEvents(u16);
10
11impl PollEvents {
12 pub const fn empty() -> Self {
13 Self(0)
14 }
15
16 pub const fn from_bits(bits: u16) -> Self {
17 Self(bits)
18 }
19
20 pub const fn bits(self) -> u16 {
21 self.0
22 }
23
24 pub const fn is_empty(self) -> bool {
25 self.0 == 0
26 }
27
28 pub const fn contains(self, other: Self) -> bool {
29 self.0 & other.0 == other.0
30 }
31
32 pub const fn intersects(self, other: Self) -> bool {
33 self.0 & other.0 != 0
34 }
35}
36
37impl BitOr for PollEvents {
38 type Output = Self;
39
40 fn bitor(self, rhs: Self) -> Self::Output {
41 Self(self.0 | rhs.0)
42 }
43}
44
45impl BitOrAssign for PollEvents {
46 fn bitor_assign(&mut self, rhs: Self) {
47 self.0 |= rhs.0;
48 }
49}
50
51pub const POLLIN: PollEvents = PollEvents(0x0001);
52pub const POLLOUT: PollEvents = PollEvents(0x0004);
53pub const POLLERR: PollEvents = PollEvents(0x0008);
54pub const POLLHUP: PollEvents = PollEvents(0x0010);
55pub const POLLNVAL: PollEvents = PollEvents(0x0020);
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub struct PollFd {
59 pub fd: u32,
60 pub events: PollEvents,
61 pub revents: PollEvents,
62}
63
64impl PollFd {
65 pub const fn new(fd: u32, events: PollEvents) -> Self {
66 Self {
67 fd,
68 events,
69 revents: PollEvents::empty(),
70 }
71 }
72}
73
74#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct PollResult {
76 pub ready_count: usize,
77 pub fds: Vec<PollFd>,
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub enum PollTarget {
82 Fd(u32),
83 Socket(SocketId),
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub struct PollTargetEntry {
88 pub target: PollTarget,
89 pub events: PollEvents,
90 pub revents: PollEvents,
91}
92
93impl PollTargetEntry {
94 pub const fn new(target: PollTarget, events: PollEvents) -> Self {
95 Self {
96 target,
97 events,
98 revents: PollEvents::empty(),
99 }
100 }
101
102 pub const fn fd(fd: u32, events: PollEvents) -> Self {
103 Self::new(PollTarget::Fd(fd), events)
104 }
105
106 pub const fn socket(socket_id: SocketId, events: PollEvents) -> Self {
107 Self::new(PollTarget::Socket(socket_id), events)
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq)]
112pub struct PollTargetResult {
113 pub ready_count: usize,
114 pub targets: Vec<PollTargetEntry>,
115}
116
117#[derive(Debug, Clone)]
124pub struct PollWaitHandle {
125 notifier: PollNotifier,
126}
127
128impl PollWaitHandle {
129 pub(crate) fn new(notifier: PollNotifier) -> Self {
130 Self { notifier }
131 }
132
133 pub fn snapshot(&self) -> u64 {
135 self.notifier.snapshot()
136 }
137
138 pub fn wait_for_change(&self, observed: u64, timeout: Option<Duration>) -> bool {
141 self.notifier.wait_for_change(observed, timeout)
142 }
143
144 pub async fn wait_for_change_async(&self, observed: u64) -> bool {
149 self.notifier.wait_for_change_async(observed).await
150 }
151}
152
153#[derive(Debug, Clone, Default)]
154pub(crate) struct PollNotifier {
155 inner: Arc<PollNotifierInner>,
156}
157
158#[derive(Debug, Default)]
159struct PollNotifierInner {
160 generation: Mutex<u64>,
161 waiters: Condvar,
162 async_waiters: Event,
163}
164
165impl PollNotifier {
166 pub(crate) fn notify(&self) {
167 {
168 let mut generation = lock_or_recover(&self.inner.generation);
169 *generation = generation.wrapping_add(1);
170 }
171 self.inner.waiters.notify_all();
172 self.inner.async_waiters.notify(usize::MAX);
173 }
174
175 pub(crate) fn snapshot(&self) -> u64 {
176 *lock_or_recover(&self.inner.generation)
177 }
178
179 pub(crate) fn wait_for_change(&self, observed: u64, timeout: Option<Duration>) -> bool {
180 let mut generation = lock_or_recover(&self.inner.generation);
181 if *generation != observed {
182 return true;
183 }
184
185 let Some(timeout) = timeout else {
186 while *generation == observed {
187 generation = wait_or_recover(&self.inner.waiters, generation);
188 }
189 return true;
190 };
191
192 if timeout.is_zero() {
193 return *generation != observed;
194 }
195
196 let deadline = Instant::now() + timeout;
197 loop {
198 let now = Instant::now();
199 if now >= deadline {
200 return *generation != observed;
201 }
202
203 let remaining = deadline.saturating_duration_since(now);
204 let (next_generation, wait_result) =
205 wait_timeout_or_recover(&self.inner.waiters, generation, remaining);
206 generation = next_generation;
207 if *generation != observed {
208 return true;
209 }
210 if wait_result.timed_out() {
211 return false;
212 }
213 }
214 }
215
216 pub(crate) async fn wait_for_change_async(&self, observed: u64) -> bool {
217 loop {
218 let listener = self.inner.async_waiters.listen();
221 if self.snapshot() != observed {
222 return true;
223 }
224 listener.await;
225 if self.snapshot() != observed {
226 return true;
227 }
228 }
229 }
230}
231
232fn lock_or_recover<'a, T>(mutex: &'a Mutex<T>) -> MutexGuard<'a, T> {
233 match mutex.lock() {
234 Ok(guard) => guard,
235 Err(poisoned) => poisoned.into_inner(),
236 }
237}
238
239fn wait_or_recover<'a, T>(condvar: &Condvar, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
240 match condvar.wait(guard) {
241 Ok(guard) => guard,
242 Err(poisoned) => poisoned.into_inner(),
243 }
244}
245
246fn wait_timeout_or_recover<'a, T>(
247 condvar: &Condvar,
248 guard: MutexGuard<'a, T>,
249 timeout: Duration,
250) -> (MutexGuard<'a, T>, std::sync::WaitTimeoutResult) {
251 match condvar.wait_timeout(guard, timeout) {
252 Ok(result) => result,
253 Err(poisoned) => poisoned.into_inner(),
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::PollNotifier;
260 use std::sync::mpsc;
261 use std::thread;
262 use std::time::Duration;
263
264 #[test]
265 fn infinite_wait_returns_after_notification_without_waiter_storage() {
266 let notifier = PollNotifier::default();
267 let observed = notifier.snapshot();
268 let waiter = notifier.clone();
269 let (started_tx, started_rx) = mpsc::channel();
270 let (done_tx, done_rx) = mpsc::channel();
271
272 let handle = thread::spawn(move || {
273 started_tx.send(()).expect("signal waiter start");
274 let changed = waiter.wait_for_change(observed, None);
275 done_tx.send(changed).expect("signal waiter result");
276 });
277
278 started_rx.recv().expect("waiter should start");
279 assert!(
280 done_rx.recv_timeout(Duration::from_millis(25)).is_err(),
281 "waiter should stay blocked before notification"
282 );
283
284 notifier.notify();
285 assert!(done_rx
286 .recv_timeout(Duration::from_secs(1))
287 .expect("waiter should wake after notification"));
288 handle.join().expect("waiter thread should finish");
289 }
290
291 #[test]
292 fn saturated_generation_still_notifies_waiters() {
293 let notifier = PollNotifier::default();
294 {
295 let mut generation = super::lock_or_recover(¬ifier.inner.generation);
296 *generation = u64::MAX;
297 }
298
299 let observed = notifier.snapshot();
300 let waiter = notifier.clone();
301 let (started_tx, started_rx) = mpsc::channel();
302 let (done_tx, done_rx) = mpsc::channel();
303
304 let handle = thread::spawn(move || {
305 started_tx.send(()).expect("signal waiter start");
306 let changed = waiter.wait_for_change(observed, Some(Duration::from_secs(1)));
307 done_tx.send(changed).expect("signal waiter result");
308 });
309
310 started_rx.recv().expect("waiter should start");
311 notifier.notify();
312
313 assert!(
314 done_rx
315 .recv_timeout(Duration::from_secs(2))
316 .expect("waiter should return after saturated notify"),
317 "saturated notify should still wake the waiter"
318 );
319 handle.join().expect("waiter thread should finish");
320 }
321}