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}