summary refs log tree commit diff
path: root/devices/src/virtio/wl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'devices/src/virtio/wl.rs')
-rw-r--r--devices/src/virtio/wl.rs108
1 files changed, 91 insertions, 17 deletions
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
index 6fefd51..a685e51 100644
--- a/devices/src/virtio/wl.rs
+++ b/devices/src/virtio/wl.rs
@@ -67,10 +67,39 @@ use sys_util::ioctl_with_ref;
 
 use super::resource_bridge::*;
 use super::{
-    DescriptorChain, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_WL, VIRTIO_F_VERSION_1,
+    DescriptorChain, Interrupt, InterruptProxyEvent, Queue, Reader, VirtioDevice, Writer, TYPE_WL,
+    VIRTIO_F_VERSION_1,
 };
 use vm_control::{MaybeOwnedFd, VmMemoryControlRequestSocket, VmMemoryRequest, VmMemoryResponse};
 
+use msg_socket::{MsgOnSocket, MsgSocket};
+use sys_util::net::UnixSeqpacket;
+
+#[derive(Debug, MsgOnSocket)]
+pub struct SingleFd {
+    pub memfd: MaybeOwnedFd,
+    pub interrupt: MaybeOwnedFd,
+    pub interrupt_resample_evt: MaybeOwnedFd,
+    pub in_queue: Queue,
+    pub out_queue: Queue,
+    pub vm_socket: MaybeOwnedFd,
+    pub use_transition_flags: bool,
+    pub in_queue_evt: MaybeOwnedFd,
+    pub out_queue_evt: MaybeOwnedFd,
+    pub kill_evt: MaybeOwnedFd,
+}
+
+type Socket = MsgSocket<SingleFd, ()>;
+
+lazy_static! {
+    static ref SOCKET: Socket = {
+        let mut path = std::env::var("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR missing");
+        path.push_str("/crosvm-wl.sock");
+        let socket = UnixSeqpacket::connect(&path).expect("connect failed");
+        MsgSocket::new(socket)
+    };
+}
+
 const VIRTWL_SEND_MAX_ALLOCS: usize = 28;
 const VIRTIO_WL_CMD_VFD_NEW: u32 = 256;
 const VIRTIO_WL_CMD_VFD_CLOSE: u32 = 257;
@@ -1336,7 +1365,7 @@ impl WlState {
     }
 }
 
-struct Worker {
+pub struct Worker {
     interrupt: Interrupt,
     mem: GuestMemory,
     in_queue: Queue,
@@ -1345,15 +1374,15 @@ struct Worker {
 }
 
 impl Worker {
-    fn new(
+    pub fn new(
         mem: GuestMemory,
         interrupt: Interrupt,
         in_queue: Queue,
         out_queue: Queue,
-        wayland_paths: Map<String, PathBuf>,
+        wayland_paths: Map<String, PathBuf>, // { "": "/run/user/1000/wayland-0" }
         vm_socket: VmMemoryControlRequestSocket,
         use_transition_flags: bool,
-        resource_bridge: Option<ResourceRequestSocket>,
+        resource_bridge: Option<ResourceRequestSocket>, // None
     ) -> Worker {
         Worker {
             interrupt,
@@ -1369,7 +1398,7 @@ impl Worker {
         }
     }
 
-    fn run(&mut self, mut queue_evts: Vec<EventFd>, kill_evt: EventFd) {
+    pub fn run(&mut self, mut queue_evts: Vec<EventFd>, kill_evt: EventFd) {
         let mut in_desc_chains: VecDeque<DescriptorChain> =
             VecDeque::with_capacity(QUEUE_SIZE as usize);
         let in_queue_evt = queue_evts.remove(0);
@@ -1529,6 +1558,34 @@ impl Worker {
     }
 }
 
+struct InterruptWorker {
+    socket: MsgSocket<(), InterruptProxyEvent>,
+    interrupt: Interrupt,
+}
+
+impl InterruptWorker {
+    fn new(socket: MsgSocket<(), InterruptProxyEvent>, interrupt: Interrupt) -> Self {
+        Self { socket, interrupt }
+    }
+
+    fn run(&self) {
+        loop {
+            use InterruptProxyEvent::*;
+            let val = self.socket.recv();
+            match val {
+                Ok(SignalUsedQueue(value)) => self.interrupt.signal_used_queue(value).unwrap(),
+                Ok(SignalConfigChanged) => self.interrupt.signal_config_changed().unwrap(),
+                Ok(InterruptResample) => self.interrupt.interrupt_resample().unwrap(),
+
+                Err(e) => {
+                    eprintln!("recv error: {}", e);
+                    panic!("recv error: {}", e)
+                }
+            }
+        }
+    }
+}
+
 pub struct Wl {
     kill_evt: Option<EventFd>,
     worker_thread: Option<thread::JoinHandle<()>>,
@@ -1579,6 +1636,12 @@ impl VirtioDevice for Wl {
             keep_fds.push(resource_bridge.as_raw_fd());
         }
 
+        if let Some(ref kill_evt) = self.kill_evt {
+            keep_fds.push(kill_evt.as_raw_fd());
+        }
+
+        keep_fds.push(SOCKET.as_raw_fd());
+
         keep_fds
     }
 
@@ -1624,21 +1687,32 @@ impl VirtioDevice for Wl {
             let wayland_paths = self.wayland_paths.clone();
             let use_transition_flags = self.use_transition_flags;
             let resource_bridge = self.resource_bridge.take();
+
+            let (ours, theirs) = UnixSeqpacket::pair().expect("pair failed");
+
+            if let Err(e) = SOCKET.send(&SingleFd {
+                memfd: MaybeOwnedFd::Borrowed(mem.as_raw_fd()),
+                interrupt: MaybeOwnedFd::Borrowed(theirs.as_raw_fd()),
+                interrupt_resample_evt: MaybeOwnedFd::Borrowed(
+                    interrupt.get_resample_evt().as_raw_fd(),
+                ),
+                in_queue: queues.remove(0),
+                out_queue: queues.remove(0),
+                vm_socket: MaybeOwnedFd::Borrowed(vm_socket.as_raw_fd()),
+                use_transition_flags,
+                in_queue_evt: MaybeOwnedFd::Borrowed(queue_evts[0].as_raw_fd()),
+                out_queue_evt: MaybeOwnedFd::Borrowed(queue_evts[1].as_raw_fd()),
+                kill_evt: MaybeOwnedFd::Borrowed(kill_evt.as_raw_fd()),
+            }) {
+                error!("failed to send SingleFd: {}", e);
+                return;
+            }
+
             let worker_result =
                 thread::Builder::new()
                     .name("virtio_wl".to_string())
                     .spawn(move || {
-                        Worker::new(
-                            mem,
-                            interrupt,
-                            queues.remove(0),
-                            queues.remove(0),
-                            wayland_paths,
-                            vm_socket,
-                            use_transition_flags,
-                            resource_bridge,
-                        )
-                        .run(queue_evts, kill_evt);
+                        InterruptWorker::new(MsgSocket::new(ours), interrupt).run();
                     });
 
             match worker_result {