Skip to main content

dope_runtime/
launcher.rs

1use std::io;
2use std::sync::Arc;
3use std::sync::atomic::AtomicBool;
4
5use crate::runtime::{Manifold, Runtime};
6use crate::sys::Process;
7
8#[derive(Clone, Debug)]
9pub struct LaunchCtx {
10    pub cpu: u16,
11    pub shutdown: Option<Arc<AtomicBool>>,
12}
13
14pub struct Launcher<F> {
15    pub cpus: Vec<u16>,
16    pub shutdown: Option<Arc<AtomicBool>>,
17    pub build: F,
18}
19
20impl<F> Launcher<F> {
21    pub fn new(cpus: Vec<u16>, build: F) -> Self {
22        Self {
23            cpus,
24            shutdown: None,
25            build,
26        }
27    }
28
29    pub fn with_shutdown(mut self, shutdown: Arc<AtomicBool>) -> Self {
30        self.shutdown = Some(shutdown);
31        self
32    }
33
34    pub fn run<R>(self) -> io::Result<()>
35    where
36        F: Fn(LaunchCtx) -> io::Result<Runtime<R>> + Send + Sync,
37        R: Manifold,
38    {
39        let Self {
40            cpus,
41            shutdown,
42            build,
43        } = self;
44        let (last, rest) = cpus
45            .split_last()
46            .expect("Launcher::run requires at least one cpu");
47
48        Process::ignore_sigpipe();
49        let build_ref = &build;
50        std::thread::scope(|s| -> io::Result<()> {
51            let mut handles = Vec::with_capacity(rest.len());
52            for &cpu in rest {
53                let ctx = LaunchCtx {
54                    cpu,
55                    shutdown: shutdown.clone(),
56                };
57                let handle = s.spawn(move || -> io::Result<()> {
58                    setup_worker(ctx.cpu)?;
59                    let bundle = build_ref(ctx)?;
60                    bundle.run_forever()
61                });
62                handles.push(handle);
63            }
64            let leader_ctx = LaunchCtx {
65                cpu: *last,
66                shutdown: shutdown.clone(),
67            };
68            setup_worker(leader_ctx.cpu)?;
69            let leader_bundle = build_ref(leader_ctx)?;
70            let leader_result = leader_bundle.run_forever();
71            for h in handles {
72                h.join()
73                    .map_err(|_| io::Error::other("launcher worker panicked"))??;
74            }
75            leader_result
76        })
77    }
78}
79
80fn setup_worker(_cpu: u16) -> io::Result<()> {
81    Process::lock_memory();
82    Ok(())
83}