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}