summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--devices/src/virtio/gpu/mod.rs42
-rw-r--r--src/linux.rs43
2 files changed, 51 insertions, 34 deletions
diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs
index cc42ace..0031b73 100644
--- a/devices/src/virtio/gpu/mod.rs
+++ b/devices/src/virtio/gpu/mod.rs
@@ -8,7 +8,7 @@ mod protocol;
 use std::cell::RefCell;
 use std::collections::VecDeque;
 use std::i64;
-use std::mem::size_of;
+use std::mem::{self, size_of};
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::path::{Path, PathBuf};
 use std::rc::Rc;
@@ -474,7 +474,7 @@ struct Worker {
     ctrl_evt: EventFd,
     cursor_queue: Queue,
     cursor_evt: EventFd,
-    resource_bridge: Option<ResourceResponseSocket>,
+    resource_bridges: Vec<ResourceResponseSocket>,
     kill_evt: EventFd,
     state: Frontend,
 }
@@ -492,9 +492,9 @@ impl Worker {
             CtrlQueue,
             CursorQueue,
             Display,
-            ResourceBridge,
             InterruptResample,
             Kill,
+            ResourceBridge { index: usize },
         }
 
         let poll_ctx: PollContext<Token> = match PollContext::new()
@@ -517,12 +517,14 @@ impl Worker {
             }
         };
 
