mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-22 12:35:19 +00:00
vhost_user_backend: Give access to the EpollVringHandler
By letting the consumer of this crate getting access to the vring handler, we will be able to let it perform several actions without producing a deadlock. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
cfc8c39446
commit
f14ab872ec
@ -105,7 +105,6 @@ pub struct VhostUserDaemon<S: VhostUserBackend> {
|
|||||||
name: String,
|
name: String,
|
||||||
sock_path: String,
|
sock_path: String,
|
||||||
handler: Arc<Mutex<VhostUserHandler<S>>>,
|
handler: Arc<Mutex<VhostUserHandler<S>>>,
|
||||||
vring_handler: Arc<RwLock<VringEpollHandler<S>>>,
|
|
||||||
main_thread: Option<thread::JoinHandle<Result<()>>>,
|
main_thread: Option<thread::JoinHandle<Result<()>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,13 +119,11 @@ impl<S: VhostUserBackend> VhostUserDaemon<S> {
|
|||||||
let handler = Arc::new(Mutex::new(
|
let handler = Arc::new(Mutex::new(
|
||||||
VhostUserHandler::new(backend).map_err(Error::NewVhostUserHandler)?,
|
VhostUserHandler::new(backend).map_err(Error::NewVhostUserHandler)?,
|
||||||
));
|
));
|
||||||
let vring_handler = handler.lock().unwrap().get_vring_handler();
|
|
||||||
|
|
||||||
Ok(VhostUserDaemon {
|
Ok(VhostUserDaemon {
|
||||||
name,
|
name,
|
||||||
sock_path,
|
sock_path,
|
||||||
handler,
|
handler,
|
||||||
vring_handler,
|
|
||||||
main_thread: None,
|
main_thread: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -166,47 +163,11 @@ impl<S: VhostUserBackend> VhostUserDaemon<S> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a custom event only meaningful to the caller. When this event
|
/// Retrieve the vring handler. This is necessary to perform further
|
||||||
/// is later triggered, and because only the caller knows what to do about
|
/// actions like registering and unregistering some extra event file
|
||||||
/// it, the backend implementation of `handle_event` will be called.
|
/// descriptors, as well as forcing some vring to be processed.
|
||||||
/// This lets entire control to the caller about what needs to be done for
|
pub fn get_vring_handler(&self) -> Arc<RwLock<VringEpollHandler<S>>> {
|
||||||
/// this special event, without forcing it to run its own dedicated epoll
|
self.handler.lock().unwrap().get_vring_handler()
|
||||||
/// loop for it.
|
|
||||||
pub fn register_listener(&self, fd: RawFd, ev_type: epoll::Events, data: u64) -> Result<()> {
|
|
||||||
self.vring_handler
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.register_listener(fd, ev_type, data)
|
|
||||||
.map_err(Error::RegisterListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unregister a custom event. If the custom event is triggered after this
|
|
||||||
/// function has been called, nothing will happen as it will be removed
|
|
||||||
/// from the list of file descriptors the epoll loop is listening to.
|
|
||||||
pub fn unregister_listener(&self, fd: RawFd, ev_type: epoll::Events, data: u64) -> Result<()> {
|
|
||||||
self.vring_handler
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.unregister_listener(fd, ev_type, data)
|
|
||||||
.map_err(Error::RegisterListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trigger the processing of a virtqueue. This function is meant to be
|
|
||||||
/// used by the caller whenever it might need some available queues to
|
|
||||||
/// send data back to the guest.
|
|
||||||
/// A concrete example is a backend registering one extra listener for
|
|
||||||
/// data that needs to be sent to the guest. When the associated event
|
|
||||||
/// is triggered, the backend will be invoked through its `handle_event`
|
|
||||||
/// implementation. And in this case, the way to handle the event is to
|
|
||||||
/// call into `process_queue` to let it invoke the backend implementation
|
|
||||||
/// of `process_queue`. With this twisted trick, all common parts related
|
|
||||||
/// to the virtqueues can remain part of the library.
|
|
||||||
pub fn process_queue(&self, q_idx: u16) -> Result<()> {
|
|
||||||
self.vring_handler
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.process_queue(q_idx)
|
|
||||||
.map_err(Error::ProcessQueue)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +247,7 @@ impl error::Error for VringEpollHandlerError {}
|
|||||||
/// Result of vring epoll handler operations.
|
/// Result of vring epoll handler operations.
|
||||||
type VringEpollHandlerResult<T> = std::result::Result<T, VringEpollHandlerError>;
|
type VringEpollHandlerResult<T> = std::result::Result<T, VringEpollHandlerError>;
|
||||||
|
|
||||||
struct VringEpollHandler<S: VhostUserBackend> {
|
pub struct VringEpollHandler<S: VhostUserBackend> {
|
||||||
backend: Arc<RwLock<S>>,
|
backend: Arc<RwLock<S>>,
|
||||||
vrings: Vec<Arc<RwLock<Vring>>>,
|
vrings: Vec<Arc<RwLock<Vring>>>,
|
||||||
mem: Option<GuestMemoryMmap>,
|
mem: Option<GuestMemoryMmap>,
|
||||||
@ -298,7 +259,17 @@ impl<S: VhostUserBackend> VringEpollHandler<S> {
|
|||||||
self.mem = mem;
|
self.mem = mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_queue(&mut self, q_idx: u16) -> VringEpollHandlerResult<()> {
|
/// Trigger the processing of a virtqueue. This function is meant to be
|
||||||
|
/// used by the caller whenever it might need some available queues to
|
||||||
|
/// send data back to the guest.
|
||||||
|
/// A concrete example is a backend registering one extra listener for
|
||||||
|
/// data that needs to be sent to the guest. When the associated event
|
||||||
|
/// is triggered, the backend will be invoked through its `handle_event`
|
||||||
|
/// implementation. And in this case, the way to handle the event is to
|
||||||
|
/// call into `process_queue` to let it invoke the backend implementation
|
||||||
|
/// of `process_queue`. With this twisted trick, all common parts related
|
||||||
|
/// to the virtqueues can remain part of the library.
|
||||||
|
pub fn process_queue(&mut self, q_idx: u16) -> VringEpollHandlerResult<()> {
|
||||||
let vring = &mut self.vrings[q_idx as usize].write().unwrap();
|
let vring = &mut self.vrings[q_idx as usize].write().unwrap();
|
||||||
let mut used_desc_heads = vec![(0, 0); vring.queue.size as usize];
|
let mut used_desc_heads = vec![(0, 0); vring.queue.size as usize];
|
||||||
let mut used_count = 0;
|
let mut used_count = 0;
|
||||||
@ -379,7 +350,13 @@ impl<S: VhostUserBackend> VringEpollHandler<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_listener(
|
/// Register a custom event only meaningful to the caller. When this event
|
||||||
|
/// is later triggered, and because only the caller knows what to do about
|
||||||
|
/// it, the backend implementation of `handle_event` will be called.
|
||||||
|
/// This lets entire control to the caller about what needs to be done for
|
||||||
|
/// this special event, without forcing it to run its own dedicated epoll
|
||||||
|
/// loop for it.
|
||||||
|
pub fn register_listener(
|
||||||
&self,
|
&self,
|
||||||
fd: RawFd,
|
fd: RawFd,
|
||||||
ev_type: epoll::Events,
|
ev_type: epoll::Events,
|
||||||
@ -393,7 +370,10 @@ impl<S: VhostUserBackend> VringEpollHandler<S> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unregister_listener(
|
/// Unregister a custom event. If the custom event is triggered after this
|
||||||
|
/// function has been called, nothing will happen as it will be removed
|
||||||
|
/// from the list of file descriptors the epoll loop is listening to.
|
||||||
|
pub fn unregister_listener(
|
||||||
&self,
|
&self,
|
||||||
fd: RawFd,
|
fd: RawFd,
|
||||||
ev_type: epoll::Events,
|
ev_type: epoll::Events,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user