dope_runtime/process/lifecycle/
native.rs1use std::cell::Cell;
2
3use dope_core::platform::thread;
4use o3::alloc;
5
6use crate::process::STACK;
7
8#[derive(Debug)]
10pub enum Start {
11 Allocation(alloc::Error),
12 Thread(thread::Error),
13}
14
15pub trait Task: thread::Task + Sized {
17 fn with<R>(self, run: impl FnOnce() -> R) -> Result<(R, Self::Output), Start> {
18 scope(self, |join| (run(), join.finish()))
19 }
20}
21
22impl<T: thread::Task> Task for T {}
23
24pub struct Join<'scope, O>(&'scope dyn Fn() -> O);
25
26impl<O> Join<'_, O> {
27 pub fn finish(self) -> O {
28 self.0()
29 }
30}
31
32pub fn scope<T: thread::Task, R>(
34 task: T,
35 run: impl for<'scope> FnOnce(Join<'scope, T::Output>) -> R,
36) -> Result<R, Start> {
37 let mut group = thread::Builder::try_new(1).map_err(Start::Allocation)?;
38 group.try_push(task, ()).map_err(Start::Allocation)?;
39 group.scope(|mut workers| {
40 workers
41 .start(STACK)
42 .map_err(|(_, error)| Start::Thread(error))?;
43 let workers = Cell::new(Some(workers));
44 let join = || {
45 let Some(workers) = workers.take() else {
46 unreachable!("joined")
47 };
48 match workers.finish().next() {
49 Some(((), output)) => output,
50 None => unreachable!("worker"),
51 }
52 };
53 Ok(run(Join(&join)))
54 })
55}
56
57pub struct Entry<F>(pub F);
59
60impl<F: FnOnce() -> O + Send, O: Send> thread::Task for Entry<F> {
61 type Output = O;
62
63 fn run(self) -> O {
64 self.0()
65 }
66}