dope-core 0.15.1

The manifold runtime
Documentation
use std::{io, time};

use crate::{
    backend::kqueue::engine::event,
    driver::{
        self,
        ops::{poll, reactors},
        schedule,
    },
};

struct Work<'turn, 'd> {
    reactor: reactors::Backend<'turn, 'd>,
    completion_floor: usize,
}

impl<'turn, 'd> Work<'turn, 'd> {
    fn new(context: &mut driver::Context<'_, 'd>, work: schedule::Reactor<'turn, 'd>) -> Self {
        let reactor = reactors::Backend::prepare(context, work);
        let total = reactor.remaining();
        let cursor = context.backend().poll.next_reactor_cursor();
        let resume_limit = reactors::Fair::share::<{ super::REACTOR_LANES }>(total, 0, cursor);
        let completion_floor = reactors::Fair::share::<{ super::REACTOR_LANES }>(total, 2, cursor);
        let work = Self {
            reactor,
            completion_floor,
        };
        work.resume(context, resume_limit);
        work
    }

    fn wait(
        &self,
        context: &mut driver::Context<'_, '_>,
        timeout: Option<time::Duration>,
    ) -> io::Result<()> {
        let change_limit = context.backend().poll.changes.len().min(
            self.reactor
                .remaining()
                .saturating_sub(self.completion_floor),
        );
        {
            let changes = self.reactor.budget::<event::ChangeLane>(change_limit);
            let mut changes = event::Budget::new(changes);
            let completion_limit = self
                .reactor
                .remaining()
                .min(context.backend().pending.remaining_capacity());
            let completions = self
                .reactor
                .budget::<event::CompletionLane>(completion_limit);
            let mut completions = event::Budget::new(completions);
            context
                .backend()
                .wait(timeout, &mut changes, &mut completions)?;
        }
        self.resume(context, self.reactor.remaining());
        Ok(())
    }

    fn resume(&self, context: &mut driver::Context<'_, '_>, limit: usize) {
        let limit = limit.min(context.backend().pending.remaining_capacity());
        let budget = self.reactor.budget::<event::ResumeLane>(limit);
        let mut budget = event::Budget::new(budget);
        event::Dispatch::new(context.backend()).resume_pending_with(&mut budget);
    }
}

impl<'d> poll::Poll<'d> for driver::Context<'_, 'd> {
    fn commit(&mut self, work: schedule::Reactor<'_, 'd>) -> io::Result<poll::Commit> {
        let work = Work::new(self, work);
        if !self.backend().poll.changes.is_empty() {
            work.wait(self, Some(time::Duration::ZERO))?;
        }
        self.backend().poll.check()?;
        Ok(if self.backend().poll.changes.is_empty() {
            poll::Commit::Drained
        } else {
            poll::Commit::Pending
        })
    }

    fn wait(
        &mut self,
        work: schedule::Reactor<'_, 'd>,
        timeout: Option<time::Duration>,
    ) -> io::Result<()> {
        let work = Work::new(self, work);
        let deferred_maintenance = self.driver_ref().maintenance().has_deferred_maintenance();
        let has_ready = self.driver_ref().ready().has_ready();
        let backend = self.backend();
        let must_not_block = !backend.pending.is_empty()
            || deferred_maintenance
            || has_ready
            || (work.reactor.remaining() == 0 && backend.has_pending_resume());
        let timeout = if must_not_block {
            Some(time::Duration::ZERO)
        } else {
            timeout
        };
        work.wait(self, timeout)
    }
}