dope-core 0.15.0

The manifold runtime
Documentation
use std::{ops, process};

use crate::{
    backend::{
        self, fixed,
        uring::{
            self,
            engine::{completions, tuning},
            ring,
        },
    },
    driver::{
        self, flight,
        ops::{poll, reactors},
        schedule,
    },
    io,
};

impl<'d> poll::Source<'d> for driver::Context<'_, 'd> {
    fn dispatch(
        &mut self,
        work: schedule::Reactor<'_, 'd>,
        mut dispatch: impl FnMut(io::Event<'d>, &mut Self) -> ops::ControlFlow<io::Event<'d>>,
    ) -> poll::Dispatch<'d> {
        let work = reactors::Backend::prepare(self, work);
        let total = work.remaining();
        let cursor = self.backend().next_reactor_cursor();
        let maintenance_limit = reactors::Fair::share::<{ super::REACTOR_LANES }>(total, 0, cursor);
        let maintenance = {
            let mut budget = work.budget::<super::Maintenance>(maintenance_limit);
            super::maintain(self, &mut budget)
        };

        let source = ring::Drain::begin(&mut self.backend().ring);
        let mut retained = None;
        {
            let limit = work.remaining();
            let mut budget = work.budget::<super::Completion>(limit);
            while let schedule::Admission::Item(item) = budget.admit_with(|| {
                source
                    .next(&mut self.backend().ring)
                    .map(completions::Cqe::new)
            }) {
                let event = {
                    let (backend, drain) = self.backend_drain();
                    let backend::Uring {
                        ring,
                        tuning,
                        fixed_slots,
                        ..
                    } = backend;
                    resolve_event(ring.buffers().provided(), tuning, fixed_slots, &drain, item)
                };
                let Some(event) = event else {
                    continue;
                };
                match dispatch(event, self) {
                    ops::ControlFlow::Continue(()) => {}
                    ops::ControlFlow::Break(event) => {
                        retained = Some(event);
                        break;
                    }
                }
            }
        }
        let source_pending = source.finish(&mut self.backend().ring);

        if maintenance == super::MaintenanceState::Pending && work.remaining() != 0 {
            let limit = work.remaining();
            let mut budget = work.budget::<super::Maintenance>(limit);
            let _ = super::maintain(self, &mut budget);
        }
        self.backend().ring.buffers().provided().flush();
        let drain = if source_pending || retained.is_some() {
            poll::Drain::Pending
        } else {
            poll::Drain::Drained
        };
        poll::Dispatch::new(drain, retained)
    }
}

fn resolve_event<'d>(
    provided: &mut uring::ffi::ProvidedRing,
    tuning: &mut tuning::Table,
    fixed_slots: &mut fixed::Slots,
    drain: &flight::Drain<'_, 'd>,
    item: completions::Cqe,
) -> Option<io::Event<'d>> {
    let driver = drain.driver();
    let disposition =
        completions::Resolver::new(provided, tuning, fixed_slots, drain).resolve(item);
    match disposition {
        completions::Disposition::Consumed(buffer) => {
            if let Some(buffer) = buffer {
                provided.defer(buffer);
            }
            None
        }
        completions::Disposition::Public(completion) => Some(io::Event::from_completion(
            completion,
            driver,
            |len, buffer| provided.region(buffer, buffer_len(len)),
        )),
        completions::Disposition::Closed(closed) => {
            if closed.result() < 0 || closed.work().retires_slot() {
                process::abort();
            }
            closed.settle(fixed_slots, driver);
            None
        }
    }
}

fn buffer_len(len: u32) -> usize {
    let Ok(len) = usize::try_from(len) else {
        process::abort();
    };
    len
}