mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 18:20:34 +00:00
devices: Add a trait for Interrupt
Having a trait for interrupts used by queue and the devices allows for a slightly different implementation to handle interrupting the guest when using vhost-user. Change devices to handle the resample event being optional as it is handled on the VMM side with vhost_user. Change-Id: I511d3db66a7986e7a2a8bce5f48285171dee3388 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2795284 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
parent
f860f50b8a
commit
4786cee521
18 changed files with 221 additions and 109 deletions
|
@ -19,8 +19,8 @@ use vm_control::{BalloonControlCommand, BalloonControlResult, BalloonStats};
|
|||
use vm_memory::{GuestAddress, GuestMemory};
|
||||
|
||||
use super::{
|
||||
copy_config, descriptor_utils, DescriptorChain, Interrupt, Queue, Reader, VirtioDevice,
|
||||
TYPE_BALLOON,
|
||||
copy_config, descriptor_utils, DescriptorChain, Interrupt, Queue, Reader, SignalableInterrupt,
|
||||
VirtioDevice, TYPE_BALLOON,
|
||||
};
|
||||
|
||||
#[sorted]
|
||||
|
@ -276,14 +276,20 @@ async fn handle_command_tube(
|
|||
// Async task that resamples the status of the interrupt when the guest sends a request by
|
||||
// signalling the resample event associated with the interrupt.
|
||||
async fn handle_irq_resample(ex: &Executor, interrupt: Rc<RefCell<Interrupt>>) {
|
||||
let resample_evt = interrupt
|
||||
.borrow_mut()
|
||||
.get_resample_evt()
|
||||
.try_clone()
|
||||
.unwrap();
|
||||
let resample_evt = EventAsync::new(resample_evt.0, ex).unwrap();
|
||||
while resample_evt.next_val().await.is_ok() {
|
||||
interrupt.borrow_mut().do_interrupt_resample();
|
||||
let resample_evt = if let Some(resample_evt) = interrupt.borrow_mut().get_resample_evt() {
|
||||
let resample_evt = resample_evt.try_clone().unwrap();
|
||||
let resample_evt = EventAsync::new(resample_evt.0, ex).unwrap();
|
||||
Some(resample_evt)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(resample_evt) = resample_evt {
|
||||
while resample_evt.next_val().await.is_ok() {
|
||||
interrupt.borrow_mut().do_interrupt_resample();
|
||||
}
|
||||
} else {
|
||||
// no resample event, park the future.
|
||||
let () = futures::future::pending().await;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ use vm_control::{DiskControlCommand, DiskControlResult};
|
|||
use vm_memory::GuestMemory;
|
||||
|
||||
use super::{
|
||||
copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer,
|
||||
TYPE_BLOCK,
|
||||
copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt,
|
||||
VirtioDevice, Writer, TYPE_BLOCK,
|
||||
};
|
||||
|
||||
const QUEUE_SIZE: u16 = 256;
|
||||
|
@ -397,9 +397,14 @@ impl Worker {
|
|||
let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
|
||||
(&flush_timer, Token::FlushTimer),
|
||||
(&queue_evt, Token::QueueAvailable),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
(&kill_evt, Token::Kill),
|
||||
])
|
||||
.and_then(|wc| {
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
wc.add(resample_evt, Token::InterruptResample)?;
|
||||
}
|
||||
Ok(wc)
|
||||
})
|
||||
.and_then(|pc| {
|
||||
if let Some(control_tube) = self.control_tube.as_ref() {
|
||||
pc.add(control_tube, Token::ControlRequest)?
|
||||
|
|
|
@ -33,8 +33,8 @@ use vm_control::{DiskControlCommand, DiskControlResult};
|
|||
use vm_memory::GuestMemory;
|
||||
|
||||
use super::{
|
||||
copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer,
|
||||
TYPE_BLOCK,
|
||||
copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt,
|
||||
VirtioDevice, Writer, TYPE_BLOCK,
|
||||
};
|
||||
|
||||
const QUEUE_SIZE: u16 = 256;
|
||||
|
@ -306,7 +306,7 @@ async fn process_one_request_task(
|
|||
|
||||
let mut queue = queue.borrow_mut();
|
||||
queue.add_used(&mem, descriptor_index, len as u32);
|
||||
queue.trigger_interrupt(&mem, &interrupt.borrow());
|
||||
queue.trigger_interrupt(&mem, &*interrupt.borrow());
|
||||
queue.update_int_required(&mem);
|
||||
}
|
||||
|
||||
|
@ -347,19 +347,28 @@ async fn handle_irq_resample(
|
|||
ex: &Executor,
|
||||
interrupt: Rc<RefCell<Interrupt>>,
|
||||
) -> result::Result<(), OtherError> {
|
||||
let resample_evt = interrupt
|
||||
.borrow_mut()
|
||||
.get_resample_evt()
|
||||
.try_clone()
|
||||
.map_err(OtherError::CloneResampleEvent)?;
|
||||
let resample_evt =
|
||||
EventAsync::new(resample_evt.0, ex).map_err(OtherError::AsyncResampleCreate)?;
|
||||
loop {
|
||||
let _ = resample_evt
|
||||
.next_val()
|
||||
.await
|
||||
.map_err(OtherError::ReadResampleEvent)?;
|
||||
interrupt.borrow_mut().do_interrupt_resample();
|
||||
let resample_evt = if let Some(resample_evt) = interrupt.borrow().get_resample_evt() {
|
||||
let resample_evt = resample_evt
|
||||
.try_clone()
|
||||
.map_err(OtherError::CloneResampleEvent)?;
|
||||
let resample_evt =
|
||||
EventAsync::new(resample_evt.0, ex).map_err(OtherError::AsyncResampleCreate)?;
|
||||
Some(resample_evt)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(resample_evt) = resample_evt {
|
||||
loop {
|
||||
let _ = resample_evt
|
||||
.next_val()
|
||||
.await
|
||||
.map_err(OtherError::ReadResampleEvent)?;
|
||||
interrupt.borrow().do_interrupt_resample();
|
||||
}
|
||||
} else {
|
||||
// no resample event, park the future.
|
||||
let () = futures::future::pending().await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ use data_model::{DataInit, Le16, Le32};
|
|||
use vm_memory::GuestMemory;
|
||||
|
||||
use super::{
|
||||
base_features, copy_config, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_CONSOLE,
|
||||
base_features, copy_config, Interrupt, Queue, Reader, SignalableInterrupt, VirtioDevice,
|
||||
Writer, TYPE_CONSOLE,
|
||||
};
|
||||
use crate::{ProtectionType, SerialDevice};
|
||||
|
||||
|
@ -239,7 +240,6 @@ impl Worker {
|
|||
(&transmit_evt, Token::TransmitQueueAvailable),
|
||||
(&receive_evt, Token::ReceiveQueueAvailable),
|
||||
(&in_avail_evt, Token::InputAvailable),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
(&kill_evt, Token::Kill),
|
||||
]) {
|
||||
Ok(pc) => pc,
|
||||
|
@ -248,6 +248,15 @@ impl Worker {
|
|||
return;
|
||||
}
|
||||
};
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
if wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.is_err()
|
||||
{
|
||||
error!("failed adding resample event to WaitContext.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut output: Box<dyn io::Write> = match self.output.take() {
|
||||
Some(o) => o,
|
||||
|
|
|
@ -14,7 +14,7 @@ use vm_control::{FsMappingRequest, VmResponse};
|
|||
use vm_memory::GuestMemory;
|
||||
|
||||
use crate::virtio::fs::{Error, Result};
|
||||
use crate::virtio::{Interrupt, Queue, Reader, Writer};
|
||||
use crate::virtio::{Interrupt, Queue, Reader, SignalableInterrupt, Writer};
|
||||
|
||||
impl fuse::Reader for Reader {}
|
||||
|
||||
|
@ -217,9 +217,11 @@ impl<F: FileSystem + Sync> Worker<F> {
|
|||
.map_err(Error::CreateWaitContext)?;
|
||||
|
||||
if watch_resample_event {
|
||||
wait_ctx
|
||||
.add(self.irq.get_resample_evt(), Token::InterruptResample)
|
||||
.map_err(Error::CreateWaitContext)?;
|
||||
if let Some(resample_evt) = self.irq.get_resample_evt() {
|
||||
wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.map_err(Error::CreateWaitContext)?;
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
|
|
|
@ -37,8 +37,8 @@ use sync::Mutex;
|
|||
use vm_memory::{GuestAddress, GuestMemory};
|
||||
|
||||
use super::{
|
||||
copy_config, resource_bridge::*, DescriptorChain, Interrupt, Queue, Reader, VirtioDevice,
|
||||
Writer, TYPE_GPU,
|
||||
copy_config, resource_bridge::*, DescriptorChain, Interrupt, Queue, Reader,
|
||||
SignalableInterrupt, VirtioDevice, Writer, TYPE_GPU,
|
||||
};
|
||||
|
||||
use super::{PciCapabilityType, VirtioPciShmCap};
|
||||
|
@ -703,7 +703,6 @@ impl Worker {
|
|||
(&self.ctrl_evt, Token::CtrlQueue),
|
||||
(&self.cursor_evt, Token::CursorQueue),
|
||||
(&*self.state.display().borrow(), Token::Display),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
(&self.kill_evt, Token::Kill),
|
||||
]) {
|
||||
Ok(pc) => pc,
|
||||
|
@ -712,6 +711,15 @@ impl Worker {
|
|||
return;
|
||||
}
|
||||
};
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
if wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.is_err()
|
||||
{
|
||||
error!("failed creating WaitContext");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (index, bridge) in self.resource_bridges.iter().enumerate() {
|
||||
if let Err(e) = wait_ctx.add(bridge, Token::ResourceBridge { index }) {
|
||||
|
|
|
@ -16,8 +16,8 @@ use vm_memory::GuestMemory;
|
|||
|
||||
use self::event_source::{EvdevEventSource, EventSource, SocketEventSource};
|
||||
use super::{
|
||||
copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer,
|
||||
TYPE_INPUT,
|
||||
copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt,
|
||||
VirtioDevice, Writer, TYPE_INPUT,
|
||||
};
|
||||
use linux_input_sys::{virtio_input_event, InputEventDecoder};
|
||||
use std::collections::BTreeMap;
|
||||
|
@ -463,7 +463,6 @@ impl<T: EventSource> Worker<T> {
|
|||
(&event_queue_evt, Token::EventQAvailable),
|
||||
(&status_queue_evt, Token::StatusQAvailable),
|
||||
(&self.event_source, Token::InputEventsAvailable),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
(&kill_evt, Token::Kill),
|
||||
]) {
|
||||
Ok(wait_ctx) => wait_ctx,
|
||||
|
@ -472,6 +471,15 @@ impl<T: EventSource> Worker<T> {
|
|||
return;
|
||||
}
|
||||
};
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
if wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.is_err()
|
||||
{
|
||||
error!("failed adding resample event to WaitContext.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
'wait: loop {
|
||||
let wait_events = match wait_ctx.wait() {
|
||||
|
|
|
@ -9,6 +9,26 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||
use std::sync::Arc;
|
||||
use sync::Mutex;
|
||||
|
||||
pub trait SignalableInterrupt {
|
||||
/// Writes to the irqfd to VMM to deliver virtual interrupt to the guest.
|
||||
fn signal(&self, vector: u16, interrupt_status_mask: u32);
|
||||
|
||||
/// Notify the driver that buffers have been placed in the used queue.
|
||||
fn signal_used_queue(&self, vector: u16) {
|
||||
self.signal(vector, INTERRUPT_STATUS_USED_RING)
|
||||
}
|
||||
|
||||
/// Notify the driver that the device configuration has changed.
|
||||
fn signal_config_changed(&self);
|
||||
|
||||
/// Get the event to signal resampling is needed if it exists.
|
||||
fn get_resample_evt(&self) -> Option<&Event>;
|
||||
|
||||
/// Reads the status and writes to the interrupt event. Doesn't read the resample event, it
|
||||
/// assumes the resample has been requested.
|
||||
fn do_interrupt_resample(&self);
|
||||
}
|
||||
|
||||
pub struct Interrupt {
|
||||
interrupt_status: Arc<AtomicUsize>,
|
||||
interrupt_evt: Event,
|
||||
|
@ -17,23 +37,7 @@ pub struct Interrupt {
|
|||
config_msix_vector: u16,
|
||||
}
|
||||
|
||||
impl Interrupt {
|
||||
pub fn new(
|
||||
interrupt_status: Arc<AtomicUsize>,
|
||||
interrupt_evt: Event,
|
||||
interrupt_resample_evt: Event,
|
||||
msix_config: Option<Arc<Mutex<MsixConfig>>>,
|
||||
config_msix_vector: u16,
|
||||
) -> Interrupt {
|
||||
Interrupt {
|
||||
interrupt_status,
|
||||
interrupt_evt,
|
||||
interrupt_resample_evt,
|
||||
msix_config,
|
||||
config_msix_vector,
|
||||
}
|
||||
}
|
||||
|
||||
impl SignalableInterrupt for Interrupt {
|
||||
/// Virtqueue Interrupts From The Device
|
||||
///
|
||||
/// If MSI-X is enabled in this device, MSI-X interrupt is preferred.
|
||||
|
@ -62,14 +66,36 @@ impl Interrupt {
|
|||
}
|
||||
}
|
||||
|
||||
/// Notify the driver that buffers have been placed in the used queue.
|
||||
pub fn signal_used_queue(&self, vector: u16) {
|
||||
self.signal(vector, INTERRUPT_STATUS_USED_RING)
|
||||
fn signal_config_changed(&self) {
|
||||
self.signal(self.config_msix_vector, INTERRUPT_STATUS_CONFIG_CHANGED)
|
||||
}
|
||||
|
||||
/// Notify the driver that the device configuration has changed.
|
||||
pub fn signal_config_changed(&self) {
|
||||
self.signal(self.config_msix_vector, INTERRUPT_STATUS_CONFIG_CHANGED)
|
||||
fn get_resample_evt(&self) -> Option<&Event> {
|
||||
Some(&self.interrupt_resample_evt)
|
||||
}
|
||||
|
||||
fn do_interrupt_resample(&self) {
|
||||
if self.interrupt_status.load(Ordering::SeqCst) != 0 {
|
||||
self.interrupt_evt.write(1).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Interrupt {
|
||||
pub fn new(
|
||||
interrupt_status: Arc<AtomicUsize>,
|
||||
interrupt_evt: Event,
|
||||
interrupt_resample_evt: Event,
|
||||
msix_config: Option<Arc<Mutex<MsixConfig>>>,
|
||||
config_msix_vector: u16,
|
||||
) -> Interrupt {
|
||||
Interrupt {
|
||||
interrupt_status,
|
||||
interrupt_evt,
|
||||
interrupt_resample_evt,
|
||||
msix_config,
|
||||
config_msix_vector,
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle interrupt resampling event, reading the value from the event and doing the resample.
|
||||
|
@ -78,20 +104,6 @@ impl Interrupt {
|
|||
self.do_interrupt_resample();
|
||||
}
|
||||
|
||||
/// Read the status and write to the interrupt event. Don't read the resample event, assume the
|
||||
/// resample has been requested.
|
||||
pub fn do_interrupt_resample(&self) {
|
||||
if self.interrupt_status.load(Ordering::SeqCst) != 0 {
|
||||
self.interrupt_evt.write(1).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the reference of interrupt_resample_evt
|
||||
/// To keep the interface clean, this member is private.
|
||||
pub fn get_resample_evt(&self) -> &Event {
|
||||
&self.interrupt_resample_evt
|
||||
}
|
||||
|
||||
/// Get a reference to the msix configuration
|
||||
pub fn get_msix_config(&self) -> &Option<Arc<Mutex<MsixConfig>>> {
|
||||
&self.msix_config
|
||||
|
|
|
@ -23,7 +23,8 @@ use virtio_sys::virtio_net::{
|
|||
use vm_memory::GuestMemory;
|
||||
|
||||
use super::{
|
||||
copy_config, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_NET,
|
||||
copy_config, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt, VirtioDevice,
|
||||
Writer, TYPE_NET,
|
||||
};
|
||||
|
||||
const QUEUE_SIZE: u16 = 256;
|
||||
|
@ -351,9 +352,11 @@ where
|
|||
.add(ctrl_evt, Token::CtrlQueue)
|
||||
.map_err(NetError::CreateWaitContext)?;
|
||||
// Let CtrlQueue's thread handle InterruptResample also.
|
||||
wait_ctx
|
||||
.add(self.interrupt.get_resample_evt(), Token::InterruptResample)
|
||||
.map_err(NetError::CreateWaitContext)?;
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.map_err(NetError::CreateWaitContext)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut tap_polling_enabled = true;
|
||||
|
|
|
@ -12,7 +12,8 @@ use base::{error, warn, Error as SysError, Event, PollToken, RawDescriptor, Wait
|
|||
use vm_memory::GuestMemory;
|
||||
|
||||
use super::{
|
||||
copy_config, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_9P,
|
||||
copy_config, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt, VirtioDevice,
|
||||
Writer, TYPE_9P,
|
||||
};
|
||||
|
||||
const QUEUE_SIZE: u16 = 128;
|
||||
|
@ -115,12 +116,14 @@ impl Worker {
|
|||
Kill,
|
||||
}
|
||||
|
||||
let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
|
||||
(&queue_evt, Token::QueueReady),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
(&kill_evt, Token::Kill),
|
||||
])
|
||||
.map_err(P9Error::CreateWaitContext)?;
|
||||
let wait_ctx: WaitContext<Token> =
|
||||
WaitContext::build_with(&[(&queue_evt, Token::QueueReady), (&kill_evt, Token::Kill)])
|
||||
.map_err(P9Error::CreateWaitContext)?;
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.map_err(P9Error::CreateWaitContext)?;
|
||||
}
|
||||
|
||||
loop {
|
||||
let events = wait_ctx.wait().map_err(P9Error::WaitError)?;
|
||||
|
|
|
@ -14,8 +14,8 @@ use vm_control::{MemSlot, VmMsyncRequest, VmMsyncResponse};
|
|||
use vm_memory::{GuestAddress, GuestMemory};
|
||||
|
||||
use super::{
|
||||
copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer,
|
||||
TYPE_PMEM,
|
||||
copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt,
|
||||
VirtioDevice, Writer, TYPE_PMEM,
|
||||
};
|
||||
|
||||
const QUEUE_SIZE: u16 = 256;
|
||||
|
@ -173,7 +173,6 @@ impl Worker {
|
|||
|
||||
let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
|
||||
(&queue_evt, Token::QueueAvailable),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
(&kill_evt, Token::Kill),
|
||||
]) {
|
||||
Ok(pc) => pc,
|
||||
|
@ -182,6 +181,15 @@ impl Worker {
|
|||
return;
|
||||
}
|
||||
};
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
if wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.is_err()
|
||||
{
|
||||
error!("failed adding resample event to WaitContext.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
'wait: loop {
|
||||
let events = match wait_ctx.wait() {
|
||||
|
|
|
@ -11,7 +11,7 @@ use cros_async::{AsyncError, EventAsync};
|
|||
use virtio_sys::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
|
||||
use vm_memory::{GuestAddress, GuestMemory};
|
||||
|
||||
use super::{Interrupt, VIRTIO_MSI_NO_VECTOR};
|
||||
use super::{SignalableInterrupt, VIRTIO_MSI_NO_VECTOR};
|
||||
|
||||
const VIRTQ_DESC_F_NEXT: u16 = 0x1;
|
||||
const VIRTQ_DESC_F_WRITE: u16 = 0x2;
|
||||
|
@ -536,7 +536,11 @@ impl Queue {
|
|||
/// inject interrupt into guest on this queue
|
||||
/// return true: interrupt is injected into guest for this queue
|
||||
/// false: interrupt isn't injected
|
||||
pub fn trigger_interrupt(&mut self, mem: &GuestMemory, interrupt: &Interrupt) -> bool {
|
||||
pub fn trigger_interrupt(
|
||||
&mut self,
|
||||
mem: &GuestMemory,
|
||||
interrupt: &dyn SignalableInterrupt,
|
||||
) -> bool {
|
||||
if self.available_interrupt_enabled(mem) {
|
||||
self.last_used = self.next_used;
|
||||
interrupt.signal_used_queue(self.vector);
|
||||
|
@ -554,6 +558,7 @@ impl Queue {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::Interrupt;
|
||||
use super::*;
|
||||
use base::Event;
|
||||
use data_model::{DataInit, Le16, Le32, Le64};
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::thread;
|
|||
use base::{error, warn, AsRawDescriptor, Event, PollToken, RawDescriptor, WaitContext};
|
||||
use vm_memory::GuestMemory;
|
||||
|
||||
use super::{Interrupt, Queue, VirtioDevice, Writer, TYPE_RNG};
|
||||
use super::{Interrupt, Queue, SignalableInterrupt, VirtioDevice, Writer, TYPE_RNG};
|
||||
|
||||
const QUEUE_SIZE: u16 = 256;
|
||||
const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
|
||||
|
@ -75,7 +75,6 @@ impl Worker {
|
|||
|
||||
let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
|
||||
(&queue_evt, Token::QueueAvailable),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
(&kill_evt, Token::Kill),
|
||||
]) {
|
||||
Ok(pc) => pc,
|
||||
|
@ -84,6 +83,15 @@ impl Worker {
|
|||
return;
|
||||
}
|
||||
};
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
if wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.is_err()
|
||||
{
|
||||
error!("failed adding resample event to WaitContext.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
'wait: loop {
|
||||
let events = match wait_ctx.wait() {
|
||||
|
|
|
@ -14,7 +14,8 @@ use base::{error, Event, PollToken, RawDescriptor, WaitContext};
|
|||
use vm_memory::GuestMemory;
|
||||
|
||||
use super::{
|
||||
DescriptorChain, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_TPM,
|
||||
DescriptorChain, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt, VirtioDevice,
|
||||
Writer, TYPE_TPM,
|
||||
};
|
||||
|
||||
// A single queue of size 2. The guest kernel driver will enqueue a single
|
||||
|
@ -112,9 +113,14 @@ impl Worker {
|
|||
|
||||
let wait_ctx = match WaitContext::build_with(&[
|
||||
(&self.queue_evt, Token::QueueAvailable),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
(&self.kill_evt, Token::Kill),
|
||||
]) {
|
||||
])
|
||||
.and_then(|wc| {
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
wc.add(resample_evt, Token::InterruptResample)?;
|
||||
}
|
||||
Ok(wc)
|
||||
}) {
|
||||
Ok(pc) => pc,
|
||||
Err(e) => {
|
||||
error!("vtpm failed creating WaitContext: {}", e);
|
||||
|
|
|
@ -8,6 +8,7 @@ use futures::pin_mut;
|
|||
use thiserror::Error as ThisError;
|
||||
use vm_memory::GuestMemory;
|
||||
|
||||
use crate::virtio::interrupt::SignalableInterrupt;
|
||||
use crate::virtio::{Interrupt, Queue};
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
|
@ -49,6 +50,7 @@ impl Worker {
|
|||
pub fn run(&mut self, ex: &Executor, interrupt: Interrupt) -> Result<(), String> {
|
||||
let resample_evt = interrupt
|
||||
.get_resample_evt()
|
||||
.expect("resample event required")
|
||||
.try_clone()
|
||||
.expect("failed to clone resample event");
|
||||
let async_resample_evt =
|
||||
|
|
|
@ -9,7 +9,7 @@ use vhost::Vhost;
|
|||
|
||||
use super::control_socket::{VhostDevRequest, VhostDevResponse};
|
||||
use super::{Error, Result};
|
||||
use crate::virtio::{Interrupt, Queue};
|
||||
use crate::virtio::{Interrupt, Queue, SignalableInterrupt};
|
||||
use libc::EIO;
|
||||
|
||||
/// Worker that takes care of running the vhost device.
|
||||
|
@ -105,11 +105,9 @@ impl<T: Vhost> Worker<T> {
|
|||
ControlNotify,
|
||||
}
|
||||
|
||||
let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
(&self.kill_evt, Token::Kill),
|
||||
])
|
||||
.map_err(Error::CreateWaitContext)?;
|
||||
let wait_ctx: WaitContext<Token> =
|
||||
WaitContext::build_with(&[(&self.kill_evt, Token::Kill)])
|
||||
.map_err(Error::CreateWaitContext)?;
|
||||
|
||||
for (index, vhost_int) in self.vhost_interrupt.iter().enumerate() {
|
||||
wait_ctx
|
||||
|
@ -121,6 +119,11 @@ impl<T: Vhost> Worker<T> {
|
|||
.add(socket, Token::ControlNotify)
|
||||
.map_err(Error::CreateWaitContext)?;
|
||||
}
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.map_err(Error::CreateWaitContext)?;
|
||||
}
|
||||
|
||||
'wait: loop {
|
||||
let events = wait_ctx.wait().map_err(Error::WaitError)?;
|
||||
|
|
|
@ -18,7 +18,7 @@ use crate::virtio::video::device::{
|
|||
use crate::virtio::video::event::{self, EvtType, VideoEvt};
|
||||
use crate::virtio::video::response::{self, Response};
|
||||
use crate::virtio::video::{Error, Result};
|
||||
use crate::virtio::{Interrupt, Reader, Writer};
|
||||
use crate::virtio::{Interrupt, Reader, SignalableInterrupt, Writer};
|
||||
|
||||
pub struct Worker {
|
||||
pub interrupt: Interrupt,
|
||||
|
@ -275,8 +275,13 @@ impl Worker {
|
|||
(&self.cmd_evt, Token::CmdQueue),
|
||||
(&self.event_evt, Token::EventQueue),
|
||||
(&self.kill_evt, Token::Kill),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
])
|
||||
.and_then(|wc| {
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
wc.add(resample_evt, Token::InterruptResample)?;
|
||||
}
|
||||
Ok(wc)
|
||||
})
|
||||
.map_err(Error::WaitContextCreationFailed)?;
|
||||
|
||||
// Stores descriptors in which responses for asynchronous commands will be written.
|
||||
|
|
|
@ -67,7 +67,9 @@ use vm_control::GpuMemoryDesc;
|
|||
use super::resource_bridge::{
|
||||
get_resource_info, BufferInfo, ResourceBridgeError, ResourceInfo, ResourceRequest,
|
||||
};
|
||||
use super::{DescriptorChain, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_WL};
|
||||
use super::{
|
||||
DescriptorChain, Interrupt, Queue, Reader, SignalableInterrupt, VirtioDevice, Writer, TYPE_WL,
|
||||
};
|
||||
use vm_control::{MemSlot, VmMemoryRequest, VmMemoryResponse};
|
||||
|
||||
const VIRTWL_SEND_MAX_ALLOCS: usize = 28;
|
||||
|
@ -1514,7 +1516,6 @@ impl Worker {
|
|||
(&out_queue_evt, Token::OutQueue),
|
||||
(&kill_evt, Token::Kill),
|
||||
(&self.state.wait_ctx, Token::State),
|
||||
(self.interrupt.get_resample_evt(), Token::InterruptResample),
|
||||
]) {
|
||||
Ok(pc) => pc,
|
||||
Err(e) => {
|
||||
|
@ -1522,6 +1523,15 @@ impl Worker {
|
|||
return;
|
||||
}
|
||||
};
|
||||
if let Some(resample_evt) = self.interrupt.get_resample_evt() {
|
||||
if wait_ctx
|
||||
.add(resample_evt, Token::InterruptResample)
|
||||
.is_err()
|
||||
{
|
||||
error!("failed adding resample event to WaitContext.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
'wait: loop {
|
||||
let mut signal_used_in = false;
|
||||
|
|
Loading…
Reference in a new issue