dope_runtime/process/runtime/
mod.rs1use std::convert;
2
3use dope_core::{platform::signal, random};
4use o3::mem::slot;
5
6use crate::{
7 process::{self, failure::execute, gate, layout, watch},
8 shutdown,
9};
10
11pub(in crate::process) mod bus;
12mod control;
13pub(in crate::process) mod worker;
14
15pub struct Runtime<I> {
22 pub(in crate::process) workers: layout::Set<I>,
23}
24
25impl<I> Runtime<I> {
26 pub fn run<'r, E, X>(
28 self,
29 storage: slot::Vacant<'r, signal::Receiver>,
30 entry: E,
31 ) -> Result<(), execute::Error<'r, convert::Infallible, X>>
32 where
33 I: Send,
34 E: for<'run> Fn(
35 I,
36 process::Context<'run>,
37 ) -> Result<shutdown::Requested<process::Shutdown<'run>>, X>
38 + Clone
39 + Send,
40 X: Send,
41 {
42 let entry = worker::Plain::new(entry);
43 let Self { workers } = self;
44 signal::Source::scope(storage, move |signal| {
45 run_waiting(workers, entry, control::Control::signal(signal))
46 })
47 .map_err(execute::Error::from)
48 }
49
50 pub fn run_watched<'r, N, E, X>(
52 self,
53 storage: slot::Vacant<'r, signal::Receiver>,
54 entry: E,
55 notify: N,
56 ) -> Result<(), execute::Error<'r, N::Error, X>>
57 where
58 I: Send,
59 N: watch::Notify,
60 E: for<'run> Fn(
61 I,
62 process::Context<'run>,
63 ) -> Result<shutdown::Requested<process::Shutdown<'run>>, X>
64 + Clone
65 + Send,
66 X: Send,
67 {
68 self.watch_inner(storage, worker::Plain::new(entry), notify)
69 }
70
71 pub fn watch_gated<'r, N, E, X>(
73 self,
74 storage: slot::Vacant<'r, signal::Receiver>,
75 entry: E,
76 notify: N,
77 ) -> Result<(), execute::Error<'r, N::Error, X>>
78 where
79 I: Send,
80 N: watch::Notify,
81 E: for<'run> Fn(
82 I,
83 process::Context<'run>,
84 gate::Closed<'run>,
85 ) -> Result<shutdown::Requested<process::Shutdown<'run>>, X>
86 + Clone
87 + Send,
88 X: Send,
89 {
90 self.watch_inner(storage, worker::Gated::new(entry), notify)
91 }
92
93 fn watch_inner<'r, N, E, X>(
94 self,
95 storage: slot::Vacant<'r, signal::Receiver>,
96 entry: E,
97 notify: N,
98 ) -> Result<(), execute::Error<'r, N::Error, X>>
99 where
100 I: Send,
101 N: watch::Notify,
102 E: worker::Entry<I, X>,
103 X: Send,
104 {
105 let Self { workers } = self;
106 signal::Source::scope(storage, move |signal| {
107 run_waiting_watched(workers, entry, notify, control::Control::signal(signal))
108 })
109 .map_err(execute::Error::from)
110 }
111}
112
113fn run_waiting<'r, I, E, X>(
114 workers: layout::Set<I>,
115 entry: worker::Plain<E>,
116 control: control::Control<'_>,
117) -> Result<(), execute::Error<'r, convert::Infallible, X>>
118where
119 I: Send,
120 worker::Plain<E>: worker::Entry<I, X>,
121 X: Send,
122{
123 let count = workers.len();
124 let seed = random::Seed::acquire().map_err(execute::Cause::Entropy)?;
125 worker::scope(workers, seed, entry, |running| {
126 let outcome = control.ready(count, &running);
127 let stopped = running.stop();
128 match outcome {
129 Ok(()) => stopped.clean(),
130 Err(error) => Err(stopped.fail(error)),
131 }
132 })
133}
134
135fn run_waiting_watched<'r, I, N, E, X>(
136 workers: layout::Set<I>,
137 entry: E,
138 notify: N,
139 control: control::Control<'_>,
140) -> Result<(), execute::Error<'r, N::Error, X>>
141where
142 I: Send,
143 N: watch::Notify,
144 E: worker::Entry<I, X>,
145 X: Send,
146{
147 let count = workers.len();
148 let seed = random::Seed::acquire().map_err(execute::Cause::Entropy)?;
149 worker::scope(workers, seed, entry, |running| {
150 let outcome = control.watch(count, notify, &running);
151 let stopped = running.stop();
152 let outcome = outcome.and_then(|clock| match clock {
153 Some(clock) => {
154 control::Finish::new(&stopped).map_or(Ok(()), |finish| finish.drain(count, clock))
155 }
156 None => Ok(()),
157 });
158 match outcome {
159 Ok(()) => stopped.clean(),
160 Err(error) => Err(stopped.fail(error)),
161 }
162 })
163}