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