Skip to main content

rustix/event/
port.rs

1//! Solaris/illumos event ports.
2//!
3//! # Examples
4//!
5//! ```
6//! # fn test() -> std::io::Result<()> {
7//! use rustix::event::port;
8//! use rustix::stdio::stdout;
9//! use std::io;
10//!
11//! let some_fd = stdout();
12//! let some_userdata = 7 as *mut _;
13//!
14//! // Create a port.
15//! let port = port::create()?;
16//!
17//! // Associate `some_fd` with the port.
18//! unsafe {
19//!     port::associate_fd(&port, some_fd, port::PollFlags::IN, some_userdata)?;
20//! }
21//!
22//! // Get a single event.
23//! let event = port::get(&port, None)?;
24//!
25//! assert_eq!(event.userdata(), some_userdata);
26//! # Ok(())
27//! # }
28//! ```
29
30use crate::backend::c;
31use crate::backend::event::syscalls;
32use crate::buffer::Buffer;
33use crate::fd::{AsFd, AsRawFd, OwnedFd};
34use crate::timespec::Timespec;
35use crate::{ffi, io};
36
37pub use super::PollFlags;
38
39/// The structure representing a port event.
40#[repr(transparent)]
41#[doc(alias = "port_event")]
42pub struct Event(pub(crate) c::port_event);
43
44impl Event {
45    /// Get the events associated with this event.
46    pub fn events(&self) -> i32 {
47        self.0.portev_events
48    }
49
50    /// Get the event source associated with this event.
51    pub fn object(&self) -> usize {
52        self.0.portev_object
53    }
54
55    /// Get the userdata associated with this event.
56    pub fn userdata(&self) -> *mut ffi::c_void {
57        self.0.portev_user
58    }
59}
60
61/// `port_create()`—Creates a new port.
62///
63/// # References
64///  - [OpenSolaris]
65///  - [illumos]
66///
67/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_create/
68/// [illumos]: https://illumos.org/man/3C/port_create
69#[doc(alias = "port_create")]
70pub fn create() -> io::Result<OwnedFd> {
71    syscalls::port_create()
72}
73
74/// `port_associate(_, PORT_SOURCE_FD, _, _, _)`—Associates a file descriptor
75/// with a port.
76///
77/// # Safety
78///
79/// Any `object`s passed into the `port` must be valid for the lifetime of the
80/// `port`. Logically, `port` keeps a borrowed reference to the `object` until
81/// it is removed via [`dissociate_fd`].
82///
83/// # References
84///  - [OpenSolaris]
85///  - [illumos]
86///
87/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_associate/
88/// [illumos]: https://illumos.org/man/3C/port_associate
89#[doc(alias = "port_associate")]
90pub unsafe fn associate_fd<Fd: AsFd, RawFd: AsRawFd>(
91    port: Fd,
92    object: RawFd,
93    events: PollFlags,
94    userdata: *mut ffi::c_void,
95) -> io::Result<()> {
96    syscalls::port_associate(
97        port.as_fd(),
98        c::PORT_SOURCE_FD,
99        object.as_raw_fd() as _,
100        events.bits() as _,
101        userdata.cast(),
102    )
103}
104
105/// `port_dissociate(_, PORT_SOURCE_FD, _)`—Dissociates a file descriptor
106/// from a port.
107///
108/// # Safety
109///
110/// The file descriptor passed into this function must have been previously
111/// associated with the port via [`associate_fd`].
112///
113/// # References
114///  - [OpenSolaris]
115///  - [illumos]
116///
117/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_dissociate
118/// [illumos]: https://illumos.org/man/3C/port_dissociate
119#[doc(alias = "port_dissociate")]
120pub unsafe fn dissociate_fd<Fd: AsFd, RawFd: AsRawFd>(port: Fd, object: RawFd) -> io::Result<()> {
121    syscalls::port_dissociate(port.as_fd(), c::PORT_SOURCE_FD, object.as_raw_fd() as _)
122}
123
124/// `port_get(port, timeout)`—Gets an event from a port.
125///
126/// If an unsupported timeout is passed, this function fails with
127/// [`io::Errno::INVAL`].
128///
129/// # References
130///  - [OpenSolaris]
131///  - [illumos]
132///
133/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_get/
134/// [illumos]: https://illumos.org/man/3C/port_get
135#[doc(alias = "port_get")]
136pub fn get<Fd: AsFd>(port: Fd, timeout: Option<&Timespec>) -> io::Result<Event> {
137    syscalls::port_get(port.as_fd(), timeout)
138}
139
140/// `port_getn(port, events, min_events, timeout)`—Gets multiple events from
141/// a port.
142///
143/// If `events` is empty, this does nothing and returns immediately.
144///
145/// To query the number of events without retrieving any, use [`getn_query`].
146///
147/// If an unsupported timeout is passed, this function fails with
148/// [`io::Errno::INVAL`].
149///
150/// # References
151///  - [OpenSolaris]
152///  - [illumos]
153///
154/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_getn/
155/// [illumos]: https://illumos.org/man/3C/port_getn
156#[doc(alias = "port_getn")]
157pub fn getn<Fd: AsFd, Buf: Buffer<Event>>(
158    port: Fd,
159    mut events: Buf,
160    min_events: u32,
161    timeout: Option<&Timespec>,
162) -> io::Result<Buf::Output> {
163    // SAFETY: `port_getn` behaves.
164    let nevents =
165        unsafe { syscalls::port_getn(port.as_fd(), events.parts_mut(), min_events, timeout)? };
166    // SAFETY: `port_getn` behaves.
167    unsafe { Ok(events.assume_init(nevents)) }
168}
169
170/// `port_getn(port, NULL, 0, NULL)`—Queries the number of events
171/// available from a port.
172///
173/// To retrieve the events, use [`getn`].
174///
175/// # References
176///  - [OpenSolaris]
177///  - [illumos]
178///
179/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_getn/
180/// [illumos]: https://illumos.org/man/3C/port_getn
181#[doc(alias = "port_getn")]
182pub fn getn_query<Fd: AsFd>(port: Fd) -> io::Result<u32> {
183    syscalls::port_getn_query(port.as_fd())
184}
185
186/// `port_send(port, events, userdata)`—Sends an event to a port.
187///
188/// # References
189///  - [OpenSolaris]
190///  - [illumos]
191///
192/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_send/
193/// [illumos]: https://illumos.org/man/3C/port_send
194#[doc(alias = "port_send")]
195pub fn send<Fd: AsFd>(port: Fd, events: i32, userdata: *mut ffi::c_void) -> io::Result<()> {
196    syscalls::port_send(port.as_fd(), events, userdata.cast())
197}