orbit_core/ring/
readiness.rs1#![cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
11
12use std::os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd};
13use std::sync::atomic::{AtomicBool, Ordering};
14use std::sync::{Arc, Condvar, Mutex};
15use std::thread::JoinHandle;
16use std::{fmt, io};
17
18use super::shm::ShmRing;
19use crate::readiness::{Readiness, Signal};
20
21pub struct RingEventFd {
32 fd: Readiness,
33 ring: Arc<ShmRing>,
34 stop: Arc<AtomicBool>,
35 driver: Option<JoinHandle<()>>,
36}
37
38impl RingEventFd {
39 pub(crate) fn new(ring: Arc<ShmRing>) -> io::Result<Self> {
40 let (fd, driver_fd) = local_notification_pair()?;
41 let stop = Arc::new(AtomicBool::new(false));
42 let driver_stop = stop.clone();
43 let driver_ring = ring.clone();
44 let mut observed =
45 ring.notification_generation().load(Ordering::Acquire);
46
47 #[cfg(target_os = "macos")]
49 debug_assert_ne!(fd.as_raw_fd(), driver_fd.as_raw_fd());
50
51 let driver = std::thread::Builder::new()
52 .name(format!("orbit-ring-{}-eventfd", ring.kind()))
53 .spawn(move || {
54 while !driver_stop.load(Ordering::Acquire) {
55 let current = driver_ring
56 .notification_generation()
57 .load(Ordering::Acquire);
58 if current != observed {
59 observed = current;
60 if driver_fd.signal().is_err() {
61 break;
62 }
63 continue;
64 }
65 if crate::sync::wait_word(
66 driver_ring.notification_generation(),
67 observed,
68 )
69 .is_err()
70 {
71 break;
72 }
73 }
74 })?;
75
76 Ok(Self { fd, ring, stop, driver: Some(driver) })
77 }
78
79 pub(crate) fn notify(ring: &ShmRing) -> io::Result<()> {
80 ring.notification_generation().fetch_add(1, Ordering::Release);
81 crate::sync::wake_word(ring.notification_generation())
82 }
83
84 pub fn drain(&self) -> io::Result<u64> {
89 self.fd.drain()
90 }
91}
92
93impl AsRawFd for RingEventFd {
94 fn as_raw_fd(&self) -> RawFd {
95 self.fd.as_raw_fd()
96 }
97}
98
99impl AsFd for RingEventFd {
100 fn as_fd(&self) -> BorrowedFd<'_> {
101 self.fd.as_fd()
102 }
103}
104
105impl fmt::Debug for RingEventFd {
106 fn fmt(
107 &self,
108 f: &mut fmt::Formatter<'_>,
109 ) -> fmt::Result {
110 f.debug_struct("RingEventFd")
111 .field("fd", &self.fd.as_raw_fd())
112 .field("ring_kind", &self.ring.kind())
113 .finish_non_exhaustive()
114 }
115}
116
117impl Drop for RingEventFd {
118 fn drop(&mut self) {
119 self.stop.store(true, Ordering::Release);
120 self.ring.notification_generation().fetch_add(1, Ordering::Release);
124 let _ = crate::sync::wake_word(self.ring.notification_generation());
125 if let Some(driver) = self.driver.take() {
126 let _ = driver.join();
127 }
128 }
129}
130
131pub struct ParkedRingEventFd {
159 fd: Readiness,
160 ring: Arc<ShmRing>,
161 stop: Arc<AtomicBool>,
162 drained: Arc<Drained>,
163 driver: Option<JoinHandle<()>>,
164}
165
166#[derive(Default)]
169struct Drained {
170 pending: Mutex<bool>,
171 taken: Condvar,
172}
173
174impl ParkedRingEventFd {
175 pub(crate) fn new(ring: Arc<ShmRing>) -> io::Result<Self> {
176 let (fd, driver_fd) = local_notification_pair()?;
177 let stop = Arc::new(AtomicBool::new(false));
178 let drained = Arc::new(Drained::default());
179 let (driver_stop, driver_drained, driver_ring) =
180 (stop.clone(), drained.clone(), ring.clone());
181 let mut observed =
182 ring.notification_generation().load(Ordering::Acquire);
183
184 let driver = std::thread::Builder::new()
185 .name(format!("orbit-ring-{}-parked", ring.kind()))
186 .spawn(move || {
187 let generation = driver_ring.notification_generation();
188 let waiters = driver_ring.notification_waiters();
189 while !driver_stop.load(Ordering::Acquire) {
190 waiters.fetch_add(1, Ordering::SeqCst);
194 let current = generation.load(Ordering::SeqCst);
195 if current == observed
196 && !driver_stop.load(Ordering::Acquire)
197 {
198 let parked =
199 crate::sync::wait_word(generation, observed);
200 waiters.fetch_sub(1, Ordering::SeqCst);
201 if parked.is_err() {
202 break;
203 }
204 continue;
205 }
206 waiters.fetch_sub(1, Ordering::SeqCst);
207 if driver_stop.load(Ordering::Acquire) {
208 break;
209 }
210 observed = current;
211 *driver_drained.pending.lock().unwrap() = true;
212 if driver_fd.signal().is_err() {
213 break;
214 }
215 let mut pending = driver_drained.pending.lock().unwrap();
216 while *pending && !driver_stop.load(Ordering::Acquire) {
217 pending = driver_drained.taken.wait(pending).unwrap();
218 }
219 }
220 })?;
221
222 Ok(Self { fd, ring, stop, drained, driver: Some(driver) })
223 }
224
225 pub(crate) fn notify(ring: &ShmRing) -> io::Result<()> {
227 ring.notification_generation().fetch_add(1, Ordering::SeqCst);
228 if ring.notification_waiters().load(Ordering::SeqCst) == 0 {
229 return Ok(());
230 }
231 crate::sync::wake_word(ring.notification_generation())
232 }
233
234 pub fn drain(&self) -> io::Result<u64> {
236 let tokens = self.fd.drain()?;
237 *self.drained.pending.lock().unwrap() = false;
238 self.drained.taken.notify_one();
239 Ok(tokens)
240 }
241}
242
243impl AsRawFd for ParkedRingEventFd {
244 fn as_raw_fd(&self) -> RawFd {
245 self.fd.as_raw_fd()
246 }
247}
248
249impl AsFd for ParkedRingEventFd {
250 fn as_fd(&self) -> BorrowedFd<'_> {
251 self.fd.as_fd()
252 }
253}
254
255impl fmt::Debug for ParkedRingEventFd {
256 fn fmt(
257 &self,
258 f: &mut fmt::Formatter<'_>,
259 ) -> fmt::Result {
260 f.debug_struct("ParkedRingEventFd")
261 .field("fd", &self.fd.as_raw_fd())
262 .field("ring_kind", &self.ring.kind())
263 .finish_non_exhaustive()
264 }
265}
266
267impl Drop for ParkedRingEventFd {
268 fn drop(&mut self) {
269 self.stop.store(true, Ordering::Release);
270 {
274 let _pending = self.drained.pending.lock().unwrap();
275 self.drained.taken.notify_one();
276 }
277 self.ring.notification_generation().fetch_add(1, Ordering::SeqCst);
278 let _ = crate::sync::wake_word(self.ring.notification_generation());
279 if let Some(driver) = self.driver.take() {
280 let _ = driver.join();
281 }
282 }
283}
284
285#[cfg(any(target_os = "linux", target_os = "freebsd"))]
286fn local_notification_pair() -> io::Result<(Readiness, Signal)> {
287 crate::readiness::pair()
288}
289
290#[cfg(target_os = "macos")]
293fn local_notification_pair() -> io::Result<(Readiness, Signal)> {
294 if crate::sync::macos::api().is_none() {
295 return Err(io::Error::new(
296 io::ErrorKind::Unsupported,
297 "Orbit native readiness requires macOS 14.4 or later",
298 ));
299 }
300 crate::readiness::pair()
301}