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 {
46 fd: Readiness,
47 ring: Arc<ShmRing>,
48 stop: Arc<AtomicBool>,
49 drained: Arc<Drained>,
50 driver: Option<JoinHandle<()>>,
51}
52
53#[derive(Default)]
56struct Drained {
57 pending: Mutex<bool>,
58 taken: Condvar,
59}
60
61impl RingEventFd {
62 pub(crate) fn new(ring: Arc<ShmRing>) -> io::Result<Self> {
63 let (fd, driver_fd) = local_notification_pair()?;
64 let stop = Arc::new(AtomicBool::new(false));
65 let drained = Arc::new(Drained::default());
66 let (driver_stop, driver_drained, driver_ring) =
67 (stop.clone(), drained.clone(), ring.clone());
68 let mut observed =
69 ring.notification_generation().load(Ordering::Acquire);
70
71 let driver = std::thread::Builder::new()
72 .name(format!("orbit-ring-{}-eventfd", ring.kind()))
73 .spawn(move || {
74 let generation = driver_ring.notification_generation();
75 let waiters = driver_ring.notification_waiters();
76 while !driver_stop.load(Ordering::Acquire) {
77 waiters.fetch_add(1, Ordering::SeqCst);
81 let current = generation.load(Ordering::SeqCst);
82 if current == observed
83 && !driver_stop.load(Ordering::Acquire)
84 {
85 let parked =
86 crate::sync::wait_word(generation, observed);
87 waiters.fetch_sub(1, Ordering::SeqCst);
88 if parked.is_err() {
89 break;
90 }
91 continue;
92 }
93 waiters.fetch_sub(1, Ordering::SeqCst);
94 if driver_stop.load(Ordering::Acquire) {
95 break;
96 }
97 observed = current;
98 *driver_drained.pending.lock().unwrap() = true;
99 if driver_fd.signal().is_err() {
100 break;
101 }
102 let mut pending = driver_drained.pending.lock().unwrap();
103 while *pending && !driver_stop.load(Ordering::Acquire) {
104 pending = driver_drained.taken.wait(pending).unwrap();
105 }
106 }
107 })?;
108
109 Ok(Self { fd, ring, stop, drained, driver: Some(driver) })
110 }
111
112 pub(crate) fn notify(ring: &ShmRing) -> io::Result<()> {
114 ring.notification_generation().fetch_add(1, Ordering::SeqCst);
115 if ring.notification_waiters().load(Ordering::SeqCst) == 0 {
116 return Ok(());
117 }
118 crate::sync::wake_word(ring.notification_generation())
119 }
120
121 pub fn drain(&self) -> io::Result<u64> {
123 let tokens = self.fd.drain()?;
124 *self.drained.pending.lock().unwrap() = false;
125 self.drained.taken.notify_one();
126 Ok(tokens)
127 }
128}
129
130impl AsRawFd for RingEventFd {
131 fn as_raw_fd(&self) -> RawFd {
132 self.fd.as_raw_fd()
133 }
134}
135
136impl AsFd for RingEventFd {
137 fn as_fd(&self) -> BorrowedFd<'_> {
138 self.fd.as_fd()
139 }
140}
141
142impl fmt::Debug for RingEventFd {
143 fn fmt(
144 &self,
145 f: &mut fmt::Formatter<'_>,
146 ) -> fmt::Result {
147 f.debug_struct("RingEventFd")
148 .field("fd", &self.fd.as_raw_fd())
149 .field("ring_kind", &self.ring.kind())
150 .finish_non_exhaustive()
151 }
152}
153
154impl Drop for RingEventFd {
155 fn drop(&mut self) {
156 self.stop.store(true, Ordering::Release);
157 {
161 let _pending = self.drained.pending.lock().unwrap();
162 self.drained.taken.notify_one();
163 }
164 self.ring.notification_generation().fetch_add(1, Ordering::SeqCst);
165 let _ = crate::sync::wake_word(self.ring.notification_generation());
166 if let Some(driver) = self.driver.take() {
167 let _ = driver.join();
168 }
169 }
170}
171
172#[cfg(any(target_os = "linux", target_os = "freebsd"))]
173fn local_notification_pair() -> io::Result<(Readiness, Signal)> {
174 crate::readiness::pair()
175}
176
177#[cfg(target_os = "macos")]
180fn local_notification_pair() -> io::Result<(Readiness, Signal)> {
181 if crate::sync::macos::api().is_none() {
182 return Err(io::Error::new(
183 io::ErrorKind::Unsupported,
184 "Orbit native readiness requires macOS 14.4 or later",
185 ));
186 }
187 crate::readiness::pair()
188}