1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use anyhow::Context;
6 use anyhow::Result;
7 use base::info;
8 use base::CloseNotifier;
9 use base::ReadNotifier;
10 use base::SafeDescriptor;
11 use base::Tube;
12 use cros_async::EventAsync;
13 use cros_async::Executor;
14 use futures::channel::oneshot;
15 use futures::pin_mut;
16 use futures::select_biased;
17 use futures::FutureExt;
18 use vmm_vhost::message::VhostUserProtocolFeatures;
19
20 use crate::virtio::vhost_user_frontend::handler::BackendReqHandler;
21 use crate::virtio::vhost_user_frontend::handler::BackendReqHandlerImpl;
22 use crate::virtio::vhost_user_frontend::Error;
23 use crate::virtio::vhost_user_frontend::Result as VhostResult;
24
create_backend_req_handler( h: BackendReqHandlerImpl, backend_pid: Option<u32>, ) -> VhostResult<(BackendReqHandler, SafeDescriptor)>25 pub fn create_backend_req_handler(
26 h: BackendReqHandlerImpl,
27 backend_pid: Option<u32>,
28 ) -> VhostResult<(BackendReqHandler, SafeDescriptor)> {
29 let backend_pid = backend_pid.expect("tube needs target pid for backend requests");
30 vmm_vhost::FrontendServer::with_tube(h, backend_pid).map_err(Error::CreateBackendReqHandler)
31 }
32
33 /// Process requests from the backend.
34 ///
35 /// If `stop_rx` is sent a value, the function will exit at a well defined point so that
36 /// `run_backend_request_handler` can be re-invoked to resume processing the connection.
run_backend_request_handler( ex: &Executor, handler: &mut BackendReqHandler, mut stop_rx: oneshot::Receiver<()>, ) -> Result<()>37 pub async fn run_backend_request_handler(
38 ex: &Executor,
39 handler: &mut BackendReqHandler,
40 mut stop_rx: oneshot::Receiver<()>,
41 ) -> Result<()> {
42 let read_notifier = handler.get_read_notifier();
43 let close_notifier = handler.get_close_notifier();
44
45 let read_event = EventAsync::clone_raw_without_reset(read_notifier, ex)
46 .context("failed to create an async event")?;
47 let close_event = EventAsync::clone_raw_without_reset(close_notifier, ex)
48 .context("failed to create an async event")?;
49
50 let read_event_fut = read_event.next_val().fuse();
51 let close_event_fut = close_event.next_val().fuse();
52 pin_mut!(read_event_fut);
53 pin_mut!(close_event_fut);
54
55 loop {
56 select_biased! {
57 _ = stop_rx => return Ok(()),
58 _read_res = read_event_fut => {
59 handler
60 .handle_request()
61 .context("failed to handle a vhost-user request")?;
62 read_event_fut.set(read_event.next_val().fuse());
63 }
64 // Tube closed event.
65 _close_res = close_event_fut => {
66 info!("exit run loop: got close event");
67 return Ok(())
68 }
69 }
70 }
71 }
72