1#![no_std]
4#![deny(missing_docs)]
5
6extern crate alloc;
7
8use alloc::{boxed::Box, sync::Arc, vec::Vec};
9use core::{
10 sync::atomic::{AtomicBool, Ordering},
11 task::Waker,
12};
13
14use ax_lazyinit::OnceLock;
15use ax_sync::SpinLock;
16use axpoll::{IoEvents, PollRegistration, PollSource, RegistrationMode};
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19struct RegistrationId(u64);
20
21struct Entry {
22 id: RegistrationId,
23 waker: Waker,
24 notified: Arc<AtomicBool>,
25 interests: IoEvents,
26 mode: RegistrationMode,
27}
28
29struct Inner {
30 entries: Vec<Entry>,
31 next_id: u64,
32 closed: bool,
33}
34
35impl Inner {
36 const fn new() -> Self {
37 Self {
38 entries: Vec::new(),
39 next_id: 0,
40 closed: false,
41 }
42 }
43
44 fn register(
45 &mut self,
46 waker: &Waker,
47 interests: IoEvents,
48 mode: RegistrationMode,
49 ) -> Option<(RegistrationId, Arc<AtomicBool>)> {
50 if self.closed || interests.is_empty() {
51 return None;
52 }
53 let id = RegistrationId(self.next_id);
54 let notified = Arc::new(AtomicBool::new(false));
55 self.next_id = self
56 .next_id
57 .checked_add(1)
58 .expect("poll registration ID space exhausted");
59 self.entries.push(Entry {
60 id,
61 waker: waker.clone(),
62 notified: notified.clone(),
63 interests,
64 mode,
65 });
66 Some((id, notified))
67 }
68
69 fn unregister(&mut self, id: RegistrationId) {
70 if let Some(index) = self.entries.iter().position(|entry| entry.id == id) {
71 self.entries.remove(index);
72 }
73 }
74
75 fn wake_boundary(&self) -> u64 {
76 self.next_id
77 }
78
79 fn take_next_matching(
80 &mut self,
81 ready: IoEvents,
82 boundary: u64,
83 exclusive_available: bool,
84 ) -> Option<Entry> {
85 let index = self.entries.iter().position(|entry| {
86 entry.id.0 < boundary
87 && entry.interests.intersects(ready)
88 && (entry.mode == RegistrationMode::Shared || exclusive_available)
89 })?;
90 self.entries[index].notified.store(true, Ordering::Release);
91 Some(self.entries.remove(index))
92 }
93
94 fn take_next_before(&mut self, boundary: u64) -> Option<Entry> {
95 let index = self
96 .entries
97 .iter()
98 .position(|entry| entry.id.0 < boundary)?;
99 self.entries[index].notified.store(true, Ordering::Release);
100 Some(self.entries.remove(index))
101 }
102}
103
104struct PollState(SpinLock<Inner>);
105
106impl PollState {
107 const fn new() -> Self {
108 Self(SpinLock::new(Inner::new()))
109 }
110
111 fn register(
112 &self,
113 waker: &Waker,
114 interests: IoEvents,
115 mode: RegistrationMode,
116 ) -> Option<(RegistrationId, Arc<AtomicBool>)> {
117 self.0.lock().register(waker, interests, mode)
118 }
119
120 fn unregister(&self, id: RegistrationId) {
121 self.0.lock().unregister(id);
122 }
123
124 fn wake_with(
125 &self,
126 ready: IoEvents,
127 mut exclusive_budget: usize,
128 wake: &mut impl FnMut(Waker),
129 ) -> usize {
130 let boundary = self.0.lock().wake_boundary();
131 let mut woke = 0;
132 loop {
133 let entry = self
134 .0
135 .lock()
136 .take_next_matching(ready, boundary, exclusive_budget != 0);
137 let Some(entry) = entry else {
138 return woke;
139 };
140 if entry.mode == RegistrationMode::Exclusive {
141 exclusive_budget -= 1;
142 }
143 wake(entry.waker);
144 woke += 1;
145 }
146 }
147
148 fn close(&self) {
149 let boundary = {
150 let mut inner = self.0.lock();
151 inner.closed = true;
152 inner.wake_boundary()
153 };
154 loop {
155 let entry = self.0.lock().take_next_before(boundary);
156 let Some(entry) = entry else {
157 return;
158 };
159 entry.waker.wake();
160 }
161 }
162}
163
164struct Registration {
165 state: Arc<PollState>,
166 id: RegistrationId,
167 notified: Arc<AtomicBool>,
168}
169
170impl PollRegistration for Registration {
171 fn was_notified(&self) -> bool {
172 self.notified.load(Ordering::Acquire)
173 }
174}
175
176impl Drop for Registration {
177 fn drop(&mut self) {
178 self.state.unregister(self.id);
179 }
180}
181
182pub struct PollSet(OnceLock<Arc<PollState>>);
184
185impl Default for PollSet {
186 fn default() -> Self {
187 Self::new()
188 }
189}
190
191impl PollSet {
192 pub const fn new() -> Self {
194 Self(OnceLock::new())
195 }
196
197 fn state(&self) -> Arc<PollState> {
198 Arc::clone(self.0.call_once(|| Arc::new(PollState::new())))
199 }
200
201 pub unsafe fn wake(&self, ready: IoEvents) -> usize {
209 let Some(state) = self.0.get() else {
210 return 0;
211 };
212 state.wake_with(ready, 1, &mut Waker::wake)
213 }
214
215 pub unsafe fn wake_with(&self, ready: IoEvents, mut wake: impl FnMut(Waker)) -> usize {
230 let Some(state) = self.0.get() else {
231 return 0;
232 };
233 state.wake_with(ready, 1, &mut wake)
234 }
235
236 pub unsafe fn wake_all(&self, ready: IoEvents) -> usize {
246 let Some(state) = self.0.get() else {
247 return 0;
248 };
249 state.wake_with(ready, usize::MAX, &mut Waker::wake)
250 }
251}
252
253impl PollSource for PollSet {
254 unsafe fn register(
255 &self,
256 waker: &Waker,
257 interests: IoEvents,
258 mode: RegistrationMode,
259 ) -> Option<Box<dyn PollRegistration>> {
260 let state = self.state();
261 state
262 .register(waker, interests, mode)
263 .map(|(id, notified)| {
264 let registration: Box<dyn PollRegistration> = Box::new(Registration {
265 state,
266 id,
267 notified,
268 });
269 registration
270 })
271 }
272}
273
274impl Drop for PollSet {
275 fn drop(&mut self) {
276 if let Some(state) = self.0.get() {
277 state.close();
278 }
279 }
280}