• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 std::pin::pin;
6 
7 use anyhow::Context;
8 use base::Event;
9 use cros_async::EventAsync;
10 use cros_async::Executor;
11 use futures::channel::oneshot;
12 use futures::select_biased;
13 use futures::FutureExt;
14 
15 use crate::virtio::async_utils;
16 use crate::virtio::vhost_user_frontend::handler::BackendReqHandler;
17 use crate::virtio::vhost_user_frontend::sys::run_backend_request_handler;
18 use crate::virtio::Interrupt;
19 use crate::virtio::VIRTIO_MSI_NO_VECTOR;
20 
21 pub struct Worker {
22     pub kill_evt: Event,
23     pub non_msix_evt: Event,
24     pub backend_req_handler: Option<BackendReqHandler>,
25 }
26 
27 impl Worker {
28     // Runs asynchronous tasks.
run(&mut self, ex: &Executor, interrupt: Interrupt) -> anyhow::Result<()>29     pub async fn run(&mut self, ex: &Executor, interrupt: Interrupt) -> anyhow::Result<()> {
30         let non_msix_evt = self
31             .non_msix_evt
32             .try_clone()
33             .expect("failed to clone non_msix_evt");
34         let mut handle_non_msix_evt =
35             pin!(handle_non_msix_evt(ex, non_msix_evt, interrupt.clone()).fuse());
36 
37         let mut resample = pin!(async_utils::handle_irq_resample(ex, interrupt).fuse());
38 
39         let kill_evt = self.kill_evt.try_clone().expect("failed to clone kill_evt");
40         let mut kill = pin!(async_utils::await_and_exit(ex, kill_evt).fuse());
41 
42         let (stop_tx, stop_rx) = oneshot::channel();
43         let mut req_handler = pin!(if let Some(backend_req_handler) =
44             self.backend_req_handler.as_mut()
45         {
46             run_backend_request_handler(ex, backend_req_handler, stop_rx)
47                 .fuse()
48                 .left_future()
49         } else {
50             stop_rx.map(|_| Ok(())).right_future()
51         }
52         .fuse());
53 
54         select_biased! {
55             r = kill => {
56                 r.context("failed to wait on the kill event")?;
57                 // Stop req_handler cooperatively.
58                 let _ = stop_tx.send(());
59                 req_handler.await.context("backend request failure on stop")?;
60             }
61             r = handle_non_msix_evt => r.context("non msix event failure")?,
62             r = resample => r.context("failed to resample a irq value")?,
63             r = req_handler => r.context("backend request failure")?,
64         }
65 
66         Ok(())
67     }
68 }
69 
70 // The vhost-user protocol allows the backend to signal events, but for non-MSI-X devices,
71 // a device must also update the interrupt status mask. `handle_non_msix_evt` proxies events
72 // from the vhost-user backend to update the status mask.
handle_non_msix_evt( ex: &Executor, non_msix_evt: Event, interrupt: Interrupt, ) -> anyhow::Result<()>73 async fn handle_non_msix_evt(
74     ex: &Executor,
75     non_msix_evt: Event,
76     interrupt: Interrupt,
77 ) -> anyhow::Result<()> {
78     let event_async =
79         EventAsync::new(non_msix_evt, ex).expect("failed to create async non_msix_evt");
80     loop {
81         let _ = event_async.next_val().await;
82         // The parameter vector of signal_used_queue is used only when msix is enabled.
83         interrupt.signal_used_queue(VIRTIO_MSI_NO_VECTOR);
84     }
85 }
86