Skip to content

Commit 26f1d86

Browse files
authored
feat: Expose the Solarish event ports API (#503)
* Add event ports API * feat: Add event ports API for solarish Fix unused unsafe warning Code review Use RawFd and unsafe in association Get going! Empty commit to re-run the CI Fix 1.48 build
1 parent 0f1032a commit 26f1d86

File tree

3 files changed

+241
-0
lines changed

3 files changed

+241
-0
lines changed

src/backend/libc/io/syscalls.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use super::super::offset::{libc_preadv, libc_pwritev};
1212
#[cfg(all(target_os = "linux", target_env = "gnu"))]
1313
use super::super::offset::{libc_preadv2, libc_pwritev2};
1414
use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd};
15+
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
16+
use crate::io::port::Event;
1517
#[cfg(not(any(target_os = "aix", target_os = "wasi")))]
1618
use crate::io::DupFlags;
1719
#[cfg(not(any(apple, target_os = "aix", target_os = "haiku", target_os = "wasi")))]
@@ -579,3 +581,85 @@ pub unsafe fn vmsplice(
579581
))
580582
.map(|spliced| spliced as usize)
581583
}
584+
585+
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
586+
pub(crate) fn port_create() -> io::Result<OwnedFd> {
587+
unsafe { ret_owned_fd(c::port_create()) }
588+
}
589+
590+
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
591+
pub(crate) unsafe fn port_associate(
592+
port: BorrowedFd<'_>,
593+
source: c::c_int,
594+
object: c::uintptr_t,
595+
events: c::c_int,
596+
user: *mut c::c_void,
597+
) -> io::Result<()> {
598+
ret(c::port_associate(
599+
borrowed_fd(port),
600+
source,
601+
object,
602+
events,
603+
user,
604+
))
605+
}
606+
607+
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
608+
pub(crate) unsafe fn port_dissociate(
609+
port: BorrowedFd<'_>,
610+
source: c::c_int,
611+
object: c::uintptr_t,
612+
) -> io::Result<()> {
613+
ret(c::port_dissociate(borrowed_fd(port), source, object))
614+
}
615+
616+
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
617+
pub(crate) fn port_get(
618+
port: BorrowedFd<'_>,
619+
timeout: Option<&mut c::timespec>,
620+
) -> io::Result<Event> {
621+
let mut event = MaybeUninit::<c::port_event>::uninit();
622+
let timeout = timeout.map_or(core::ptr::null_mut(), |t| t as *mut _);
623+
624+
unsafe {
625+
ret(c::port_get(borrowed_fd(port), event.as_mut_ptr(), timeout))?;
626+
}
627+
628+
// If we're done, initialize the event and return it.
629+
Ok(Event(unsafe { event.assume_init() }))
630+
}
631+
632+
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
633+
pub(crate) fn port_getn(
634+
port: BorrowedFd<'_>,
635+
timeout: Option<&mut c::timespec>,
636+
events: &mut Vec<Event>,
637+
mut nget: u32,
638+
) -> io::Result<()> {
639+
let timeout = timeout.map_or(core::ptr::null_mut(), |t| t as *mut _);
640+
unsafe {
641+
ret(c::port_getn(
642+
borrowed_fd(port),
643+
events.as_mut_ptr().cast(),
644+
events.len().try_into().unwrap(),
645+
&mut nget,
646+
timeout,
647+
))?;
648+
}
649+
650+
// Update the vector length.
651+
unsafe {
652+
events.set_len(nget.try_into().unwrap());
653+
}
654+
655+
Ok(())
656+
}
657+
658+
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
659+
pub(crate) fn port_send(
660+
port: BorrowedFd<'_>,
661+
events: c::c_int,
662+
userdata: *mut c::c_void,
663+
) -> io::Result<()> {
664+
unsafe { ret(c::port_send(borrowed_fd(port), events, userdata)) }
665+
}

src/io/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub mod kqueue;
2727
#[cfg(not(any(windows, target_os = "wasi")))]
2828
mod pipe;
2929
mod poll;
30+
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
31+
pub mod port;
3032
#[cfg(all(feature = "procfs", any(target_os = "android", target_os = "linux")))]
3133
mod procfs;
3234
#[cfg(not(windows))]

