Skip to content

Commit 9b60fbe

Browse files
committed
Introduce a new Buffer trait.
Using the idea from #908 and #1110, introduce a new `Buffer` trait for reading into possibly uninitialized buffers, and use it in `read`, `recv`, `epoll::wait`, `kqueue`, `getxattr`, and several other functions. This eliminates the need for separate `*_uninit` functions
1 parent 3b0e286 commit 9b60fbe

38 files changed

+896
-563
lines changed

CHANGES.md

+30
Original file line numberDiff line numberDiff line change
@@ -273,5 +273,35 @@ a `[MaybeUninit<u8>]` instead of a `[u8]`.
273273
[`SendAncillaryBuffer`]: https://docs.rs/rustix/1.0.0/rustix/net/struct.SendAncillaryBuffer.html
274274
[`RecvAncillaryBuffer`]: https://docs.rs/rustix/1.0.0/rustix/net/struct.RecvAncillaryBuffer.html
275275

276+
[`read`], [`pread`], [`recv`], [`recvfrom`], [`getrandom`], [`epoll::wait`],
277+
[`kqueue`], [`getxattr`], [`lgetxattr`], [`fgetxattr`], [`listxattr`],
278+
[`llistxattr`], and [`flistxattr`] now use the new [`Buffer` trait].
279+
280+
This replaces `read_uninit`, `pread_uninit`, `recv_uninit`, `recvfrom_uninit`,
281+
and `getrandom_uninit`, as the `Buffer` trait supports reading into
282+
uninitialized slices.
283+
284+
`epoll::wait` and `kqueue` previously took a `Vec` which it implicitly cleared
285+
before results were appended. When passing a `Vec` to `epoll::wait` or `kqueue`
286+
using [`spare_capacity`], the `Vec` is not cleared first. Consider clearing the
287+
vector before calling `epoll::wait` or `kqueue`, or consuming it using
288+
`.drain(..)` before reusing it.
289+
290+
[`read`]: https://docs.rs/rustix/1.0.0/rustix/io/fn.read.html
291+
[`pread`]: https://docs.rs/rustix/1.0.0/rustix/io/fn.pread.html
292+
[`recv`]: https://docs.rs/rustix/1.0.0/rustix/net/fn.recv.html
293+
[`recvfrom`]: https://docs.rs/rustix/1.0.0/rustix/net/fn.recvfrom.html
294+
[`getrandom`]: https://docs.rs/rustix/1.0.0/rustix/rand/fn.getrandom.html
295+
[`epoll::wait`]: https://docs.rs/rustix/1.0.0/rustix/event/epoll/fn.wait.html
296+
[`getxattr`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.getxattr.html
297+
[`lgetxattr`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.lgetxattr.html
298+
[`fgetxattr`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.fgetxattr.html
299+
[`listxattr`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.listxattr.html
300+
[`llistxattr`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.llistxattr.html
301+
[`flistxattr`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.flistxattr.html
302+
[`kqueue`]: https://docs.rs/rustix/1.0.0/x86_64-unknown-freebsd/rustix/event/kqueue/fn.kqueue.html
303+
[`Buffer` trait]: https://docs.rs/rustix/1.0.0/rustix/buffer/trait.Buffer.html
304+
[`spare_capacity`]: https://docs.rs/rustix/1.0.0/rustix/buffer/fn.spare_capacity.html
305+
276306
All explicitly deprecated functions and types have been removed. Their
277307
deprecation messages will have identified alternatives.

examples/kq.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
#[cfg(all(bsd, feature = "event"))]
44
fn main() -> std::io::Result<()> {
5+
use rustix::buffer::spare_capacity;
56
use rustix::event::kqueue::*;
67
#[cfg(feature = "fs")]
78
use rustix::{fd::AsRawFd, fs};
@@ -60,7 +61,7 @@ fn main() -> std::io::Result<()> {
6061
eprintln!("Run with --features process to enable more!");
6162
#[cfg(not(feature = "fs"))]
6263
eprintln!("Run with --features fs to enable more!");
63-
unsafe { kevent(&kq, &subs, &mut out, None) }?;
64+
unsafe { kevent(&kq, &subs, spare_capacity(&mut out), None) }?;
6465

6566
loop {
6667
while let Some(e) = out.pop() {
@@ -80,7 +81,7 @@ fn main() -> std::io::Result<()> {
8081
_ => eprintln!("Unknown event"),
8182
}
8283
}
83-
unsafe { kevent(&kq, &[], &mut out, None) }?;
84+
unsafe { kevent(&kq, &[], spare_capacity(&mut out), None) }?;
8485
}
8586
}
8687

src/backend/libc/event/syscalls.rs

+15-24
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use crate::backend::c;
44
#[cfg(any(linux_kernel, solarish, target_os = "redox"))]
55
use crate::backend::conv::ret;
66
use crate::backend::conv::ret_c_int;
7-
#[cfg(feature = "alloc")]
87
#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
98
use crate::backend::conv::ret_u32;
109
#[cfg(solarish)]
@@ -24,11 +23,7 @@ use crate::io;
2423
use crate::utils::as_mut_ptr;
2524
#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
2625
use crate::utils::as_ptr;
27-
#[cfg(any(
28-
all(feature = "alloc", bsd),
29-
solarish,
30-
all(feature = "alloc", any(linux_kernel, target_os = "redox")),
31-
))]
26+
#[cfg(solarish)]
3227
use core::mem::MaybeUninit;
3328
#[cfg(any(
3429
bsd,
@@ -107,7 +102,7 @@ pub(crate) fn kqueue() -> io::Result<OwnedFd> {
107102
pub(crate) unsafe fn kevent(
108103
kq: BorrowedFd<'_>,
109104
changelist: &[Event],
110-
eventlist: &mut [MaybeUninit<Event>],
105+
eventlist: (*mut Event, usize),
111106
timeout: Option<&c::timespec>,
112107
) -> io::Result<c::c_int> {
113108
ret_c_int(c::kevent(
@@ -117,11 +112,8 @@ pub(crate) unsafe fn kevent(
117112
.len()
118113
.try_into()
119114
.map_err(|_| io::Errno::OVERFLOW)?,
120-
eventlist.as_mut_ptr().cast(),
121-
eventlist
122-
.len()
123-
.try_into()
124-
.map_err(|_| io::Errno::OVERFLOW)?,
115+
eventlist.0.cast(),
116+
eventlist.1.try_into().map_err(|_| io::Errno::OVERFLOW)?,
125117
timeout.map_or(null(), as_ptr),
126118
))
127119
}
@@ -512,11 +504,10 @@ pub(crate) fn epoll_del(epoll: BorrowedFd<'_>, source: BorrowedFd<'_>) -> io::Re
512504
}
513505

514506
#[inline]
515-
#[cfg(feature = "alloc")]
516507
#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
517-
pub(crate) fn epoll_wait(
508+
pub(crate) unsafe fn epoll_wait(
518509
epoll: BorrowedFd<'_>,
519-
events: &mut [MaybeUninit<crate::event::epoll::Event>],
510+
events: (*mut crate::event::epoll::Event, usize),
520511
timeout: Option<&Timespec>,
521512
) -> io::Result<usize> {
522513
// If we're on Linux >= 5.11 and a libc that has an `epoll_pwait2`
@@ -527,7 +518,7 @@ pub(crate) fn epoll_wait(
527518
target_env = "gnu",
528519
not(fix_y2038)
529520
))]
530-
unsafe {
521+
{
531522
weak! {
532523
fn epoll_pwait2(
533524
c::c_int,
@@ -541,8 +532,8 @@ pub(crate) fn epoll_wait(
541532
if let Some(epoll_pwait2_func) = epoll_pwait2.get() {
542533
return ret_u32(epoll_pwait2_func(
543534
borrowed_fd(epoll),
544-
events.as_mut_ptr().cast::<c::epoll_event>(),
545-
events.len().try_into().unwrap_or(i32::MAX),
535+
events.0.cast::<c::epoll_event>(),
536+
events.1.try_into().unwrap_or(i32::MAX),
546537
crate::utils::option_as_ptr(timeout).cast(),
547538
null(),
548539
))
@@ -552,7 +543,7 @@ pub(crate) fn epoll_wait(
552543

553544
// If we're on Linux >= 5.11, use `epoll_pwait2` via `libc::syscall`.
554545
#[cfg(all(linux_kernel, feature = "linux_5_11"))]
555-
unsafe {
546+
{
556547
use linux_raw_sys::general::__kernel_timespec as timespec;
557548

558549
syscall! {
@@ -567,8 +558,8 @@ pub(crate) fn epoll_wait(
567558

568559
ret_u32(epoll_pwait2(
569560
borrowed_fd(epoll),
570-
events.as_mut_ptr().cast::<c::epoll_event>(),
571-
events.len().try_into().unwrap_or(i32::MAX),
561+
events.0.cast::<c::epoll_event>(),
562+
events.1.try_into().unwrap_or(i32::MAX),
572563
crate::utils::option_as_ptr(timeout).cast(),
573564
null(),
574565
))
@@ -577,16 +568,16 @@ pub(crate) fn epoll_wait(
577568

578569
// Otherwise just use `epoll_wait`.
579570
#[cfg(not(all(linux_kernel, feature = "linux_5_11")))]
580-
unsafe {
571+
{
581572
let timeout = match timeout {
582573
None => -1,
583574
Some(timeout) => timeout.as_c_int_millis().ok_or(io::Errno::INVAL)?,
584575
};
585576

586577
ret_u32(c::epoll_wait(
587578
borrowed_fd(epoll),
588-
events.as_mut_ptr().cast::<c::epoll_event>(),
589-
events.len().try_into().unwrap_or(i32::MAX),
579+
events.0.cast::<c::epoll_event>(),
580+
events.1.try_into().unwrap_or(i32::MAX),
590581
timeout,
591582
))
592583
.map(|i| i as usize)

0 commit comments

Comments
 (0)