-        if let Some(resource_bridge) = &self.resource_bridge {
-            if let Err(e) = poll_ctx.add(resource_bridge, Token::ResourceBridge) {
+        for (index, bridge) in self.resource_bridges.iter().enumerate() {
+            if let Err(e) = poll_ctx.add(bridge, Token::ResourceBridge { index }) {
                 error!("failed to add resource bridge to PollContext: {}", e);
             }
         }
 
+        // Declare this outside the loop so we don't keep allocating and freeing the vector.
+        let mut process_resource_bridge = Vec::with_capacity(self.resource_bridges.len());
         'poll: loop {
             // If there are outstanding fences, wake up early to poll them.
             let duration = if !self.state.fence_descriptors.is_empty() {
@@ -539,7 +541,11 @@ impl Worker {
                 }
             };
             let mut signal_used = false;
-            let mut process_resource_bridge = false;
+
+            // Clear the old values and re-initialize with false.
+            process_resource_bridge.clear();
+            process_resource_bridge.resize(self.resource_bridges.len(), false);
+
             for event in events.iter_readable() {
                 match event.token() {
                     Token::CtrlQueue => {
@@ -558,7 +564,7 @@ impl Worker {
                             let _ = self.exit_evt.write(1);
                         }
                     }
-                    Token::ResourceBridge => process_resource_bridge = true,
+                    Token::ResourceBridge { index } => process_resource_bridge[index] = true,
                     Token::InterruptResample => {
                         let _ = self.interrupt_resample_evt.read();
                         if self.interrupt_status.load(Ordering::SeqCst) != 0 {
@@ -587,9 +593,11 @@ impl Worker {
             // Process the entire control queue before the resource bridge in case a resource is
             // created or destroyed by the control queue. Processing the resource bridge first may
             // lead to a race condition.
-            if process_resource_bridge {
-                if let Some(resource_bridge) = &self.resource_bridge {
-                    self.state.process_resource_bridge(resource_bridge);
+            for (bridge, &should_process) in
+                self.resource_bridges.iter().zip(&process_resource_bridge)
+            {
+                if should_process {
+                    self.state.process_resource_bridge(bridge);
                 }
             }
 
@@ -604,7 +612,7 @@ pub struct Gpu {
     config_event: bool,
     exit_evt: EventFd,
     gpu_device_socket: Option<VmMemoryControlRequestSocket>,
-    resource_bridge: Option<ResourceResponseSocket>,
+    resource_bridges: Vec<ResourceResponseSocket>,
     kill_evt: Option<EventFd>,
     wayland_socket_path: PathBuf,
 }
@@ -613,14 +621,14 @@ impl Gpu {
     pub fn new<P: AsRef<Path>>(
         exit_evt: EventFd,
         gpu_device_socket: Option<VmMemoryControlRequestSocket>,
-        resource_bridge: Option<ResourceResponseSocket>,
+        resource_bridges: Vec<ResourceResponseSocket>,
         wayland_socket_path: P,
     ) -> Gpu {
         Gpu {
             config_event: false,
             exit_evt,
             gpu_device_socket,
-            resource_bridge,
+            resource_bridges,
             kill_evt: None,
             wayland_socket_path: wayland_socket_path.as_ref().to_path_buf(),
         }
@@ -664,8 +672,8 @@ impl VirtioDevice for Gpu {
         }
 
         keep_fds.push(self.exit_evt.as_raw_fd());
-        if let Some(resource_bridge) = &self.resource_bridge {
-            keep_fds.push(resource_bridge.as_raw_fd());
+        for bridge in &self.resource_bridges {
+            keep_fds.push(bridge.as_raw_fd());
         }
         keep_fds
     }
@@ -739,7 +747,7 @@ impl VirtioDevice for Gpu {
         };
         self.kill_evt = Some(self_kill_evt);
 
-        let resource_bridge = self.resource_bridge.take();
+        let resource_bridges = mem::replace(&mut self.resource_bridges, Vec::new());
 
         let ctrl_queue = queues.remove(0);
         let ctrl_evt = queue_evts.remove(0);
@@ -802,7 +810,7 @@ impl VirtioDevice for Gpu {
                             ctrl_evt,
                             cursor_queue,
                             cursor_evt,
-                            resource_bridge,
+                            resource_bridges,
                             kill_evt,
                             state: Frontend::new(Backend::new(
                                 device,
diff --git a/src/linux.rs b/src/linux.rs
index 2fe1d5b..48cbe52 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -552,7 +552,7 @@ fn create_gpu_device(
     cfg: &Config,
     exit_evt: &EventFd,
     gpu_device_socket: VmMemoryControlRequestSocket,
-    gpu_socket: virtio::resource_bridge::ResourceResponseSocket,
+    gpu_sockets: Vec<virtio::resource_bridge::ResourceResponseSocket>,
     wayland_socket_path: &Path,
 ) -> DeviceResult {
     let jailed_wayland_path = Path::new("/wayland-0");
@@ -560,7 +560,7 @@ fn create_gpu_device(
     let dev = virtio::Gpu::new(
         exit_evt.try_clone().map_err(Error::CloneEventFd)?,
         Some(gpu_device_socket),
-        Some(gpu_socket),
+        gpu_sockets,
         if cfg.sandbox {
             &jailed_wayland_path
         } else {
@@ -835,36 +835,45 @@ fn create_virtio_devices(
     }
 
     #[cfg_attr(not(feature = "gpu"), allow(unused_mut))]
-    let mut resource_bridge_wl_socket = None::<virtio::resource_bridge::ResourceRequestSocket>;
+    let mut resource_bridges = Vec::<virtio::resource_bridge::ResourceResponseSocket>::new();
+
+    if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() {
+        #[cfg_attr(not(feature = "gpu"), allow(unused_mut))]
+        let mut wl_resource_bridge = None::<virtio::resource_bridge::ResourceRequestSocket>;
+
+        #[cfg(feature = "gpu")]
+        {
+            if cfg.gpu {
+                let (wl_socket, gpu_socket) =
+                    virtio::resource_bridge::pair().map_err(Error::CreateSocket)?;
+                resource_bridges.push(gpu_socket);
+                wl_resource_bridge = Some(wl_socket);
+            }
+        }
+
+        devs.push(create_wayland_device(
+            cfg,
+            wayland_socket_path,
+            wayland_device_socket,
+            wl_resource_bridge,
+        )?);
+    }
 
     #[cfg(feature = "gpu")]
     {
         if cfg.gpu {
             if let Some(wayland_socket_path) = &cfg.wayland_socket_path {
-                let (wl_socket, gpu_socket) =
-                    virtio::resource_bridge::pair().map_err(Error::CreateSocket)?;
-                resource_bridge_wl_socket = Some(wl_socket);
-
                 devs.push(create_gpu_device(
                     cfg,
                     _exit_evt,
                     gpu_device_socket,
-                    gpu_socket,
+                    resource_bridges,
                     wayland_socket_path,
                 )?);
             }
         }
     }
 
-    if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() {
-        devs.push(create_wayland_device(
-            cfg,
-            wayland_socket_path,
-            wayland_device_socket,
-            resource_bridge_wl_socket,
-        )?);
-    }
-
     if let Some(cid) = cfg.cid {
         devs.push(create_vhost_vsock_device(cfg, cid, mem)?);
     }