From f14ab872ec0e1ade36eabc33a818a44f870e1bec Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Mon, 23 Sep 2019 12:23:28 -0700 Subject: [PATCH] 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 --- vhost_user_backend/src/lib.rs | 76 +++++++++++++---------------------- 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/vhost_user_backend/src/lib.rs b/vhost_user_backend/src/lib.rs index 5b9a5c6c8..a5bae5cce 100644 --- a/vhost_user_backend/src/lib.rs +++ b/vhost_user_backend/src/lib.rs @@ -105,7 +105,6 @@ pub struct VhostUserDaemon { name: String, sock_path: String, handler: Arc>>, - vring_handler: Arc>>, main_thread: Option>>, } @@ -120,13 +119,11 @@ impl VhostUserDaemon { let handler = Arc::new(Mutex::new( VhostUserHandler::new(backend).map_err(Error::NewVhostUserHandler)?, )); - let vring_handler = handler.lock().unwrap().get_vring_handler(); Ok(VhostUserDaemon { name, sock_path, handler, - vring_handler, main_thread: None, }) } @@ -166,47 +163,11 @@ impl VhostUserDaemon { Ok(()) } - /// 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, 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) + /// Retrieve the vring handler. This is necessary to perform further + /// actions like registering and unregistering some extra event file + /// descriptors, as well as forcing some vring to be processed. + pub fn get_vring_handler(&self) -> Arc>> { + self.handler.lock().unwrap().get_vring_handler() } } @@ -286,7 +247,7 @@ impl error::Error for VringEpollHandlerError {} /// Result of vring epoll handler operations. type VringEpollHandlerResult = std::result::Result; -struct VringEpollHandler { +pub struct VringEpollHandler { backend: Arc>, vrings: Vec>>, mem: Option, @@ -298,7 +259,17 @@ impl VringEpollHandler { 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 mut used_desc_heads = vec![(0, 0); vring.queue.size as usize]; let mut used_count = 0; @@ -379,7 +350,13 @@ impl VringEpollHandler { } } - 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, fd: RawFd, ev_type: epoll::Events, @@ -393,7 +370,10 @@ impl VringEpollHandler { ) } - 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, fd: RawFd, ev_type: epoll::Events,