From 3d0de5ad713febac44593f3032f408bb1c12a4a6 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 22:54:36 +0200 Subject: [PATCH] shm: close client buffers in the cpu worker --- src/cli/input.rs | 7 +-- src/clientmem.rs | 55 +++++++++++++++++++--- src/cpu_worker.rs | 1 - src/ifs/jay_input.rs | 9 +++- src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs | 12 +++-- src/ifs/wl_shm_pool.rs | 9 +++- src/it/tests/t0040_virtual_keyboard.rs | 2 +- 7 files changed, 79 insertions(+), 16 deletions(-) diff --git a/src/cli/input.rs b/src/cli/input.rs index 46625bd5..d48b5624 100644 --- a/src/cli/input.rs +++ b/src/cli/input.rs @@ -353,9 +353,10 @@ impl Input { async fn handle_keymap(&self, input: JayInputId) -> Vec { let data = Rc::new(RefCell::new(Vec::new())); jay_input::Keymap::handle(&self.tc, input, data.clone(), |d, map| { - let mem = - Rc::new(ClientMem::new(&map.keymap, map.keymap_len as _, true, None).unwrap()) - .offset(0); + let mem = Rc::new( + ClientMem::new(&map.keymap, map.keymap_len as _, true, None, None).unwrap(), + ) + .offset(0); mem.read(d.borrow_mut().deref_mut()).unwrap(); }); self.tc.round_trip().await; diff --git a/src/clientmem.rs b/src/clientmem.rs index 8b7d506f..3f435e0c 100644 --- a/src/clientmem.rs +++ b/src/clientmem.rs @@ -1,8 +1,12 @@ use { - crate::{client::Client, utils::vec_ext::VecExt}, + crate::{ + client::Client, + cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker}, + utils::vec_ext::VecExt, + }, std::{ cell::Cell, - mem::MaybeUninit, + mem::{ManuallyDrop, MaybeUninit}, ptr, rc::Rc, sync::atomic::{compiler_fence, Ordering}, @@ -25,10 +29,11 @@ pub enum ClientMemError { } pub struct ClientMem { - fd: Rc, + fd: ManuallyDrop>, failed: Cell, sigbus_impossible: bool, data: *const [Cell], + cpu: Option>, } #[derive(Clone)] @@ -44,6 +49,7 @@ impl ClientMem { len: usize, read_only: bool, client: Option<&Client>, + cpu: Option<&Rc>, ) -> Result { let mut sigbus_impossible = false; if let Ok(seals) = uapi::fcntl_get_seals(fd.raw()) { @@ -78,10 +84,11 @@ impl ClientMem { } }; Ok(Self { - fd: fd.clone(), + fd: ManuallyDrop::new(fd.clone()), failed: Cell::new(false), sigbus_impossible, data, + cpu: cpu.cloned(), }) } @@ -155,8 +162,17 @@ impl ClientMemOffset { impl Drop for ClientMem { fn drop(&mut self) { - unsafe { - c::munmap(self.data as _, self.len()); + let fd = unsafe { ManuallyDrop::take(&mut self.fd) }; + if let Some(cpu) = &self.cpu { + let pending = cpu.submit(Box::new(CloseMemWork { + fd: Rc::try_unwrap(fd).ok(), + data: self.data, + })); + pending.detach(); + } else { + unsafe { + c::munmap(self.data as _, self.len()); + } } } } @@ -219,3 +235,30 @@ pub fn init() -> Result<(), ClientMemError> { } } } + +struct CloseMemWork { + fd: Option, + data: *const [Cell], +} + +unsafe impl Send for CloseMemWork {} + +impl CpuJob for CloseMemWork { + fn work(&mut self) -> &mut dyn CpuWork { + self + } + + fn completed(self: Box) { + // nothing + } +} + +impl CpuWork for CloseMemWork { + fn run(&mut self) -> Option> { + self.fd.take(); + unsafe { + c::munmap(self.data as _, self.data.len()); + } + None + } +} diff --git a/src/cpu_worker.rs b/src/cpu_worker.rs index 3875401f..ec360aa0 100644 --- a/src/cpu_worker.rs +++ b/src/cpu_worker.rs @@ -140,7 +140,6 @@ pub enum CpuWorkerError { } impl PendingJob { - #[expect(dead_code)] pub fn detach(self) { match self.job_data.state.get() { PendingJobState::Waiting => { diff --git a/src/ifs/jay_input.rs b/src/ifs/jay_input.rs index 8d196063..2e6d26fe 100644 --- a/src/ifs/jay_input.rs +++ b/src/ifs/jay_input.rs @@ -169,7 +169,14 @@ impl JayInput { where F: FnOnce(&Rc) -> Result<(), JayInputError>, { - let cm = Rc::new(ClientMem::new(keymap, len as _, true, Some(&self.client))?).offset(0); + let cm = Rc::new(ClientMem::new( + keymap, + len as _, + true, + Some(&self.client), + None, + )?) + .offset(0); let mut map = vec![]; cm.read(&mut map)?; self.or_error(|| { diff --git a/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs b/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs index 914ac247..e100ce3e 100644 --- a/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs +++ b/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs @@ -56,9 +56,15 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 { if req.size > MAX_SIZE { return Err(ZwpVirtualKeyboardV1Error::OversizedKeymap); } - let client_mem = ClientMem::new(&req.fd, req.size as usize - 1, true, Some(&self.client)) - .map(Rc::new) - .map_err(ZwpVirtualKeyboardV1Error::MapKeymap)?; + let client_mem = ClientMem::new( + &req.fd, + req.size as usize - 1, + true, + Some(&self.client), + None, + ) + .map(Rc::new) + .map_err(ZwpVirtualKeyboardV1Error::MapKeymap)?; let mut map = vec![]; client_mem .offset(0) diff --git a/src/ifs/wl_shm_pool.rs b/src/ifs/wl_shm_pool.rs index 6ea0c670..b03dd608 100644 --- a/src/ifs/wl_shm_pool.rs +++ b/src/ifs/wl_shm_pool.rs @@ -34,7 +34,13 @@ impl WlShmPool { Ok(Self { id, client: client.clone(), - mem: CloneCell::new(Rc::new(ClientMem::new(&fd, len, false, Some(client))?)), + mem: CloneCell::new(Rc::new(ClientMem::new( + &fd, + len, + false, + Some(client), + Some(&client.state.cpu_worker), + )?)), fd, tracker: Default::default(), version, @@ -86,6 +92,7 @@ impl WlShmPoolRequestHandler for WlShmPool { req.size as usize, false, Some(&self.client), + Some(&self.client.state.cpu_worker), )?)); Ok(()) } diff --git a/src/it/tests/t0040_virtual_keyboard.rs b/src/it/tests/t0040_virtual_keyboard.rs index bc0627c3..dc2b1d1f 100644 --- a/src/it/tests/t0040_virtual_keyboard.rs +++ b/src/it/tests/t0040_virtual_keyboard.rs @@ -149,7 +149,7 @@ async fn test(run: Rc) -> TestResult { } fn read_keymap(fd: &Rc, size: usize) -> String { - let client_mem = ClientMem::new(fd, size - 1, true, None).unwrap(); + let client_mem = ClientMem::new(fd, size - 1, true, None, None).unwrap(); let client_mem = Rc::new(client_mem).offset(0); let mut v = vec![]; client_mem.read(&mut v).unwrap();