Skip to main content

vmbus_channel/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Vmbus channel offer support and related functionality.
5
6#![forbid(unsafe_code)]
7
8pub mod bus;
9pub mod channel;
10pub mod gpadl;
11pub mod gpadl_ring;
12pub mod offer;
13pub mod resources;
14pub mod simple;
15pub mod stream;
16
17pub use stream::TaggedStream;
18
19use std::sync::Arc;
20use std::sync::atomic::AtomicBool;
21use std::sync::atomic::Ordering;
22use std::task::Context;
23use std::task::Poll;
24use vmbus_ring::FlatRingMem;
25use vmbus_ring::IncomingRing;
26use vmbus_ring::OutgoingRing;
27use vmbus_ring::RingMem;
28use vmcore::slim_event::SlimEvent;
29
30/// An object to use to communicate notifications with the remote endpoint of a
31/// vmbus channel.
32///
33/// When dropped, this may (or may not) signal to the remote endpoint that the
34/// channel is being closed.
35pub trait SignalVmbusChannel: Send + Sync {
36    /// Signals the remote endpoint that there is work to do: either the
37    /// outgoing ring buffer has transitioned from empty to non-empty, or the
38    /// incoming ring buffer now has enough space for the remote endpoint's
39    /// pending send.
40    fn signal_remote(&self);
41
42    /// Poll the channel for a ring buffer signal or for being closed.
43    ///
44    /// If the remote endpoint has closed the channel, then this can return
45    /// [`ChannelClosed`].
46    fn poll_for_signal(&self, cx: &mut Context<'_>) -> Poll<Result<(), ChannelClosed>>;
47}
48
49/// Error returned from [`SignalVmbusChannel::poll_for_signal`] indicating the channel
50/// has been closed by the other endpoint.
51pub struct ChannelClosed;
52
53/// Creates a pair of connected channels. Useful for testing.
54pub fn connected_async_channels(
55    ring_size: usize,
56) -> (RawAsyncChannel<FlatRingMem>, RawAsyncChannel<FlatRingMem>) {
57    #[derive(Default)]
58    struct EventWithDoneInner {
59        event: SlimEvent,
60        done: AtomicBool,
61    }
62
63    struct SignalInProc {
64        local: Arc<EventWithDoneInner>,
65        remote: Arc<EventWithDoneInner>,
66        close_on_drop: bool,
67    }
68
69    impl SignalVmbusChannel for SignalInProc {
70        fn signal_remote(&self) {
71            self.remote.event.signal();
72        }
73
74        fn poll_for_signal(&self, cx: &mut Context<'_>) -> Poll<Result<(), ChannelClosed>> {
75            if self.local.done.load(Ordering::Relaxed) {
76                return Err(ChannelClosed).into();
77            }
78            self.local.event.poll_wait(cx).map(Ok)
79        }
80    }
81
82    impl Drop for SignalInProc {
83        fn drop(&mut self) {
84            if self.close_on_drop {
85                self.remote.done.store(true, Ordering::Relaxed);
86                self.remote.event.signal();
87            }
88        }
89    }
90
91    let host_notify = SignalInProc {
92        local: Default::default(),
93        remote: Default::default(),
94        close_on_drop: false,
95    };
96    let guest_notify = SignalInProc {
97        local: host_notify.remote.clone(),
98        remote: host_notify.local.clone(),
99        close_on_drop: true,
100    };
101    let (host_in_ring, guest_out_ring) = make_ring_pair(ring_size);
102    let (guest_in_ring, host_out_ring) = make_ring_pair(ring_size);
103
104    let host = RawAsyncChannel {
105        in_ring: host_in_ring,
106        out_ring: host_out_ring,
107        signal: Box::new(host_notify),
108    };
109    let guest = RawAsyncChannel {
110        in_ring: guest_in_ring,
111        out_ring: guest_out_ring,
112        signal: Box::new(guest_notify),
113    };
114    (host, guest)
115}
116
117fn make_ring_pair(size: usize) -> (IncomingRing<FlatRingMem>, OutgoingRing<FlatRingMem>) {
118    let flat_mem = FlatRingMem::new(size);
119    let ring1 = IncomingRing::new(flat_mem.clone()).unwrap();
120    let ring2 = OutgoingRing::new(flat_mem).unwrap();
121    (ring1, ring2)
122}
123
124/// The resources for a bidirectional vmbus channel.
125pub struct RawAsyncChannel<M: RingMem> {
126    /// The incoming ring buffer.
127    pub in_ring: IncomingRing<M>,
128    /// The outgoing ring buffer.
129    pub out_ring: OutgoingRing<M>,
130    /// The object to use to communicate notifications with the remote endpoint.
131    pub signal: Box<dyn SignalVmbusChannel>,
132}