vmi_core/handler/mod.rs
1mod termination;
2
3use std::{
4 ops::ControlFlow,
5 sync::{Arc, atomic::AtomicBool},
6 time::{Duration, Instant},
7};
8
9pub use self::termination::VmiTerminationHandler;
10use crate::{VmiContext, VmiEventResponse, VmiOs, VmiSession};
11
12/// A trait for handling VMI events.
13///
14/// A factory that creates a handler implementing this trait is passed to
15/// the [`VmiSession::handle`] method to handle VMI events.
16///
17/// [`VmiSession::handle`]: crate::VmiSession::handle
18pub trait VmiHandler<Os>
19where
20 Os: VmiOs,
21{
22 /// The output type of the handler.
23 type Output;
24
25 /// Called for each VMI event.
26 ///
27 /// The returned [`VmiEventResponse`] tells the hypervisor how to resume
28 /// the vCPU that triggered the event.
29 fn handle_event(&mut self, event: VmiContext<Os>) -> VmiEventResponse<Os::Architecture>;
30
31 /// Called when the event loop times out waiting for the next event.
32 ///
33 /// This is useful for periodic housekeeping while the guest is idle.
34 fn handle_timeout(&mut self, _session: &VmiSession<Os>) {}
35
36 /// Called when the event loop is interrupted by a signal.
37 ///
38 /// Typically used to initiate a graceful shutdown. If the handler can be
39 /// torn down now, this method should return [`ControlFlow::Break`].
40 /// Otherwise, for example while a hijacked thread still runs injected
41 /// code, it should return [`ControlFlow::Continue`]. The event loop then
42 /// keeps handling events until [`poll`](Self::poll) returns `Some`, or
43 /// until a second signal arrives.
44 fn handle_interrupted(&mut self, _session: &VmiSession<Os>) -> ControlFlow<()> {
45 ControlFlow::Break(())
46 }
47
48 /// Called once before the session tears down monitoring.
49 ///
50 /// This gives the handler an opportunity to release resources that
51 /// depend on the session (views, memory access permissions, event
52 /// monitors) before the session calls [`reset_state`].
53 ///
54 /// # Notes
55 ///
56 /// The guest is paused while this method runs. Do not wait here for the
57 /// guest to do something, because it cannot run until the cleanup is
58 /// done.
59 ///
60 /// [`reset_state`]: crate::VmiCore::reset_state
61 fn cleanup(&mut self, _session: &VmiSession<Os>) {}
62
63 /// Checks if the handler has completed.
64 ///
65 /// This method is called after each event is handled. If the handler
66 /// has completed, this method should return the output of the handler.
67 /// Otherwise, it should return `None`.
68 fn poll(&mut self) -> Option<Self::Output> {
69 None
70 }
71}
72
73/// Extension methods on [`VmiHandler`].
74///
75/// The blanket impl is the only impl of this trait, so implementors of
76/// [`VmiHandler`] cannot override the default bodies.
77pub trait VmiHandlerExt<Os>: VmiHandler<Os> + Sized
78where
79 Os: VmiOs,
80{
81 /// Wraps the handler in a [`VmiTerminationHandler`] that interrupts it
82 /// at `deadline`.
83 fn with_deadline(self, deadline: Instant) -> VmiTerminationHandler<Self> {
84 VmiTerminationHandler::new(self).with_deadline(deadline)
85 }
86
87 /// Wraps the handler in a [`VmiTerminationHandler`] with a flag that
88 /// interrupts it once the flag becomes `true`.
89 fn with_termination_flag(
90 self,
91 termination_flag: Arc<AtomicBool>,
92 ) -> VmiTerminationHandler<Self> {
93 VmiTerminationHandler::new(self).with_termination_flag(termination_flag)
94 }
95
96 /// Wraps the handler in a [`VmiTerminationHandler`] that gives it
97 /// `termination_timeout` to finish once interrupted.
98 fn with_termination_timeout(
99 self,
100 termination_timeout: Duration,
101 ) -> VmiTerminationHandler<Self> {
102 VmiTerminationHandler::new(self).with_termination_timeout(termination_timeout)
103 }
104}
105
106impl<Os, Handler> VmiHandlerExt<Os> for Handler
107where
108 Os: VmiOs,
109 Handler: VmiHandler<Os>,
110{
111}