diff --git a/changelog/2741.changed.md b/changelog/2741.changed.md new file mode 100644 index 0000000000..09555bd50e --- /dev/null +++ b/changelog/2741.changed.md @@ -0,0 +1,9 @@ +In both the inotify and fanotify `read_events(...)` APIs: + +Remove logic with `MaybeUninit` + `ptr::copy_nonoverlapping` and use `ptr::read_unaligned`, leaving the code more concise and clean on both sides, without the redundant check using `.min()` + +Use `Vec::with_capacity(nread / size)` instead of allocating empty space. Useful for increasing performance in case of event bursts. Allocates space to spare, but is still more performant than allocating almost empty space + +In inotify `read_events`: + +Reduce the event name iteration window to the maximum byte size (which is `event.len`), without risking reading beyond the event name in any way and without needing to scan again using `CStr::from_ptr` and increasing perfomance diff --git a/src/sys/fanotify.rs b/src/sys/fanotify.rs index 0b5e43f30d..b9bbe6a1d1 100644 --- a/src/sys/fanotify.rs +++ b/src/sys/fanotify.rs @@ -15,7 +15,7 @@ use crate::fcntl::OFlag; use crate::unistd::{close, read, write}; use crate::{NixPath, Result}; use std::marker::PhantomData; -use std::mem::{size_of, MaybeUninit}; +use std::mem::{size_of}; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}; use std::ptr; @@ -358,21 +358,18 @@ impl Fanotify { let metadata_size = size_of::(); const BUFSIZ: usize = 4096; let mut buffer = [0u8; BUFSIZ]; - let mut events = Vec::new(); let mut offset = 0; let nread = read(&self.fd, &mut buffer)?; + let mut events = Vec::with_capacity(nread / metadata_size); + while (nread - offset) >= metadata_size { let metadata = unsafe { - let mut metadata = - MaybeUninit::::uninit(); - ptr::copy_nonoverlapping( - buffer.as_ptr().add(offset), - metadata.as_mut_ptr().cast(), - (BUFSIZ - offset).min(metadata_size), - ); - metadata.assume_init() + ptr::read_unaligned( + buffer.as_ptr().add(offset) + as *const libc::fanotify_event_metadata, + ) }; events.push(FanotifyEvent(metadata)); diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs index 0cc65f41a6..4b223d890c 100644 --- a/src/sys/inotify.rs +++ b/src/sys/inotify.rs @@ -28,9 +28,9 @@ use crate::unistd::read; use crate::NixPath; use crate::Result; use cfg_if::cfg_if; -use libc::{c_char, c_int}; -use std::ffi::{CStr, OsStr, OsString}; -use std::mem::{size_of, MaybeUninit}; +use libc::c_int; +use std::ffi::{OsStr, OsString}; +use std::mem::size_of; use std::os::unix::ffi::OsStrExt; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}; use std::ptr; @@ -204,33 +204,32 @@ impl Inotify { let header_size = size_of::(); const BUFSIZ: usize = 4096; let mut buffer = [0u8; BUFSIZ]; - let mut events = Vec::new(); - let mut offset = 0; let nread = read(&self.fd, &mut buffer)?; + let mut events = Vec::with_capacity(nread / header_size); + let mut offset = 0; + while (nread - offset) >= header_size { let event = unsafe { - let mut event = MaybeUninit::::uninit(); - ptr::copy_nonoverlapping( - buffer.as_ptr().add(offset), - event.as_mut_ptr().cast(), - (BUFSIZ - offset).min(header_size), - ); - event.assume_init() + ptr::read_unaligned( + buffer.as_ptr().add(offset) + as *const libc::inotify_event, + ) }; - let name = match event.len { - 0 => None, - _ => { - let ptr = unsafe { - buffer.as_ptr().add(offset + header_size) - as *const c_char - }; - let cstr = unsafe { CStr::from_ptr(ptr) }; + let name = if event.len == 0 { + None + } else { + let name_start = offset + header_size; + let name_bytes = + &buffer[name_start..name_start + event.len as usize]; - Some(OsStr::from_bytes(cstr.to_bytes()).to_owned()) - } + let len = name_bytes + .iter() + .position(|&b| b == 0) + .unwrap_or(name_bytes.len()); + Some(OsStr::from_bytes(&name_bytes[..len]).to_owned()) }; events.push(InotifyEvent {