dope-runtime 0.2.1

Thin io_uring adaptor with "Manifolds"
Documentation
use std::io;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;

use crate::runtime::{Manifold, Runtime};
use crate::sys::Process;

#[derive(Clone, Debug)]
pub struct LaunchCtx {
    pub cpu: u16,
    pub shutdown: Option<Arc<AtomicBool>>,
}

pub struct Launcher<F> {
    pub cpus: Vec<u16>,
    pub shutdown: Option<Arc<AtomicBool>>,
    pub build: F,
}

impl<F> Launcher<F> {
    pub fn new(cpus: Vec<u16>, build: F) -> Self {
        Self {
            cpus,
            shutdown: None,
            build,
        }
    }

    pub fn with_shutdown(mut self, shutdown: Arc<AtomicBool>) -> Self {
        self.shutdown = Some(shutdown);
        self
    }

    pub fn run<R>(self) -> io::Result<()>
    where
        F: Fn(LaunchCtx) -> io::Result<Runtime<R>> + Send + Sync,
        R: Manifold,
    {
        let Self {
            cpus,
            shutdown,
            build,
        } = self;
        let (last, rest) = cpus
            .split_last()
            .expect("Launcher::run requires at least one cpu");

        Process::ignore_sigpipe();
        let build_ref = &build;
        std::thread::scope(|s| -> io::Result<()> {
            let mut handles = Vec::with_capacity(rest.len());
            for &cpu in rest {
                let ctx = LaunchCtx {
                    cpu,
                    shutdown: shutdown.clone(),
                };
                let handle = s.spawn(move || -> io::Result<()> {
                    setup_worker(ctx.cpu)?;
                    let bundle = build_ref(ctx)?;
                    bundle.run_forever()
                });
                handles.push(handle);
            }
            let leader_ctx = LaunchCtx {
                cpu: *last,
                shutdown: shutdown.clone(),
            };
            setup_worker(leader_ctx.cpu)?;
            let leader_bundle = build_ref(leader_ctx)?;
            let leader_result = leader_bundle.run_forever();
            for h in handles {
                h.join()
                    .map_err(|_| io::Error::other("launcher worker panicked"))??;
            }
            leader_result
        })
    }
}

fn setup_worker(_cpu: u16) -> io::Result<()> {
    Process::lock_memory();
    Ok(())
}