src/io/port.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//! Solaris/Illumos event ports.
2+
3+
use crate::backend::{c, io::syscalls};
4+
use crate::fd::{AsFd, AsRawFd, OwnedFd};
5+
use crate::io;
6+
7+
use super::PollFlags;
8+
9+
use core::convert::TryInto;
10+
use core::time::Duration;
11+
12+
/// The structure representing a port event.
13+
#[repr(transparent)]
14+
pub struct Event(pub(crate) c::port_event);
15+
16+
impl Event {
17+
/// Get the events associated with this event.
18+
pub fn events(&self) -> i32 {
19+
self.0.portev_events
20+
}
21+
22+
/// Get the event source associated with this event.
23+
pub fn object(&self) -> usize {
24+
self.0.portev_object
25+
}
26+
27+
/// Get the userdata associated with this event.
28+
pub fn userdata(&self) -> *mut c::c_void {
29+
self.0.portev_user
30+
}
31+
}
32+
33+
/// `port_create()`- Creates a new port.
34+
///
35+
/// # References
36+
///
37+
/// - [OpenSolaris]
38+
/// - [illumos]
39+
///
40+
/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_create/
41+
/// [illumos]: https://illumos.org/man/3C/port_create
42+
pub fn port_create() -> io::Result<OwnedFd> {
43+
syscalls::port_create()
44+
}
45+
46+
/// `port_associate(_, PORT_SOURCE_FD, _, _, _)`- Associates a file descriptor
47+
/// with a port.
48+
///
49+
/// # Safety
50+
///
51+
/// Any `object`s passed into the `port` must be valid for the lifetime of the `port`.
52+
/// Logically, `port` keeps a borrowed reference to the `object` until it is
53+
/// removed via `port_dissociate_fd`.
54+
///
55+
/// # References
56+
///
57+
/// - [OpenSolaris]
58+
/// - [illumos]
59+
///
60+
/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_associate/
61+
/// [illumos]: https://illumos.org/man/3C/port_associate
62+
pub unsafe fn port_associate_fd(
63+
port: impl AsFd,
64+
object: impl AsRawFd,
65+
events: PollFlags,
66+
userdata: *mut c::c_void,
67+
) -> io::Result<()> {
68+
syscalls::port_associate(
69+
port.as_fd(),
70+
c::PORT_SOURCE_FD,
71+
object.as_raw_fd() as _,
72+
events.bits() as _,
73+
userdata.cast(),
74+
)
75+
}
76+
77+
/// `port_dissociate(_, PORT_SOURCE_FD, _)`- Dissociates a file descriptor from
78+
/// a port.
79+
///
80+
/// # Safety
81+
///
82+
/// The file descriptor passed into this function must have been previously
83+
/// associated with the port via [`port_associate_fd`].
84+
///
85+
/// # References
86+
///
87+
/// - [OpenSolaris]
88+
/// - [illumos]
89+
///
90+
/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_dissociate
91+
/// [illumos]: https://illumos.org/man/3C/port_dissociate
92+
pub unsafe fn port_dissociate_fd(port: impl AsFd, object: impl AsRawFd) -> io::Result<()> {
93+
syscalls::port_dissociate(port.as_fd(), c::PORT_SOURCE_FD, object.as_raw_fd() as _)
94+
}
95+
96+
/// `port_get()`- Gets an event from a port.
97+
///
98+
/// # References
99+
///
100+
/// - [OpenSolaris]
101+
/// - [illumos]
102+
///
103+
/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_get/
104+
/// [illumos]: https://illumos.org/man/3C/port_get
105+
pub fn port_get(port: impl AsFd, timeout: Option<Duration>) -> io::Result<Event> {
106+
let mut timeout = timeout.map(|timeout| c::timespec {
107+
tv_sec: timeout.as_secs().try_into().unwrap(),
108+
tv_nsec: timeout.subsec_nanos() as _,
109+
});
110+
111+
syscalls::port_get(port.as_fd(), timeout.as_mut())
112+
}
113+
114+
/// `port_getn()`- Gets multiple events from a port.
115+
///
116+
/// # References
117+
///
118+
/// - [OpenSolaris]
119+
/// - [illumos]
120+
///
121+
/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_getn/
122+
/// [illumos]: https://illumos.org/man/3C/port_getn
123+
pub fn port_getn(
124+
port: impl AsFd,
125+
events: &mut Vec<Event>,
126+
min_events: usize,
127+
timeout: Option<Duration>,
128+
) -> io::Result<()> {
129+
events.clear();
130+
131+
let mut timeout = timeout.map(|timeout| c::timespec {
132+
tv_sec: timeout.as_secs().try_into().unwrap(),
133+
tv_nsec: timeout.subsec_nanos() as _,
134+
});
135+
136+
syscalls::port_getn(
137+
port.as_fd(),
138+
timeout.as_mut(),
139+
events,
140+
min_events.try_into().unwrap(),
141+
)
142+
}
143+
144+
/// `port_send()`- Sends an event to a port.
145+
///
146+
/// # References
147+
///
148+
/// - [OpenSolaris]
149+
/// - [illumos]
150+
///
151+
/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_send/
152+
/// [illumos]: https://illumos.org/man/3C/port_send
153+
pub fn port_send(port: impl AsFd, events: i32, userdata: *mut c::c_void) -> io::Result<()> {
154+
syscalls::port_send(port.as_fd(), events, userdata.cast())
155+
}

0 commit comments

Comments
 (0)