Skip to content

Commit 6cc0166

Browse files
authored
Convert port::nget to Buffer. (#1361)
And, change `port::*` to use Timespec for timeouts, consistent with the other polling functions in rustix.
1 parent 3602b47 commit 6cc0166

3 files changed

Lines changed: 108 additions & 83 deletions

File tree

CHANGES.md

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ greater than the requested size.
77

88
[`rustix::pipe::fcntl_setpipe_size`]: https://docs.rs/rustix/1.0.0/rustix/pipe/fn.fcntl_setpipe_size.html
99

10-
When a `&mut Vec<_>` is passed to [`rustix::event::epoll::wait`] or
11-
[`rustix::event::kqueue::kevent`], these functions previously adjusted the
12-
length of the `Vec` to the number of elements written, and now do not. A common
13-
alternative is to wrap the `&mut Vec<_>` using [`spare_capacity`], and then to
14-
clear the `Vec` by iterating using `.drain(..)` after each call. For an example
15-
of using `spare_capacity` in this way, see [here].
10+
When a `&mut Vec<_>` is passed to [`rustix::event::epoll::wait`],
11+
[`rustix::event::kqueue::kevent`], or [`rustix::event::port::getn`], these
12+
functions previously adjusted the length of the `Vec` to the number of elements
13+
written, and now do not. A common alternative is to wrap the `&mut Vec<_>`
14+
using [`spare_capacity`], and then to clear the `Vec` by iterating using
15+
`.drain(..)` after each call. For an example of using `spare_capacity` in this
16+
way, see [here].
1617

1718
[`rustix::event::epoll::wait`]: https://docs.rs/rustix/1.0.0/rustix/event/epoll/fn.wait.html
18-
[`rustix::event::kqueue::kevent`]: https://docs.rs/rustix/1.0.0/x86_64-unknown-freebsd/rustix/event/kqueue/fn.kqueue.html
19+
[`rustix::event::kqueue::kevent`]: https://docs.rs/rustix/1.0.0/x86_64-unknown-freebsd/rustix/event/kqueue/fn.kevent.html
20+
[`rustix::event::port::getn`]: https://docs.rs/rustix/1.0.0/x86_64-unknown-illumos/rustix/event/port/fn.getn.html
1921
[`spare_capacity`]: https://docs.rs/rustix/1.0.0/rustix/buffer/fn.spare_capacity.html
2022
[here]: https://docs.rs/rustix/1.0.0/rustix/event/epoll/index.html#examples
2123

@@ -287,18 +289,19 @@ a `[MaybeUninit<u8>]` instead of a `[u8]`.
287289
[`RecvAncillaryBuffer`]: https://docs.rs/rustix/1.0.0/rustix/net/struct.RecvAncillaryBuffer.html
288290

289291
[`read`], [`pread`], [`recv`], [`recvfrom`], [`getrandom`], [`epoll::wait`],
290-
[`kqueue`], [`getxattr`], [`lgetxattr`], [`fgetxattr`], [`listxattr`],
291-
[`llistxattr`], and [`flistxattr`] now use the new [`Buffer` trait].
292+
[`kevent`], [`port::getn`], [`getxattr`], [`lgetxattr`], [`fgetxattr`],
293+
[`listxattr`], [`llistxattr`], and [`flistxattr`] now use the new
294+
[`Buffer` trait].
292295

293296
This replaces `read_uninit`, `pread_uninit`, `recv_uninit`, `recvfrom_uninit`,
294297
and `getrandom_uninit`, as the `Buffer` trait supports reading into
295298
uninitialized slices.
296299

297-
`epoll::wait` and `kqueue` previously took a `Vec` which it implicitly cleared
298-
before results were appended. When passing a `Vec` to `epoll::wait` or `kqueue`
299-
using [`spare_capacity`], the `Vec` is not cleared first. Consider clearing the
300-
vector before calling `epoll::wait` or `kqueue`, or consuming it using
301-
`.drain(..)` before reusing it.
300+
`epoll::wait`, `kevent`, and `port::getn` previously took a `Vec` which they
301+
implicitly cleared before results were appended. When passing a `Vec` to
302+
`epoll::wait`, `kevent`, or `port::getn` using [`spare_capacity`], the `Vec` is
303+
not cleared first. Consider clearing the vector before calling `epoll::wait`,
304+
`kevent`, or `port::getn`, or consuming it using `.drain(..)` before reusing it.
302305

303306
[`read`]: https://docs.rs/rustix/1.0.0/rustix/io/fn.read.html
304307
[`pread`]: https://docs.rs/rustix/1.0.0/rustix/io/fn.pread.html
@@ -312,7 +315,8 @@ vector before calling `epoll::wait` or `kqueue`, or consuming it using
312315
[`listxattr`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.listxattr.html
313316
[`llistxattr`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.llistxattr.html
314317
[`flistxattr`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.flistxattr.html
315-
[`kqueue`]: https://docs.rs/rustix/1.0.0/x86_64-unknown-freebsd/rustix/event/kqueue/fn.kqueue.html
318+
[`kevent`]: https://docs.rs/rustix/1.0.0/x86_64-unknown-freebsd/rustix/event/kqueue/fn.kevent.html
319+
[`port::getn`]: https://docs.rs/rustix/1.0.0/x86_64-unknown-illumos/rustix/event/port/fn.getn.html
316320
[`Buffer` trait]: https://docs.rs/rustix/1.0.0/rustix/buffer/trait.Buffer.html
317321
[`spare_capacity`]: https://docs.rs/rustix/1.0.0/rustix/buffer/fn.spare_capacity.html
318322

@@ -335,5 +339,10 @@ In place of `BadOpcode`, use the opcode value directly.
335339
[`rustix::ioctl::Opcode`]: https://docs.rs/rustix/1.0.0/rustix/ioctl/type.Opcode.html
336340
[`ioctl::opcode`]: https://docs.rs/rustix/1.0.0/rustix/ioctl/opcode/index.html
337341

342+
[`rustix::event::port::getn`]'s `min_events` argument is now a `u32`, to
343+
reflect the type in the underlying system API.
344+
345+
[`rustix::event::port::getn`]: https://docs.rs/rustix/1.0.0/x86_64-unknown-illumos/rustix/event/port/fn.getn.html
346+
338347
All explicitly deprecated functions and types have been removed. Their
339348
deprecation messages will have identified alternatives.

src/backend/libc/event/syscalls.rs

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ use crate::event::EventfdFlags;
1919
use crate::event::FdSetElement;
2020
use crate::event::{PollFd, Timespec};
2121
use crate::io;
22-
#[cfg(solarish)]
23-
use crate::utils::as_mut_ptr;
2422
#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))]
2523
use crate::utils::as_ptr;
2624
#[cfg(solarish)]
@@ -362,52 +360,87 @@ pub(crate) unsafe fn port_dissociate(
362360
}
363361

364362
#[cfg(solarish)]
365-
pub(crate) fn port_get(
366-
port: BorrowedFd<'_>,
367-
timeout: Option<&mut c::timespec>,
368-
) -> io::Result<Event> {
363+
pub(crate) fn port_get(port: BorrowedFd<'_>, timeout: Option<&Timespec>) -> io::Result<Event> {
364+
// If we don't have to fix y2038 on this platform, `Timespec` is
365+
// the same as `c::timespec` and it's easy.
366+
#[cfg(not(fix_y2038))]
367+
let timeout = crate::timespec::option_as_libc_timespec_ptr(timeout);
368+
369+
// If we do have to fix y2038 on this platform, convert to
370+
// `c::timespec`.
371+
#[cfg(fix_y2038)]
372+
let converted_timeout;
373+
#[cfg(fix_y2038)]
374+
let timeout = match timeout {
375+
None => null(),
376+
Some(timeout) => {
377+
converted_timeout = c::timespec {
378+
tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
379+
tv_nsec: timeout.tv_nsec as _,
380+
};
381+
&converted_timeout
382+
}
383+
};
384+
369385
let mut event = MaybeUninit::<c::port_event>::uninit();
370-
let timeout = timeout.map_or(null_mut(), as_mut_ptr);
371386

387+
// In Rust >= 1.65, the `as _` can be `.cast_mut()`.
372388
unsafe {
373-
ret(c::port_get(borrowed_fd(port), event.as_mut_ptr(), timeout))?;
389+
ret(c::port_get(
390+
borrowed_fd(port),
391+
event.as_mut_ptr(),
392+
timeout as _,
393+
))?;
374394
}
375395

376396
// If we're done, initialize the event and return it.
377397
Ok(Event(unsafe { event.assume_init() }))
378398
}
379399

380-
#[cfg(all(feature = "alloc", solarish))]
381-
pub(crate) fn port_getn(
400+
#[cfg(solarish)]
401+
pub(crate) unsafe fn port_getn(
382402
port: BorrowedFd<'_>,
383-
timeout: Option<&mut c::timespec>,
384-
events: &mut Vec<Event>,
403+
events: (*mut Event, usize),
385404
mut nget: u32,
386-
) -> io::Result<()> {
387-
// `port_getn` special-cases a max value of 0 to be a query that returns
388-
// the number of events. We don't want to do the `set_len` in that case, so
389-
// so bail out early if needed.
390-
if events.capacity() == 0 {
391-
return Ok(());
392-
}
405+
timeout: Option<&Timespec>,
406+
) -> io::Result<usize> {
407+
// If we don't have to fix y2038 on this platform, `Timespec` is
408+
// the same as `c::timespec` and it's easy.
409+
#[cfg(not(fix_y2038))]
410+
let timeout = crate::timespec::option_as_libc_timespec_ptr(timeout);
411+
412+
// If we do have to fix y2038 on this platform, convert to
413+
// `c::timespec`.
414+
#[cfg(fix_y2038)]
415+
let converted_timeout;
416+
#[cfg(fix_y2038)]
417+
let timeout = match timeout {
418+
None => null(),
419+
Some(timeout) => {
420+
converted_timeout = c::timespec {
421+
tv_sec: timeout.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
422+
tv_nsec: timeout.tv_nsec as _,
423+
};
424+
&converted_timeout
425+
}
426+
};
393427

394-
let timeout = timeout.map_or(null_mut(), as_mut_ptr);
395-
unsafe {
396-
ret(c::port_getn(
397-
borrowed_fd(port),
398-
events.as_mut_ptr().cast(),
399-
events.capacity().try_into().unwrap(),
400-
&mut nget,
401-
timeout,
402-
))?;
428+
// `port_getn` special-cases a max value of 0 to be a query that returns
429+
// the number of events, so so bail out early if needed.
430+
if events.1 == 0 {
431+
return Ok(0);
403432
}
404433

405-
// Update the vector length.
406-
unsafe {
407-
events.set_len(nget.try_into().unwrap());
408-
}
434+
// In Rust >= 1.65, the `as _` can be `.cast_mut()`.
435+
ret(c::port_getn(
436+
borrowed_fd(port),
437+
events.0.cast(),
438+
events.1.try_into().unwrap_or(u32::MAX),
439+
&mut nget,
440+
timeout as _,
441+
))?;
409442

410-
Ok(())
443+
Ok(nget as usize)
411444
}
412445

413446
#[cfg(solarish)]

src/event/port.rs

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@
2929
3030
use crate::backend::c;
3131
use crate::backend::event::syscalls;
32+
use crate::buffer::Buffer;
3233
use crate::fd::{AsFd, AsRawFd, OwnedFd};
34+
use crate::timespec::Timespec;
3335
use crate::{ffi, io};
3436

35-
use core::time::Duration;
36-
3737
pub use super::PollFlags;
3838

3939
/// The structure representing a port event.
@@ -130,52 +130,35 @@ pub unsafe fn dissociate_fd<Fd: AsFd, RawFd: AsRawFd>(port: Fd, object: RawFd) -
130130
/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_get/
131131
/// [illumos]: https://illumos.org/man/3C/port_get
132132
#[doc(alias = "port_get")]
133-
pub fn get<Fd: AsFd>(port: Fd, timeout: Option<Duration>) -> io::Result<Event> {
134-
let mut timeout = timeout.map(|timeout| c::timespec {
135-
tv_sec: timeout.as_secs().try_into().unwrap(),
136-
tv_nsec: timeout.subsec_nanos() as _,
137-
});
138-
139-
syscalls::port_get(port.as_fd(), timeout.as_mut())
133+
pub fn get<Fd: AsFd>(port: Fd, timeout: Option<&Timespec>) -> io::Result<Event> {
134+
syscalls::port_get(port.as_fd(), timeout)
140135
}
141136

142-
/// `port_getn(port, events, min_events, timeout)`—Gets multiple events from a
143-
/// port.
137+
/// `port_getn(port, events, min_events, timeout)`—Gets multiple events from
138+
/// a port.
144139
///
145-
/// This requests up to a max of `events.capacity()` events, and then resizes
146-
/// `events` to the number of events retrieved. If `events.capacity()` is 0,
147-
/// this does nothing and returns immediately.
140+
/// If `events` is empty, this does nothing and returns immediately.
148141
///
149-
/// To query the number of events without retrieving any, use
150-
/// [`getn_query`].
142+
/// To query the number of events without retrieving any, use [`getn_query`].
151143
///
152144
/// # References
153145
/// - [OpenSolaris]
154146
/// - [illumos]
155147
///
156148
/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_getn/
157149
/// [illumos]: https://illumos.org/man/3C/port_getn
158-
#[cfg(feature = "alloc")]
159150
#[doc(alias = "port_getn")]
160-
pub fn getn<Fd: AsFd>(
151+
pub fn getn<Fd: AsFd, Buf: Buffer<Event>>(
161152
port: Fd,
162-
events: &mut Vec<Event>,
163-
min_events: usize,
164-
timeout: Option<Duration>,
165-
) -> io::Result<()> {
166-
events.clear();
167-
168-
let mut timeout = timeout.map(|timeout| c::timespec {
169-
tv_sec: timeout.as_secs().try_into().unwrap(),
170-
tv_nsec: timeout.subsec_nanos() as _,
171-
});
172-
173-
syscalls::port_getn(
174-
port.as_fd(),
175-
timeout.as_mut(),
176-
events,
177-
min_events.try_into().unwrap(),
178-
)
153+
mut events: Buf,
154+
min_events: u32,
155+
timeout: Option<&Timespec>,
156+
) -> io::Result<Buf::Output> {
157+
// SAFETY: `port_getn` behaves.
158+
let nevents =
159+
unsafe { syscalls::port_getn(port.as_fd(), events.parts_mut(), min_events, timeout)? };
160+
// SAFETY: `port_getn` behaves.
161+
unsafe { Ok(events.assume_init(nevents)) }
179162
}
180163

181164
/// `port_getn(port, NULL, 0, NULL)`—Queries the number of events

0 commit comments

Comments
 (0)