From 9f986031216db6a9141e8944054339d9c2224236 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 12:48:02 +0200 Subject: [PATCH 01/22] vulkan: move OnDrop out of vulkan module --- src/gfx_apis/vulkan.rs | 1 - src/gfx_apis/vulkan/bo_allocator.rs | 4 ++-- src/gfx_apis/vulkan/device.rs | 2 +- src/gfx_apis/vulkan/image.rs | 4 ++-- src/gfx_apis/vulkan/instance.rs | 5 ++++- src/gfx_apis/vulkan/pipeline.rs | 9 ++++++--- src/gfx_apis/vulkan/shm_image.rs | 3 +-- src/gfx_apis/vulkan/staging.rs | 12 +++++++----- src/utils.rs | 1 + src/{gfx_apis/vulkan/util.rs => utils/on_drop.rs} | 0 10 files changed, 24 insertions(+), 17 deletions(-) rename src/{gfx_apis/vulkan/util.rs => utils/on_drop.rs} (100%) diff --git a/src/gfx_apis/vulkan.rs b/src/gfx_apis/vulkan.rs index 8b1cae35..49f3dac0 100644 --- a/src/gfx_apis/vulkan.rs +++ b/src/gfx_apis/vulkan.rs @@ -14,7 +14,6 @@ mod semaphore; mod shaders; mod shm_image; mod staging; -mod util; use { crate::{ diff --git a/src/gfx_apis/vulkan/bo_allocator.rs b/src/gfx_apis/vulkan/bo_allocator.rs index 1874c72f..f89da55b 100644 --- a/src/gfx_apis/vulkan/bo_allocator.rs +++ b/src/gfx_apis/vulkan/bo_allocator.rs @@ -8,9 +8,9 @@ use { gfx_apis::vulkan::{ allocator::VulkanAllocator, command::VulkanCommandBuffer, device::VulkanDevice, format::VulkanFormat, renderer::image_barrier, staging::VulkanStagingBuffer, - util::OnDrop, VulkanError, + VulkanError, }, - utils::errorfmt::ErrorFmt, + utils::{errorfmt::ErrorFmt, on_drop::OnDrop}, video::{ dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec}, drm::Drm, diff --git a/src/gfx_apis/vulkan/device.rs b/src/gfx_apis/vulkan/device.rs index 8e23fabe..00f3b67b 100644 --- a/src/gfx_apis/vulkan/device.rs +++ b/src/gfx_apis/vulkan/device.rs @@ -7,9 +7,9 @@ use { map_extension_properties, ApiVersionDisplay, Extensions, VulkanInstance, API_VERSION, }, - util::OnDrop, VulkanError, }, + utils::on_drop::OnDrop, video::{ drm::{sync_obj::SyncObjCtx, Drm}, gbm::GbmDevice, diff --git a/src/gfx_apis/vulkan/image.rs b/src/gfx_apis/vulkan/image.rs index d92ad53a..ee0555a5 100644 --- a/src/gfx_apis/vulkan/image.rs +++ b/src/gfx_apis/vulkan/image.rs @@ -4,10 +4,10 @@ use { gfx_api::{GfxApiOpt, GfxError, GfxFramebuffer, GfxImage, GfxTexture, SyncFile}, gfx_apis::vulkan::{ allocator::VulkanAllocation, device::VulkanDevice, format::VulkanModifierLimits, - renderer::VulkanRenderer, shm_image::VulkanShmImage, util::OnDrop, VulkanError, + renderer::VulkanRenderer, shm_image::VulkanShmImage, VulkanError, }, theme::Color, - utils::clonecell::CloneCell, + utils::{clonecell::CloneCell, on_drop::OnDrop}, video::dmabuf::{DmaBuf, PlaneVec}, }, ash::vk::{ diff --git a/src/gfx_apis/vulkan/instance.rs b/src/gfx_apis/vulkan/instance.rs index aba36851..bb39f3c3 100644 --- a/src/gfx_apis/vulkan/instance.rs +++ b/src/gfx_apis/vulkan/instance.rs @@ -1,5 +1,8 @@ use { - crate::gfx_apis::vulkan::{util::OnDrop, VulkanError, VULKAN_VALIDATION}, + crate::{ + gfx_apis::vulkan::{VulkanError, VULKAN_VALIDATION}, + utils::on_drop::OnDrop, + }, ahash::{AHashMap, AHashSet}, ash::{ ext::{debug_utils, validation_features}, diff --git a/src/gfx_apis/vulkan/pipeline.rs b/src/gfx_apis/vulkan/pipeline.rs index 037e1692..3d495f39 100644 --- a/src/gfx_apis/vulkan/pipeline.rs +++ b/src/gfx_apis/vulkan/pipeline.rs @@ -1,7 +1,10 @@ use { - crate::gfx_apis::vulkan::{ - descriptor::VulkanDescriptorSetLayout, device::VulkanDevice, shaders::VulkanShader, - util::OnDrop, VulkanError, + crate::{ + gfx_apis::vulkan::{ + descriptor::VulkanDescriptorSetLayout, device::VulkanDevice, shaders::VulkanShader, + VulkanError, + }, + utils::on_drop::OnDrop, }, arrayvec::ArrayVec, ash::{ diff --git a/src/gfx_apis/vulkan/shm_image.rs b/src/gfx_apis/vulkan/shm_image.rs index e272eb87..81f6e568 100644 --- a/src/gfx_apis/vulkan/shm_image.rs +++ b/src/gfx_apis/vulkan/shm_image.rs @@ -9,11 +9,10 @@ use { image::{VulkanImage, VulkanImageMemory}, renderer::{image_barrier, VulkanRenderer}, staging::VulkanStagingBuffer, - util::OnDrop, VulkanError, }, rect::Rect, - utils::errorfmt::ErrorFmt, + utils::{errorfmt::ErrorFmt, on_drop::OnDrop}, }, ash::vk::{ AccessFlags2, BufferImageCopy2, BufferMemoryBarrier2, CommandBufferBeginInfo, diff --git a/src/gfx_apis/vulkan/staging.rs b/src/gfx_apis/vulkan/staging.rs index 7e205a81..b8ccc2ef 100644 --- a/src/gfx_apis/vulkan/staging.rs +++ b/src/gfx_apis/vulkan/staging.rs @@ -1,9 +1,11 @@ use { - crate::gfx_apis::vulkan::{ - allocator::{VulkanAllocation, VulkanAllocator}, - device::VulkanDevice, - util::OnDrop, - VulkanError, + crate::{ + gfx_apis::vulkan::{ + allocator::{VulkanAllocation, VulkanAllocator}, + device::VulkanDevice, + VulkanError, + }, + utils::on_drop::OnDrop, }, ash::vk::{Buffer, BufferCreateInfo, BufferUsageFlags, MappedMemoryRange}, gpu_alloc::UsageFlags, diff --git a/src/utils.rs b/src/utils.rs index d2afdf17..9aed5327 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -27,6 +27,7 @@ pub mod nonblock; pub mod num_cpus; pub mod numcell; pub mod on_change; +pub mod on_drop; pub mod once; pub mod opaque; pub mod opaque_cell; diff --git a/src/gfx_apis/vulkan/util.rs b/src/utils/on_drop.rs similarity index 100% rename from src/gfx_apis/vulkan/util.rs rename to src/utils/on_drop.rs From 92f7cb56fd5df49c81a3895cbdcf3b4b69907c5b Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 16:54:25 +0200 Subject: [PATCH 02/22] damage: add damage queue --- src/rect.rs | 4 ++- src/rect/region.rs | 67 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/rect.rs b/src/rect.rs index df9dedd7..a5cd711c 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -3,6 +3,8 @@ mod region; #[cfg(test)] mod tests; +#[expect(unused_imports)] +pub use region::DamageQueue; pub use region::RegionBuilder; use { jay_algorithms::rect::RectRaw, @@ -16,7 +18,7 @@ pub struct Rect { raw: RectRaw, } -#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(Clone, Eq, PartialEq, Debug, Default)] pub struct Region { rects: SmallVec<[RectRaw; 1]>, extents: Rect, diff --git a/src/rect/region.rs b/src/rect/region.rs index 262950d3..ade706c1 100644 --- a/src/rect/region.rs +++ b/src/rect/region.rs @@ -1,11 +1,17 @@ use { - crate::rect::{Rect, Region}, + crate::{ + rect::{Rect, Region}, + utils::{ + array, + ptr_ext::{MutPtrExt, PtrExt}, + }, + }, jay_algorithms::rect::{ region::{extents, rects_to_bands, subtract, union}, RectRaw, }, smallvec::SmallVec, - std::{mem, ops::Deref, rc::Rc}, + std::{cell::UnsafeCell, mem, ops::Deref, rc::Rc}, }; thread_local! { @@ -18,12 +24,16 @@ thread_local! { impl Region { pub fn new(rect: Rect) -> Rc { + Rc::new(Self::new2(rect)) + } + + pub fn new2(rect: Rect) -> Self { let mut rects = SmallVec::new(); rects.push(rect.raw); - Rc::new(Self { + Self { rects, extents: rect, - }) + } } pub fn empty() -> Rc { @@ -34,16 +44,23 @@ impl Region { if rects.is_empty() { return Self::empty(); } + Rc::new(Self::from_rects2(rects)) + } + + pub fn from_rects2(rects: &[Rect]) -> Self { + if rects.is_empty() { + return Self::default(); + } if rects.len() == 1 { - return Self::new(rects[0]); + return Self::new2(rects[0]); } let rects = rects_to_bands(unsafe { mem::transmute::<&[Rect], &[RectRaw]>(rects) }); - Rc::new(Self { + Self { extents: Rect { raw: extents(&rects), }, rects, - }) + } } pub fn union(self: &Rc, other: &Rc) -> Rc { @@ -173,3 +190,39 @@ impl RegionBuilder { self.pending.clear(); } } + +pub struct DamageQueue { + this: usize, + datas: Rc>>>, +} + +impl DamageQueue { + #[expect(dead_code)] + pub fn new() -> [DamageQueue; N] { + let datas = Rc::new(UnsafeCell::new(vec![vec!(); N])); + array::from_fn(|this| DamageQueue { + this, + datas: datas.clone(), + }) + } + + #[expect(dead_code)] + pub fn damage(&self, rects: &[Rect]) { + let datas = unsafe { self.datas.get().deref_mut() }; + for data in datas { + data.extend(rects); + } + } + + #[expect(dead_code)] + pub fn clear(&self) { + let data = unsafe { &mut self.datas.get().deref_mut()[self.this] }; + data.clear(); + } + + #[expect(dead_code)] + pub fn get(&self) -> Region { + let data = unsafe { &self.datas.get().deref()[self.this] }; + Region::from_rects2(data) + } +} From 604974c927aee0c410774cdec3caea74e6ac907a Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 17:00:08 +0200 Subject: [PATCH 03/22] clientmem: store more information about mappings --- src/cli/input.rs | 5 +- src/clientmem.rs | 58 +++++++++++++++++++--- src/ifs/jay_input.rs | 4 +- src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs | 2 +- src/ifs/wl_shm_pool.rs | 5 +- src/it/tests/t0040_virtual_keyboard.rs | 11 ++-- 6 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/cli/input.rs b/src/cli/input.rs index b41c2c4b..46625bd5 100644 --- a/src/cli/input.rs +++ b/src/cli/input.rs @@ -353,8 +353,9 @@ 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.raw(), map.keymap_len as _, true).unwrap()) - .offset(0); + let mem = + Rc::new(ClientMem::new(&map.keymap, map.keymap_len as _, true, 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 f85dc5e7..1c8e9c98 100644 --- a/src/clientmem.rs +++ b/src/clientmem.rs @@ -1,5 +1,5 @@ use { - crate::utils::vec_ext::VecExt, + crate::{client::Client, utils::vec_ext::VecExt}, std::{ cell::Cell, mem::MaybeUninit, @@ -8,7 +8,10 @@ use { sync::atomic::{compiler_fence, Ordering}, }, thiserror::Error, - uapi::{c, c::raise}, + uapi::{ + c::{self, raise}, + OwnedFd, + }, }; #[derive(Debug, Error)] @@ -22,6 +25,7 @@ pub enum ClientMemError { } pub struct ClientMem { + fd: Rc, failed: Cell, sigbus_impossible: bool, data: *const [Cell], @@ -30,19 +34,34 @@ pub struct ClientMem { #[derive(Clone)] pub struct ClientMemOffset { mem: Rc, + offset: usize, data: *const [Cell], } impl ClientMem { - pub fn new(fd: i32, len: usize, read_only: bool) -> Result { + pub fn new( + fd: &Rc, + len: usize, + read_only: bool, + client: Option<&Client>, + ) -> Result { let mut sigbus_impossible = false; - if let Ok(seals) = uapi::fcntl_get_seals(fd) { + if let Ok(seals) = uapi::fcntl_get_seals(fd.raw()) { if seals & c::F_SEAL_SHRINK != 0 { - if let Ok(stat) = uapi::fstat(fd) { + if let Ok(stat) = uapi::fstat(fd.raw()) { sigbus_impossible = stat.st_size as u64 >= len as u64; } } } + if !sigbus_impossible { + if let Some(client) = client { + log::debug!( + "Client {} ({}) has created a shm buffer that might cause SIGBUS", + client.pid_info.comm, + client.id, + ); + } + } let data = if len == 0 { &mut [][..] } else { @@ -51,7 +70,7 @@ impl ClientMem { false => c::PROT_READ | c::PROT_WRITE, }; unsafe { - let data = c::mmap64(ptr::null_mut(), len, prot, c::MAP_SHARED, fd, 0); + let data = c::mmap64(ptr::null_mut(), len, prot, c::MAP_SHARED, fd.raw(), 0); if data == c::MAP_FAILED { return Err(ClientMemError::MmapFailed(uapi::Errno::default().into())); } @@ -59,6 +78,7 @@ impl ClientMem { } }; Ok(Self { + fd: fd.clone(), failed: Cell::new(false), sigbus_impossible, data, @@ -73,12 +93,38 @@ impl ClientMem { let mem = unsafe { &*self.data }; ClientMemOffset { mem: self.clone(), + offset, data: &mem[offset..], } } + + #[expect(dead_code)] + pub fn fd(&self) -> &Rc { + &self.fd + } + + #[expect(dead_code)] + pub fn sigbus_impossible(&self) -> bool { + self.sigbus_impossible + } } impl ClientMemOffset { + #[expect(dead_code)] + pub fn pool(&self) -> &ClientMem { + &self.mem + } + + #[expect(dead_code)] + pub fn offset(&self) -> usize { + self.offset + } + + #[expect(dead_code)] + pub fn ptr(&self) -> *const [Cell] { + self.data + } + pub fn access]) -> T>(&self, f: F) -> Result { unsafe { if self.mem.sigbus_impossible { diff --git a/src/ifs/jay_input.rs b/src/ifs/jay_input.rs index f0362763..8d196063 100644 --- a/src/ifs/jay_input.rs +++ b/src/ifs/jay_input.rs @@ -165,11 +165,11 @@ impl JayInput { } } - fn set_keymap_impl(&self, keymap: &OwnedFd, len: u32, f: F) -> Result<(), JayInputError> + fn set_keymap_impl(&self, keymap: &Rc, len: u32, f: F) -> Result<(), JayInputError> where F: FnOnce(&Rc) -> Result<(), JayInputError>, { - let cm = Rc::new(ClientMem::new(keymap.raw(), len as _, true)?).offset(0); + let cm = Rc::new(ClientMem::new(keymap, len as _, true, Some(&self.client))?).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 2dde71f4..914ac247 100644 --- a/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs +++ b/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs @@ -56,7 +56,7 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 { if req.size > MAX_SIZE { return Err(ZwpVirtualKeyboardV1Error::OversizedKeymap); } - let client_mem = ClientMem::new(req.fd.raw(), req.size as usize - 1, true) + let client_mem = ClientMem::new(&req.fd, req.size as usize - 1, true, Some(&self.client)) .map(Rc::new) .map_err(ZwpVirtualKeyboardV1Error::MapKeymap)?; let mut map = vec![]; diff --git a/src/ifs/wl_shm_pool.rs b/src/ifs/wl_shm_pool.rs index 30687f6c..6ea0c670 100644 --- a/src/ifs/wl_shm_pool.rs +++ b/src/ifs/wl_shm_pool.rs @@ -34,7 +34,7 @@ impl WlShmPool { Ok(Self { id, client: client.clone(), - mem: CloneCell::new(Rc::new(ClientMem::new(fd.raw(), len, false)?)), + mem: CloneCell::new(Rc::new(ClientMem::new(&fd, len, false, Some(client))?)), fd, tracker: Default::default(), version, @@ -82,9 +82,10 @@ impl WlShmPoolRequestHandler for WlShmPool { return Err(WlShmPoolError::CannotShrink); } self.mem.set(Rc::new(ClientMem::new( - self.fd.raw(), + &self.fd, req.size as usize, false, + Some(&self.client), )?)); Ok(()) } diff --git a/src/it/tests/t0040_virtual_keyboard.rs b/src/it/tests/t0040_virtual_keyboard.rs index bf6519f2..bc0627c3 100644 --- a/src/it/tests/t0040_virtual_keyboard.rs +++ b/src/it/tests/t0040_virtual_keyboard.rs @@ -7,6 +7,7 @@ use { }, bstr::ByteSlice, std::rc::Rc, + uapi::OwnedFd, }; testcase!(); @@ -15,7 +16,7 @@ async fn test(run: Rc) -> TestResult { let virtual_keymap_str = { let xkb = XkbContext::new()?; let map = xkb.keymap_from_str(VIRTUAL_KEYMAP).unwrap(); - read_keymap(map.map.raw(), map.map_len) + read_keymap(&map.map, map.map_len) }; let ds = run.create_default_setup().await?; @@ -51,7 +52,7 @@ async fn test(run: Rc) -> TestResult { s_client.sync().await; let (start, keymap) = s_keymap.next().expect("virtual keymap"); tassert_eq!( - &read_keymap(keymap.fd.raw(), keymap.size as _), + &read_keymap(&keymap.fd, keymap.size as _), &virtual_keymap_str ); { @@ -119,7 +120,7 @@ async fn test(run: Rc) -> TestResult { s_client.sync().await; let (pos, keymap) = s_keymap.next().expect("seat keymap"); tassert_eq!(pos, start + 8); - tassert!(read_keymap(keymap.fd.raw(), keymap.size as _) != virtual_keymap_str); + tassert!(read_keymap(&keymap.fd, keymap.size as _) != virtual_keymap_str); { let (pos, mods) = s_modifiers.next().expect("mods 0"); tassert_eq!(pos, start + 9); @@ -147,8 +148,8 @@ async fn test(run: Rc) -> TestResult { Ok(()) } -fn read_keymap(fd: i32, size: usize) -> String { - let client_mem = ClientMem::new(fd, size - 1, true).unwrap(); +fn read_keymap(fd: &Rc, size: usize) -> String { + let client_mem = ClientMem::new(fd, size - 1, true, None).unwrap(); let client_mem = Rc::new(client_mem).offset(0); let mut v = vec![]; client_mem.read(&mut v).unwrap(); From 69c0cf4031030ebbaed3d8eeab45d9c4513f3946 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 17:01:22 +0200 Subject: [PATCH 04/22] fdclosor: assign name to thread --- src/utils/fdcloser.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/utils/fdcloser.rs b/src/utils/fdcloser.rs index fa5b4cac..32bb80aa 100644 --- a/src/utils/fdcloser.rs +++ b/src/utils/fdcloser.rs @@ -16,20 +16,23 @@ impl FdCloser { cv: Condvar::new(), }); let slf2 = slf.clone(); - std::thread::spawn(move || { - let mut fds = vec![]; - let mut lock = slf2.fds.lock(); - loop { - mem::swap(&mut *lock, &mut fds); - if fds.len() > 0 { - drop(lock); - fds.clear(); - lock = slf2.fds.lock(); - } else { - slf2.cv.wait(&mut lock); + std::thread::Builder::new() + .name("fd closer".to_string()) + .spawn(move || { + let mut fds = vec![]; + let mut lock = slf2.fds.lock(); + loop { + mem::swap(&mut *lock, &mut fds); + if fds.len() > 0 { + drop(lock); + fds.clear(); + lock = slf2.fds.lock(); + } else { + slf2.cv.wait(&mut lock); + } } - } - }); + }) + .unwrap(); slf } From e1d1fe7fda34eb8bb7f1ba722c840008e27fcefe Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 17:02:28 +0200 Subject: [PATCH 05/22] util: add OnDrop2 for non-copy closures --- src/utils/on_drop.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/utils/on_drop.rs b/src/utils/on_drop.rs index a7a12d79..15557f0a 100644 --- a/src/utils/on_drop.rs +++ b/src/utils/on_drop.rs @@ -1,4 +1,4 @@ -use std::mem; +use std::{mem, mem::ManuallyDrop}; pub struct OnDrop(pub F) where @@ -15,3 +15,34 @@ impl Drop for OnDrop { (self.0)(); } } + +pub struct OnDrop2 +where + F: FnOnce(), +{ + f: ManuallyDrop, +} + +impl OnDrop2 { + #[expect(dead_code)] + pub fn new(f: F) -> Self { + Self { + f: ManuallyDrop::new(f), + } + } + + #[expect(dead_code)] + pub fn forget(mut self) { + unsafe { + ManuallyDrop::drop(&mut self.f); + } + mem::forget(self); + } +} + +impl Drop for OnDrop2 { + fn drop(&mut self) { + let f = unsafe { ManuallyDrop::take(&mut self.f) }; + f(); + } +} From 6cbf6119de53eaddb6bfd6e9d472d7bafada683c Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 17:05:43 +0200 Subject: [PATCH 06/22] io_uring: use strongly typed ids --- src/io_uring.rs | 35 ++++++++++++++++++++------------ src/io_uring/ops/accept.rs | 6 +++--- src/io_uring/ops/async_cancel.rs | 12 +++++------ src/io_uring/ops/connect.rs | 8 ++++---- src/io_uring/ops/poll.rs | 6 +++--- src/io_uring/ops/read_write.rs | 6 +++--- src/io_uring/ops/recvmsg.rs | 8 ++++---- src/io_uring/ops/sendmsg.rs | 8 ++++---- src/io_uring/ops/timeout.rs | 6 +++--- src/io_uring/ops/timeout_link.rs | 6 +++--- 10 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/io_uring.rs b/src/io_uring.rs index baf4c934..23b8749d 100644 --- a/src/io_uring.rs +++ b/src/io_uring.rs @@ -22,7 +22,6 @@ use { copyhashmap::CopyHashMap, errorfmt::ErrorFmt, mmap::{mmap, Mmapped}, - numcell::NumCell, oserror::OsError, ptr_ext::{MutPtrExt, PtrExt}, stack::Stack, @@ -254,10 +253,10 @@ struct IoUringData { cqes_consumed: AsyncEvent, - next: NumCell, - to_encode: SyncQueue, - pending_in_kernel: CopyHashMap, - tasks: CopyHashMap>, + next: IoUringTaskIds, + to_encode: SyncQueue, + pending_in_kernel: CopyHashMap, + tasks: CopyHashMap>, pending_results: PendingResults, @@ -276,7 +275,7 @@ struct IoUringData { } unsafe trait Task { - fn id(&self) -> u64; + fn id(&self) -> IoUringTaskId; fn complete(self: Box, ring: &IoUringData, res: i32); fn encode(&self, sqe: &mut io_uring_sqe); @@ -347,8 +346,9 @@ impl IoUringData { let entry = self.cqmap.deref()[idx].get(); head = head.wrapping_add(1); self.cqhead.deref().store(head, Release); - if let Some(pending) = self.tasks.remove(&entry.user_data) { - self.pending_in_kernel.remove(&entry.user_data); + let id = IoUringTaskId(entry.user_data); + if let Some(pending) = self.tasks.remove(&id) { + self.pending_in_kernel.remove(&id); pending.complete(self, entry.res); } } @@ -384,7 +384,7 @@ impl IoUringData { let sqe = self.sqesmap.deref()[idx].get().deref_mut(); self.sqmap.deref()[idx].set(idx as _); *sqe = Default::default(); - sqe.user_data = id; + sqe.user_data = id.raw(); task.encode(sqe); if has_timeout { sqe.flags |= IOSQE_IO_LINK; @@ -404,11 +404,11 @@ impl IoUringData { } } - fn id_raw(&self) -> u64 { - self.next.fetch_add(1) + fn id_raw(&self) -> IoUringTaskId { + self.next.next() } - fn cancel_task(&self, id: u64) { + fn cancel_task(&self, id: IoUringTaskId) { if !self.tasks.contains(&id) { return; } @@ -466,8 +466,17 @@ impl IoUringData { } } +linear_ids!(IoUringTaskIds, IoUringTaskId, u64); + +#[expect(clippy::derivable_impls)] +impl Default for IoUringTaskId { + fn default() -> Self { + Self(0) + } +} + struct Cancellable<'a> { - id: u64, + id: IoUringTaskId, data: &'a IoUringData, } diff --git a/src/io_uring/ops/accept.rs b/src/io_uring/ops/accept.rs index 6f751dcf..149592ea 100644 --- a/src/io_uring/ops/accept.rs +++ b/src/io_uring/ops/accept.rs @@ -2,7 +2,7 @@ use { crate::io_uring::{ pending_result::PendingResult, sys::{io_uring_sqe, IORING_OP_ACCEPT}, - IoUring, IoUringData, IoUringError, Task, TaskResultExt, + IoUring, IoUringData, IoUringError, IoUringTaskId, Task, TaskResultExt, }, std::rc::Rc, uapi::{c, OwnedFd}, @@ -39,14 +39,14 @@ struct Data { #[derive(Default)] pub struct AcceptTask { - id: u64, + id: IoUringTaskId, fd: i32, flags: u32, data: Option, } unsafe impl Task for AcceptTask { - fn id(&self) -> u64 { + fn id(&self) -> IoUringTaskId { self.id } diff --git a/src/io_uring/ops/async_cancel.rs b/src/io_uring/ops/async_cancel.rs index d322fd3b..3874ab98 100644 --- a/src/io_uring/ops/async_cancel.rs +++ b/src/io_uring/ops/async_cancel.rs @@ -2,7 +2,7 @@ use { crate::{ io_uring::{ sys::{io_uring_sqe, IORING_OP_ASYNC_CANCEL}, - IoUringData, Task, + IoUringData, IoUringTaskId, Task, }, utils::errorfmt::ErrorFmt, }, @@ -11,12 +11,12 @@ use { #[derive(Default)] pub struct AsyncCancelTask { - id: u64, - target: u64, + id: IoUringTaskId, + target: IoUringTaskId, } impl IoUringData { - pub fn cancel_task_in_kernel(&self, target: u64) { + pub fn cancel_task_in_kernel(&self, target: IoUringTaskId) { let id = self.id_raw(); let mut task = self.cached_cancels.pop().unwrap_or_default(); task.id = id; @@ -26,7 +26,7 @@ impl IoUringData { } unsafe impl Task for AsyncCancelTask { - fn id(&self) -> u64 { + fn id(&self) -> IoUringTaskId { self.id } @@ -41,7 +41,7 @@ unsafe impl Task for AsyncCancelTask { fn encode(&self, sqe: &mut io_uring_sqe) { sqe.opcode = IORING_OP_ASYNC_CANCEL; - sqe.u2.addr = self.target; + sqe.u2.addr = self.target.raw(); } fn is_cancel(&self) -> bool { diff --git a/src/io_uring/ops/connect.rs b/src/io_uring/ops/connect.rs index 0aca6829..a23d460e 100644 --- a/src/io_uring/ops/connect.rs +++ b/src/io_uring/ops/connect.rs @@ -2,7 +2,7 @@ use { crate::io_uring::{ pending_result::PendingResult, sys::{io_uring_sqe, IORING_OP_CONNECT}, - IoUring, IoUringData, IoUringError, Task, TaskResultExt, + IoUring, IoUringData, IoUringError, IoUringTaskId, Task, TaskResultExt, }, std::{mem, ptr, rc::Rc}, uapi::{c, OwnedFd, SockAddr}, @@ -37,7 +37,7 @@ struct Data { } pub struct ConnectTask { - id: u64, + id: IoUringTaskId, fd: i32, sockaddr: c::sockaddr_storage, addrlen: u64, @@ -47,7 +47,7 @@ pub struct ConnectTask { impl Default for ConnectTask { fn default() -> Self { Self { - id: 0, + id: Default::default(), fd: 0, sockaddr: uapi::pod_zeroed(), addrlen: 0, @@ -57,7 +57,7 @@ impl Default for ConnectTask { } unsafe impl Task for ConnectTask { - fn id(&self) -> u64 { + fn id(&self) -> IoUringTaskId { self.id } diff --git a/src/io_uring/ops/poll.rs b/src/io_uring/ops/poll.rs index 6edab2d4..1ac45281 100644 --- a/src/io_uring/ops/poll.rs +++ b/src/io_uring/ops/poll.rs @@ -3,7 +3,7 @@ use { ops::TaskResult, pending_result::PendingResult, sys::{io_uring_sqe, IORING_OP_POLL_ADD}, - IoUring, IoUringData, IoUringError, Task, TaskResultExt, + IoUring, IoUringData, IoUringError, IoUringTaskId, Task, TaskResultExt, }, std::rc::Rc, uapi::{c, OwnedFd}, @@ -45,14 +45,14 @@ struct Data { #[derive(Default)] pub struct PollTask { - id: u64, + id: IoUringTaskId, events: u16, fd: i32, data: Option, } unsafe impl Task for PollTask { - fn id(&self) -> u64 { + fn id(&self) -> IoUringTaskId { self.id } diff --git a/src/io_uring/ops/read_write.rs b/src/io_uring/ops/read_write.rs index 9ebf2c1d..f8db92cb 100644 --- a/src/io_uring/ops/read_write.rs +++ b/src/io_uring/ops/read_write.rs @@ -3,7 +3,7 @@ use { io_uring::{ pending_result::PendingResult, sys::{io_uring_sqe, IORING_OP_READ, IORING_OP_WRITE}, - IoUring, IoUringData, IoUringError, Task, TaskResultExt, + IoUring, IoUringData, IoUringError, IoUringTaskId, Task, TaskResultExt, }, time::Time, utils::buf::Buf, @@ -66,7 +66,7 @@ struct ReadWriteTaskData { #[derive(Default)] pub struct ReadWriteTask { - id: u64, + id: IoUringTaskId, has_timeout: bool, fd: c::c_int, buf: usize, @@ -76,7 +76,7 @@ pub struct ReadWriteTask { } unsafe impl Task for ReadWriteTask { - fn id(&self) -> u64 { + fn id(&self) -> IoUringTaskId { self.id } diff --git a/src/io_uring/ops/recvmsg.rs b/src/io_uring/ops/recvmsg.rs index 4196f8d4..6bea0d09 100644 --- a/src/io_uring/ops/recvmsg.rs +++ b/src/io_uring/ops/recvmsg.rs @@ -3,7 +3,7 @@ use { io_uring::{ pending_result::PendingResult, sys::{io_uring_sqe, IORING_OP_RECVMSG}, - IoUring, IoUringData, IoUringError, Task, + IoUring, IoUringData, IoUringError, IoUringTaskId, Task, }, utils::buf::Buf, }, @@ -85,7 +85,7 @@ struct Data { } pub struct RecvmsgTask { - id: u64, + id: IoUringTaskId, fd: c::c_int, bufs: Vec, iovecs: Vec, @@ -97,7 +97,7 @@ pub struct RecvmsgTask { impl Default for RecvmsgTask { fn default() -> Self { RecvmsgTask { - id: 0, + id: Default::default(), fd: 0, bufs: vec![], iovecs: vec![], @@ -109,7 +109,7 @@ impl Default for RecvmsgTask { } unsafe impl Task for RecvmsgTask { - fn id(&self) -> u64 { + fn id(&self) -> IoUringTaskId { self.id } diff --git a/src/io_uring/ops/sendmsg.rs b/src/io_uring/ops/sendmsg.rs index 23cb7a8f..67d7b4e8 100644 --- a/src/io_uring/ops/sendmsg.rs +++ b/src/io_uring/ops/sendmsg.rs @@ -3,7 +3,7 @@ use { io_uring::{ pending_result::PendingResult, sys::{io_uring_sqe, IORING_OP_SENDMSG}, - IoUring, IoUringData, IoUringError, Task, + IoUring, IoUringData, IoUringError, IoUringTaskId, Task, }, time::Time, utils::{buf::Buf, vec_ext::UninitVecExt}, @@ -91,7 +91,7 @@ struct SendmsgTaskData { } pub struct SendmsgTask { - id: u64, + id: IoUringTaskId, iovecs: Vec, msghdr: c::msghdr, bufs: Vec, @@ -106,7 +106,7 @@ impl Default for SendmsgTask { fn default() -> Self { unsafe { SendmsgTask { - id: 0, + id: Default::default(), iovecs: vec![], msghdr: MaybeUninit::zeroed().assume_init(), bufs: vec![], @@ -121,7 +121,7 @@ impl Default for SendmsgTask { } unsafe impl Task for SendmsgTask { - fn id(&self) -> u64 { + fn id(&self) -> IoUringTaskId { self.id } diff --git a/src/io_uring/ops/timeout.rs b/src/io_uring/ops/timeout.rs index 3567a56f..e8067c61 100644 --- a/src/io_uring/ops/timeout.rs +++ b/src/io_uring/ops/timeout.rs @@ -2,7 +2,7 @@ use { crate::io_uring::{ pending_result::PendingResult, sys::{io_uring_sqe, IORING_OP_TIMEOUT, IORING_TIMEOUT_ABS}, - IoUring, IoUringData, IoUringError, Task, + IoUring, IoUringData, IoUringError, IoUringTaskId, Task, }, uapi::c, }; @@ -16,7 +16,7 @@ pub(super) struct timespec64 { #[derive(Default)] pub struct TimeoutTask { - id: u64, + id: IoUringTaskId, timespec: timespec64, pr: Option, } @@ -42,7 +42,7 @@ impl IoUring { } unsafe impl Task for TimeoutTask { - fn id(&self) -> u64 { + fn id(&self) -> IoUringTaskId { self.id } diff --git a/src/io_uring/ops/timeout_link.rs b/src/io_uring/ops/timeout_link.rs index aabaa421..023fbd99 100644 --- a/src/io_uring/ops/timeout_link.rs +++ b/src/io_uring/ops/timeout_link.rs @@ -2,14 +2,14 @@ use crate::{ io_uring::{ ops::timeout::timespec64, sys::{io_uring_sqe, IORING_OP_LINK_TIMEOUT, IORING_TIMEOUT_ABS}, - IoUring, IoUringData, Task, + IoUring, IoUringData, IoUringTaskId, Task, }, time::Time, }; #[derive(Default)] pub struct TimeoutLinkTask { - id: u64, + id: IoUringTaskId, timespec: timespec64, } @@ -27,7 +27,7 @@ impl IoUring { } unsafe impl Task for TimeoutLinkTask { - fn id(&self) -> u64 { + fn id(&self) -> IoUringTaskId { self.id } From 5b36980e72669b4850fa0c06f18597dbc85a1b30 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 17:09:12 +0200 Subject: [PATCH 07/22] io_uring: allow manually cancelling tasks --- src/io_uring.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/io_uring.rs b/src/io_uring.rs index 23b8749d..f5bd6b68 100644 --- a/src/io_uring.rs +++ b/src/io_uring.rs @@ -228,6 +228,11 @@ impl IoUring { self.ring.kill(); res } + + #[expect(dead_code)] + pub fn cancel(&self, id: IoUringTaskId) { + self.ring.cancel_task(id); + } } struct IoUringData { From 874d0d0c59d41e1506493fbc1a4cb1e1f328a89c Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Sep 2024 17:11:19 +0200 Subject: [PATCH 08/22] io_uring: add ops for non-owning read/write operations --- src/io_uring.rs | 5 +- src/io_uring/ops.rs | 1 + src/io_uring/ops/read_write_no_cancel.rs | 139 ++++++++++++++++++ .../ops/read_write_no_cancel/tests.rs | 50 +++++++ 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 src/io_uring/ops/read_write_no_cancel.rs create mode 100644 src/io_uring/ops/read_write_no_cancel/tests.rs diff --git a/src/io_uring.rs b/src/io_uring.rs index f5bd6b68..865634e4 100644 --- a/src/io_uring.rs +++ b/src/io_uring.rs @@ -5,7 +5,8 @@ use { io_uring::{ ops::{ accept::AcceptTask, async_cancel::AsyncCancelTask, connect::ConnectTask, - poll::PollTask, read_write::ReadWriteTask, recvmsg::RecvmsgTask, + poll::PollTask, read_write::ReadWriteTask, + read_write_no_cancel::ReadWriteNoCancelTask, recvmsg::RecvmsgTask, sendmsg::SendmsgTask, timeout::TimeoutTask, timeout_link::TimeoutLinkTask, }, pending_result::PendingResults, @@ -205,6 +206,7 @@ impl IoUring { tasks: Default::default(), pending_results: Default::default(), cached_read_writes: Default::default(), + cached_read_writes_no_cancel: Default::default(), cached_cancels: Default::default(), cached_polls: Default::default(), cached_sendmsg: Default::default(), @@ -266,6 +268,7 @@ struct IoUringData { pending_results: PendingResults, cached_read_writes: Stack>, + cached_read_writes_no_cancel: Stack>, cached_cancels: Stack>, cached_polls: Stack>, cached_sendmsg: Stack>, diff --git a/src/io_uring/ops.rs b/src/io_uring/ops.rs index 64ea36b7..15fc1235 100644 --- a/src/io_uring/ops.rs +++ b/src/io_uring/ops.rs @@ -5,6 +5,7 @@ pub mod async_cancel; pub mod connect; pub mod poll; pub mod read_write; +pub mod read_write_no_cancel; pub mod recvmsg; pub mod sendmsg; pub mod timeout; diff --git a/src/io_uring/ops/read_write_no_cancel.rs b/src/io_uring/ops/read_write_no_cancel.rs new file mode 100644 index 00000000..16729de7 --- /dev/null +++ b/src/io_uring/ops/read_write_no_cancel.rs @@ -0,0 +1,139 @@ +#[cfg(test)] +mod tests; + +use { + crate::{ + io_uring::{ + pending_result::PendingResult, + sys::{io_uring_sqe, IORING_OP_READ, IORING_OP_WRITE}, + IoUring, IoUringData, IoUringError, IoUringTaskId, Task, TaskResultExt, + }, + time::Time, + utils::on_drop::OnDrop, + }, + uapi::{c, Fd}, +}; + +impl IoUring { + #[expect(dead_code)] + pub async fn read_no_cancel( + &self, + fd: Fd, + offset: usize, + buf: &mut [u8], + cancel: impl FnOnce(IoUringTaskId), + ) -> Result { + self.perform_no_cancel( + fd, + offset, + buf.as_mut_ptr(), + buf.len(), + None, + IORING_OP_READ, + cancel, + ) + .await + } + + #[expect(dead_code)] + pub async fn write_no_cancel( + &self, + fd: Fd, + offset: usize, + buf: &[u8], + timeout: Option