Skip to main content

async_io/
reactor.rs

1use std::borrow::Borrow;
2use std::collections::BTreeMap;
3use std::fmt;
4use std::future::Future;
5use std::io;
6use std::marker::PhantomData;
7use std::mem;
8use std::panic;
9use std::pin::Pin;
10use std::sync::atomic::{AtomicUsize, Ordering};
11use std::sync::{Arc, Mutex, MutexGuard, OnceLock};
12use std::task::{ready, Context, Poll, Waker};
13use std::time::{Duration, Instant};
14
15use concurrent_queue::ConcurrentQueue;
16use polling::{Event, Events, Poller};
17use slab::Slab;
18
19// Choose the proper implementation of `Registration` based on the target platform.
20cfg_if::cfg_if! {
21    if #[cfg(any(
22        target_vendor = "apple",
23        target_os = "freebsd",
24        target_os = "netbsd",
25        target_os = "openbsd",
26        target_os = "dragonfly",
27    ))] {
28        mod kqueue;
29        pub use kqueue::Registration;
30    } else if #[cfg(unix)] {
31        mod unix;
32        pub use unix::Registration;
33    } else {
34        compile_error!("unsupported platform");
35    }
36}
37
38#[cfg(not(target_os = "espidf"))]
39const TIMER_QUEUE_SIZE: usize = 1000;
40
41/// ESP-IDF - being an embedded OS - does not need so many timers
42/// and this saves ~ 20K RAM which is a lot for an MCU with RAM < 400K
43#[cfg(target_os = "espidf")]
44const TIMER_QUEUE_SIZE: usize = 100;
45
46const READ: usize = 0;
47const WRITE: usize = 1;
48
49/// The reactor.
50///
51/// There is only one global instance of this type, accessible by [`Reactor::get()`].
52pub(crate) struct Reactor {
53    /// Portable bindings to epoll/kqueue/event ports.
54    ///
55    /// This is where I/O is polled, producing I/O events.
56    pub(crate) poller: Poller,
57
58    /// Ticker bumped before polling.
59    ///
60    /// This is useful for checking what is the current "round" of `ReactorLock::react()` when
61    /// synchronizing things in `Source::readable()` and `Source::writable()`. Both of those
62    /// methods must make sure they don't receive stale I/O events - they only accept events from a
63    /// fresh "round" of `ReactorLock::react()`.
64    ticker: AtomicUsize,
65
66    /// Registered sources.
67    sources: Mutex<Slab<Arc<Source>>>,
68
69    /// Temporary storage for I/O events when polling the reactor.
70    ///
71    /// Holding a lock on this event list implies the exclusive right to poll I/O.
72    events: Mutex<Events>,
73
74    /// An ordered map of registered timers.
75    ///
76    /// Timers are in the order in which they fire. The `usize` in this type is a timer ID used to
77    /// distinguish timers that fire at the same time. The `Waker` represents the task awaiting the
78    /// timer.
79    timers: Mutex<BTreeMap<(Instant, usize), Waker>>,
80
81    /// A queue of timer operations (insert and remove).
82    ///
83    /// When inserting or removing a timer, we don't process it immediately - we just push it into
84    /// this queue. Timers actually get processed when the queue fills up or the reactor is polled.
85    timer_ops: ConcurrentQueue<TimerOp>,
86}
87
88impl Reactor {
89    /// Returns a reference to the reactor.
90    pub(crate) fn get() -> &'static Reactor {
91        static REACTOR: OnceLock<Reactor> = OnceLock::new();
92
93        REACTOR.get_or_init(|| {
94            crate::driver::init();
95            Reactor {
96                poller: Poller::new().expect("cannot initialize I/O event notification"),
97                ticker: AtomicUsize::new(0),
98                sources: Mutex::new(Slab::new()),
99                events: Mutex::new(Events::new()),
100                timers: Mutex::new(BTreeMap::new()),
101                timer_ops: ConcurrentQueue::bounded(TIMER_QUEUE_SIZE),
102            }
103        })
104    }
105
106    /// Returns the current ticker.
107    pub(crate) fn ticker(&self) -> usize {
108        self.ticker.load(Ordering::SeqCst)
109    }
110
111    /// Registers an I/O source in the reactor.
112    pub(crate) fn insert_io(&self, raw: Registration) -> io::Result<Arc<Source>> {
113        // Create an I/O source for this file descriptor.
114        let source = {
115            let mut sources = self.sources.lock().unwrap();
116            let key = sources.vacant_entry().key();
117            let source = Arc::new(Source {
118                registration: raw,
119                key,
120                state: Default::default(),
121            });
122            sources.insert(source.clone());
123            source
124        };
125
126        // Register the file descriptor.
127        if let Err(err) = source.registration.add(&self.poller, source.key) {
128            let mut sources = self.sources.lock().unwrap();
129            sources.remove(source.key);
130            return Err(err);
131        }
132
133        Ok(source)
134    }
135
136    /// Deregisters an I/O source from the reactor.
137    pub(crate) fn remove_io(&self, source: &Source) -> io::Result<()> {
138        let mut sources = self.sources.lock().unwrap();
139        sources.remove(source.key);
140        source.registration.delete(&self.poller)
141    }
142
143    /// Registers a timer in the reactor.
144    ///
145    /// Returns the inserted timer's ID.
146    pub(crate) fn insert_timer(&self, when: Instant, waker: &Waker) -> usize {
147        // Generate a new timer ID.
148        static ID_GENERATOR: AtomicUsize = AtomicUsize::new(1);
149        let id = ID_GENERATOR.fetch_add(1, Ordering::Relaxed);
150
151        // Push an insert operation.
152        while self
153            .timer_ops
154            .push(TimerOp::Insert(when, id, waker.clone()))
155            .is_err()
156        {
157            // If the queue is full, drain it and try again.
158            let mut timers = self.timers.lock().unwrap();
159            self.process_timer_ops(&mut timers);
160        }
161
162        // Notify that a timer has been inserted.
163        self.notify();
164
165        id
166    }
167
168    /// Deregisters a timer from the reactor.
169    pub(crate) fn remove_timer(&self, when: Instant, id: usize) {
170        // Push a remove operation.
171        while self.timer_ops.push(TimerOp::Remove(when, id)).is_err() {
172            // If the queue is full, drain it and try again.
173            let mut timers = self.timers.lock().unwrap();
174            self.process_timer_ops(&mut timers);
175        }
176    }
177
178    /// Notifies the thread blocked on the reactor.
179    pub(crate) fn notify(&self) {
180        self.poller.notify().expect("failed to notify reactor");
181    }
182
183    /// Locks the reactor, potentially blocking if the lock is held by another thread.
184    pub(crate) fn lock(&self) -> ReactorLock<'_> {
185        let reactor = self;
186        let events = self.events.lock().unwrap();
187        ReactorLock { reactor, events }
188    }
189
190    /// Attempts to lock the reactor.
191    pub(crate) fn try_lock(&self) -> Option<ReactorLock<'_>> {
192        self.events.try_lock().ok().map(|events| {
193            let reactor = self;
194            ReactorLock { reactor, events }
195        })
196    }
197
198    /// Processes ready timers and extends the list of wakers to wake.
199    ///
200    /// Returns the duration until the next timer before this method was called.
201    fn process_timers(&self, wakers: &mut Vec<Waker>) -> Option<Duration> {
202        #[cfg(feature = "tracing")]
203        let span = tracing::trace_span!("process_timers");
204        #[cfg(feature = "tracing")]
205        let _enter = span.enter();
206
207        let mut timers = self.timers.lock().unwrap();
208        self.process_timer_ops(&mut timers);
209
210        let now = Instant::now();
211
212        // Split timers into ready and pending timers.
213        //
214        // Careful to split just *after* `now`, so that a timer set for exactly `now` is considered
215        // ready.
216        let pending = timers.split_off(&(now + Duration::from_nanos(1), 0));
217        let ready = mem::replace(&mut *timers, pending);
218
219        // Calculate the duration until the next event.
220        let dur = if ready.is_empty() {
221            // Duration until the next timer.
222            timers
223                .keys()
224                .next()
225                .map(|(when, _)| when.saturating_duration_since(now))
226        } else {
227            // Timers are about to fire right now.
228            Some(Duration::from_secs(0))
229        };
230
231        // Drop the lock before waking.
232        drop(timers);
233
234        // Add wakers to the list.
235        #[cfg(feature = "tracing")]
236        tracing::trace!("{} ready wakers", ready.len());
237
238        for (_, waker) in ready {
239            wakers.push(waker);
240        }
241
242        dur
243    }
244
245    /// Processes queued timer operations.
246    fn process_timer_ops(&self, timers: &mut MutexGuard<'_, BTreeMap<(Instant, usize), Waker>>) {
247        // Process only as much as fits into the queue, or else this loop could in theory run
248        // forever.
249        self.timer_ops
250            .try_iter()
251            .take(self.timer_ops.capacity().unwrap())
252            .for_each(|op| match op {
253                TimerOp::Insert(when, id, waker) => {
254                    timers.insert((when, id), waker);
255                }
256                TimerOp::Remove(when, id) => {
257                    timers.remove(&(when, id));
258                }
259            });
260    }
261}
262
263/// A lock on the reactor.
264pub(crate) struct ReactorLock<'a> {
265    reactor: &'a Reactor,
266    events: MutexGuard<'a, Events>,
267}
268
269impl ReactorLock<'_> {
270    /// Processes new events, blocking until the first event or the timeout.
271    pub(crate) fn react(&mut self, timeout: Option<Duration>) -> io::Result<()> {
272        #[cfg(feature = "tracing")]
273        let span = tracing::trace_span!("react");
274        #[cfg(feature = "tracing")]
275        let _enter = span.enter();
276
277        let mut wakers = Vec::new();
278
279        // Process ready timers.
280        let next_timer = self.reactor.process_timers(&mut wakers);
281
282        // compute the timeout for blocking on I/O events.
283        let timeout = match (next_timer, timeout) {
284            (None, None) => None,
285            (Some(t), None) | (None, Some(t)) => Some(t),
286            (Some(a), Some(b)) => Some(a.min(b)),
287        };
288
289        // Bump the ticker before polling I/O.
290        let tick = self
291            .reactor
292            .ticker
293            .fetch_add(1, Ordering::SeqCst)
294            .wrapping_add(1);
295
296        self.events.clear();
297
298        // Block on I/O events.
299        let res = match self.reactor.poller.wait(&mut self.events, timeout) {
300            // No I/O events occurred.
301            Ok(0) => {
302                if timeout != Some(Duration::from_secs(0)) {
303                    // The non-zero timeout was hit so fire ready timers.
304                    self.reactor.process_timers(&mut wakers);
305                }
306                Ok(())
307            }
308
309            // At least one I/O event occurred.
310            Ok(_) => {
311                // Iterate over sources in the event list.
312                let sources = self.reactor.sources.lock().unwrap();
313
314                for ev in self.events.iter() {
315                    // Check if there is a source in the table with this key.
316                    if let Some(source) = sources.get(ev.key) {
317                        let mut state = source.state.lock().unwrap();
318
319                        // Collect wakers if any event was emitted.
320                        for &(dir, emitted) in &[(WRITE, ev.writable), (READ, ev.readable)] {
321                            if emitted {
322                                state[dir].tick = tick;
323                                state[dir].drain_into(&mut wakers);
324                            }
325                        }
326
327                        // Re-register if there are still writers or readers. This can happen if
328                        // e.g. we were previously interested in both readability and writability,
329                        // but only one of them was emitted.
330                        if !state[READ].is_empty() || !state[WRITE].is_empty() {
331                            // Create the event that we are interested in.
332                            let event = {
333                                let mut event = Event::none(source.key);
334                                event.readable = !state[READ].is_empty();
335                                event.writable = !state[WRITE].is_empty();
336                                event
337                            };
338
339                            // Register interest in this event.
340                            source.registration.modify(&self.reactor.poller, event)?;
341                        }
342                    }
343                }
344
345                Ok(())
346            }
347
348            // The syscall was interrupted.
349            Err(err) if err.kind() == io::ErrorKind::Interrupted => Ok(()),
350
351            // An actual error occureed.
352            Err(err) => Err(err),
353        };
354
355        // Wake up ready tasks.
356        #[cfg(feature = "tracing")]
357        tracing::trace!("{} ready wakers", wakers.len());
358        for waker in wakers {
359            // Don't let a panicking waker blow everything up.
360            panic::catch_unwind(|| waker.wake()).ok();
361        }
362
363        res
364    }
365}
366
367/// A single timer operation.
368enum TimerOp {
369    Insert(Instant, usize, Waker),
370    Remove(Instant, usize),
371}
372
373/// A registered source of I/O events.
374#[derive(Debug)]
375pub(crate) struct Source {
376    /// This source's registration into the reactor.
377    registration: Registration,
378
379    /// The key of this source obtained during registration.
380    key: usize,
381
382    /// Inner state with registered wakers.
383    state: Mutex<[Direction; 2]>,
384}
385
386/// A read or write direction.
387#[derive(Debug, Default)]
388struct Direction {
389    /// Last reactor tick that delivered an event.
390    tick: usize,
391
392    /// Ticks remembered by `Async::poll_readable()` or `Async::poll_writable()`.
393    ticks: Option<(usize, usize)>,
394
395    /// Waker stored by `Async::poll_readable()` or `Async::poll_writable()`.
396    waker: Option<Waker>,
397
398    /// Wakers of tasks waiting for the next event.
399    ///
400    /// Registered by `Async::readable()` and `Async::writable()`.
401    wakers: Slab<Option<Waker>>,
402}
403
404impl Direction {
405    /// Returns `true` if there are no wakers interested in this direction.
406    fn is_empty(&self) -> bool {
407        self.waker.is_none() && self.wakers.iter().all(|(_, opt)| opt.is_none())
408    }
409
410    /// Moves all wakers into a `Vec`.
411    fn drain_into(&mut self, dst: &mut Vec<Waker>) {
412        if let Some(w) = self.waker.take() {
413            dst.push(w);
414        }
415        for (_, opt) in self.wakers.iter_mut() {
416            if let Some(w) = opt.take() {
417                dst.push(w);
418            }
419        }
420    }
421}
422
423impl Source {
424    /// Polls the I/O source for readability.
425    pub(crate) fn poll_readable(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
426        self.poll_ready(READ, cx)
427    }
428
429    /// Polls the I/O source for writability.
430    pub(crate) fn poll_writable(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
431        self.poll_ready(WRITE, cx)
432    }
433
434    /// Registers a waker from `poll_readable()` or `poll_writable()`.
435    ///
436    /// If a different waker is already registered, it gets replaced and woken.
437    fn poll_ready(&self, dir: usize, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
438        let mut displaced = None;
439        let result = {
440            let mut state = self.state.lock().unwrap();
441
442            // Check if the reactor has delivered an event.
443            if let Some((a, b)) = state[dir].ticks {
444                if state[dir].tick != a && state[dir].tick != b {
445                    state[dir].ticks = None;
446                    return Poll::Ready(Ok(()));
447                }
448            }
449
450            let was_empty = state[dir].is_empty();
451
452            // Register the current task's waker.
453            if let Some(w) = state[dir].waker.take() {
454                if w.will_wake(cx.waker()) {
455                    state[dir].waker = Some(w);
456                    return Poll::Pending;
457                }
458                displaced = Some(w);
459            }
460            state[dir].waker = Some(cx.waker().clone());
461            state[dir].ticks = Some((state[dir].tick, state[dir].tick));
462
463            // Update interest in this I/O handle.
464            if was_empty {
465                // Create the event that we are interested in.
466                let event = {
467                    let mut event = Event::none(self.key);
468                    event.readable = !state[READ].is_empty();
469                    event.writable = !state[WRITE].is_empty();
470                    event
471                };
472
473                // Register interest in it.
474                if let Err(err) = self.registration.modify(&Reactor::get().poller, event) {
475                    Poll::Ready(Err(err))
476                } else {
477                    Poll::Pending
478                }
479            } else {
480                Poll::Pending
481            }
482        };
483
484        if let Some(w) = displaced {
485            panic::catch_unwind(|| w.wake()).ok();
486        }
487        result
488    }
489
490    /// Waits until the I/O source is readable.
491    pub(crate) fn readable<T>(handle: &crate::Async<T>) -> Readable<'_, T> {
492        Readable(Self::ready(handle, READ))
493    }
494
495    /// Waits until the I/O source is readable.
496    pub(crate) fn readable_owned<T>(handle: Arc<crate::Async<T>>) -> ReadableOwned<T> {
497        ReadableOwned(Self::ready(handle, READ))
498    }
499
500    /// Waits until the I/O source is writable.
501    pub(crate) fn writable<T>(handle: &crate::Async<T>) -> Writable<'_, T> {
502        Writable(Self::ready(handle, WRITE))
503    }
504
505    /// Waits until the I/O source is writable.
506    pub(crate) fn writable_owned<T>(handle: Arc<crate::Async<T>>) -> WritableOwned<T> {
507        WritableOwned(Self::ready(handle, WRITE))
508    }
509
510    /// Waits until the I/O source is readable or writable.
511    fn ready<H: Borrow<crate::Async<T>> + Clone, T>(handle: H, dir: usize) -> Ready<H, T> {
512        Ready {
513            handle,
514            dir,
515            ticks: None,
516            index: None,
517            _capture: PhantomData,
518        }
519    }
520}
521
522/// Future for [`Async::readable`](crate::Async::readable).
523#[must_use = "futures do nothing unless you `.await` or poll them"]
524pub struct Readable<'a, T>(Ready<&'a crate::Async<T>, T>);
525
526impl<T> Future for Readable<'_, T> {
527    type Output = io::Result<()>;
528
529    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
530        ready!(Pin::new(&mut self.0).poll(cx))?;
531        #[cfg(feature = "tracing")]
532        tracing::trace!(fd = ?self.0.handle.source.registration, "readable");
533        Poll::Ready(Ok(()))
534    }
535}
536
537impl<T> fmt::Debug for Readable<'_, T> {
538    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539        f.debug_struct("Readable").finish()
540    }
541}
542
543/// Future for [`Async::readable_owned`](crate::Async::readable_owned).
544#[must_use = "futures do nothing unless you `.await` or poll them"]
545pub struct ReadableOwned<T>(Ready<Arc<crate::Async<T>>, T>);
546
547impl<T> Future for ReadableOwned<T> {
548    type Output = io::Result<()>;
549
550    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
551        ready!(Pin::new(&mut self.0).poll(cx))?;
552        #[cfg(feature = "tracing")]
553        tracing::trace!(fd = ?self.0.handle.source.registration, "readable_owned");
554        Poll::Ready(Ok(()))
555    }
556}
557
558impl<T> fmt::Debug for ReadableOwned<T> {
559    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
560        f.debug_struct("ReadableOwned").finish()
561    }
562}
563
564/// Future for [`Async::writable`](crate::Async::writable).
565#[must_use = "futures do nothing unless you `.await` or poll them"]
566pub struct Writable<'a, T>(Ready<&'a crate::Async<T>, T>);
567
568impl<T> Future for Writable<'_, T> {
569    type Output = io::Result<()>;
570
571    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
572        ready!(Pin::new(&mut self.0).poll(cx))?;
573        #[cfg(feature = "tracing")]
574        tracing::trace!(fd = ?self.0.handle.source.registration, "writable");
575        Poll::Ready(Ok(()))
576    }
577}
578
579impl<T> fmt::Debug for Writable<'_, T> {
580    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581        f.debug_struct("Writable").finish()
582    }
583}
584
585/// Future for [`Async::writable_owned`](crate::Async::writable_owned).
586#[must_use = "futures do nothing unless you `.await` or poll them"]
587pub struct WritableOwned<T>(Ready<Arc<crate::Async<T>>, T>);
588
589impl<T> Future for WritableOwned<T> {
590    type Output = io::Result<()>;
591
592    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
593        ready!(Pin::new(&mut self.0).poll(cx))?;
594        #[cfg(feature = "tracing")]
595        tracing::trace!(fd = ?self.0.handle.source.registration, "writable_owned");
596        Poll::Ready(Ok(()))
597    }
598}
599
600impl<T> fmt::Debug for WritableOwned<T> {
601    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
602        f.debug_struct("WritableOwned").finish()
603    }
604}
605
606struct Ready<H: Borrow<crate::Async<T>>, T> {
607    handle: H,
608    dir: usize,
609    ticks: Option<(usize, usize)>,
610    index: Option<usize>,
611    _capture: PhantomData<fn() -> T>,
612}
613
614impl<H: Borrow<crate::Async<T>>, T> Unpin for Ready<H, T> {}
615
616impl<H: Borrow<crate::Async<T>> + Clone, T> Future for Ready<H, T> {
617    type Output = io::Result<()>;
618
619    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
620        let Self {
621            ref handle,
622            dir,
623            ticks,
624            index,
625            ..
626        } = &mut *self;
627
628        let mut state = handle.borrow().source.state.lock().unwrap();
629
630        // Check if the reactor has delivered an event.
631        if let Some((a, b)) = *ticks {
632            if state[*dir].tick != a && state[*dir].tick != b {
633                return Poll::Ready(Ok(()));
634            }
635        }
636
637        let was_empty = state[*dir].is_empty();
638
639        // Register the current task's waker.
640        let i = match *index {
641            Some(i) => i,
642            None => {
643                let i = state[*dir].wakers.insert(None);
644                *index = Some(i);
645                *ticks = Some((state[*dir].tick, state[*dir].tick));
646                i
647            }
648        };
649        state[*dir].wakers[i] = Some(cx.waker().clone());
650
651        // Update interest in this I/O handle.
652        if was_empty {
653            // Create the event that we are interested in.
654            let event = {
655                let mut event = Event::none(handle.borrow().source.key);
656                event.readable = !state[READ].is_empty();
657                event.writable = !state[WRITE].is_empty();
658                event
659            };
660
661            // Indicate that we are interested in this event.
662            handle
663                .borrow()
664                .source
665                .registration
666                .modify(&Reactor::get().poller, event)?;
667        }
668
669        Poll::Pending
670    }
671}
672
673impl<H: Borrow<crate::Async<T>>, T> Drop for Ready<H, T> {
674    fn drop(&mut self) {
675        // Remove our waker when dropped.
676        if let Some(key) = self.index {
677            let mut state = self.handle.borrow().source.state.lock().unwrap();
678            let wakers = &mut state[self.dir].wakers;
679            if wakers.contains(key) {
680                wakers.remove(key);
681            }
682        }
683    }
684}