vmbus_server/
event.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use pal_async::driver::SpawnDriver;
5use pal_async::task::Task;
6use pal_async::wait::PolledWait;
7use pal_event::Event;
8use std::io;
9use vmcore::interrupt::Interrupt;
10
11/// Represents an object that may or may not be backed by an OS event, and can also be signaled
12/// manually.
13pub trait OsEventBacked {
14    /// Gets the OS event associated with this object, if any.
15    fn os_event(&self) -> Option<&Event>;
16
17    /// Signals the object manually.
18    fn signal(&self);
19}
20
21impl OsEventBacked for Interrupt {
22    fn os_event(&self) -> Option<&Event> {
23        self.event()
24    }
25
26    fn signal(&self) {
27        self.deliver();
28    }
29}
30
31/// A wrapper around an object that does not natively have an OS event, but needs to be signaled
32/// using one.
33pub struct WrappedEvent {
34    _task: Task<()>,
35}
36
37impl WrappedEvent {
38    /// Creates an OS event, and a task that will signal the original object when the event is triggered.
39    fn new(
40        driver: &impl SpawnDriver,
41        original: impl OsEventBacked + Send + 'static,
42    ) -> io::Result<(Self, Event)> {
43        let event = Event::new();
44        let wait = PolledWait::new(driver, event.clone())?;
45        let task = driver.spawn("vmbus-event-wrapper", async move {
46            Self::run(wait, original).await;
47        });
48        Ok((Self { _task: task }, event))
49    }
50
51    async fn run(mut event: PolledWait<Event>, original: impl OsEventBacked) {
52        loop {
53            event.wait().await.expect("wait should not fail");
54            original.signal();
55        }
56    }
57}
58
59/// Represents an object that either has an OS event or is wrapped using one.
60pub enum MaybeWrappedEvent<T> {
61    Original(T),
62    Wrapped { event: Event, wrapper: WrappedEvent },
63}
64
65impl<T: OsEventBacked + Send + 'static> MaybeWrappedEvent<T> {
66    /// Creates a new `MaybeWrappedEvent`. If the original object has an OS event, it is used
67    /// directly. Otherwise, a new OS event is created that can be used to signal the original
68    /// object.
69    pub fn new(driver: &impl SpawnDriver, original: T) -> io::Result<Self> {
70        if original.os_event().is_some() {
71            Ok(Self::Original(original))
72        } else {
73            let (wrapper, event) = WrappedEvent::new(driver, original)?;
74            Ok(Self::Wrapped { event, wrapper })
75        }
76    }
77
78    /// Gets the OS event associated with this object. This can be either the original event or the
79    /// wrapped event.
80    pub fn event(&self) -> &Event {
81        match self {
82            Self::Original(original) => original.os_event().expect("event should be present"),
83            Self::Wrapped { event, .. } => event,
84        }
85    }
86
87    /// Extracts the `WrappedEvent`, if one was created.
88    pub fn into_wrapped(self) -> Option<WrappedEvent> {
89        match self {
90            Self::Original(_) => None,
91            Self::Wrapped { wrapper, .. } => Some(wrapper),
92        }
93    }
94}