Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions changelog/2741.changed.md
Original file line number Diff line number Diff line change
@@ -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
17 changes: 7 additions & 10 deletions src/sys/fanotify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -358,21 +358,18 @@ impl Fanotify {
let metadata_size = size_of::<libc::fanotify_event_metadata>();
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::<libc::fanotify_event_metadata>::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));
Expand Down
43 changes: 21 additions & 22 deletions src/sys/inotify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -204,33 +204,32 @@ impl Inotify {
let header_size = size_of::<libc::inotify_event>();
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::<libc::inotify_event>::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 {
Expand Down