misty_vm/
schedule.rs

1use std::{
2    convert::Infallible,
3    sync::{Arc, RwLock},
4};
5
6use crate::{
7    client::MistyClientHandle,
8    controllers::MistyControllerContext,
9    signals::{MistySignal, SignalEmitter},
10};
11
12pub(crate) struct ScheduleManager {
13    tasks: Arc<RwLock<Vec<ScheduledTask>>>,
14}
15
16pub(crate) struct ScheduledTask {
17    handler: Box<dyn FnOnce(MistyClientHandle) + Send + Sync>,
18}
19
20impl ScheduledTask {
21    fn new<E>(
22        handler: impl FnOnce(MistyClientHandle) -> Result<(), E> + Send + Sync + 'static,
23    ) -> Self
24    where
25        E: std::fmt::Display,
26    {
27        Self {
28            handler: Box::new(|handle| {
29                let err = handler(handle);
30                if let Err(err) = err {
31                    tracing::error!("schedule fail, error: {}", err);
32                }
33            }),
34        }
35    }
36
37    fn run(self, handle: MistyClientHandle) {
38        (self.handler)(handle);
39    }
40}
41
42impl ScheduleManager {
43    pub fn new() -> Self {
44        Self {
45            tasks: Default::default(),
46        }
47    }
48
49    pub fn enqueue<E>(
50        &self,
51        signal_emitter: &SignalEmitter,
52        handler: impl FnOnce(MistyClientHandle) -> Result<(), E> + Send + Sync + 'static,
53    ) where
54        E: std::fmt::Display,
55    {
56        {
57            let mut tasks = self.tasks.write().unwrap();
58            tasks.push(ScheduledTask::new(handler));
59        }
60        signal_emitter.emit(MistySignal::Schedule);
61    }
62
63    pub fn take_all_tasks(&self) -> Vec<ScheduledTask> {
64        let mut current_tasks = vec![];
65        {
66            let mut tasks = self.tasks.write().unwrap();
67            std::mem::swap::<Vec<ScheduledTask>>(&mut *tasks, current_tasks.as_mut());
68        }
69        current_tasks
70    }
71}
72
73pub(crate) fn controller_flush_scheduled_tasks(
74    ctx: MistyControllerContext,
75    _arg: (),
76) -> Result<(), Infallible> {
77    let handle = ctx.handle();
78    let tasks = handle.inner.schedule_manager.take_all_tasks();
79
80    for task in tasks.into_iter() {
81        task.run(handle.clone());
82    }
83
84    Ok(())
85}