From f6a20da1c81c2d56a78bc6f6832b9904b9215914 Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Thu, 16 Nov 2023 13:02:42 +0100 Subject: [PATCH] Add Solaris operating system support (#1724) --- .github/workflows/ci.yml | 2 +- src/poll.rs | 20 ++++++++++++++++---- src/sys/mod.rs | 2 ++ src/sys/unix/mod.rs | 9 ++++++--- src/sys/unix/net.rs | 3 ++- src/sys/unix/pipe.rs | 6 ++++-- src/sys/unix/selector/mod.rs | 14 +++++++++++--- src/sys/unix/tcp.rs | 1 + src/sys/unix/waker.rs | 24 +++++++++++++++++++----- tests/tcp.rs | 9 ++++++++- tests/tcp_stream.rs | 12 ++++++++++-- tests/unix_datagram.rs | 1 + tests/unix_stream.rs | 4 ++++ 13 files changed, 85 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c48842dc..7a10a8f7f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -152,7 +152,7 @@ jobs: strategy: fail-fast: false matrix: - target: ["armv7-sony-vita-newlibeabihf"] + target: ["armv7-sony-vita-newlibeabihf", "sparcv9-sun-solaris", "x86_64-pc-solaris"] steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly diff --git a/src/poll.rs b/src/poll.rs index 0a7b4bedf..092482f24 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -1,4 +1,8 @@ -#[cfg(all(unix, not(mio_unsupported_force_poll_poll), not(target_os = "vita")))] +#[cfg(all( + unix, + not(mio_unsupported_force_poll_poll), + not(any(target_os = "solaris", target_os = "vita")) +))] use std::os::unix::io::{AsRawFd, RawFd}; #[cfg(all(debug_assertions, not(target_os = "wasi")))] use std::sync::atomic::{AtomicBool, Ordering}; @@ -423,7 +427,11 @@ impl Poll { } } -#[cfg(all(unix, not(mio_unsupported_force_poll_poll), not(target_os = "vita")))] +#[cfg(all( + unix, + not(mio_unsupported_force_poll_poll), + not(any(target_os = "solaris", target_os = "vita")) +))] impl AsRawFd for Poll { fn as_raw_fd(&self) -> RawFd { self.registry.as_raw_fd() @@ -710,7 +718,11 @@ impl fmt::Debug for Registry { } } -#[cfg(all(unix, not(mio_unsupported_force_poll_poll), not(target_os = "vita")))] +#[cfg(all( + unix, + not(mio_unsupported_force_poll_poll), + not(any(target_os = "solaris", target_os = "vita")) +))] impl AsRawFd for Registry { fn as_raw_fd(&self) -> RawFd { self.selector.as_raw_fd() @@ -721,7 +733,7 @@ cfg_os_poll! { #[cfg(all( unix, not(mio_unsupported_force_poll_poll), - not(target_os = "vita"), + not(any(target_os = "solaris", target_os = "vita")), ))] #[test] pub fn as_raw_fd() { diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 2a968b265..04e0b2000 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -54,6 +54,7 @@ cfg_os_poll! { #[cfg(unix)] cfg_os_poll! { mod unix; + #[allow(unused_imports)] pub use self::unix::*; } @@ -76,6 +77,7 @@ cfg_not_os_poll! { #[cfg(unix)] cfg_any_os_ext! { mod unix; + #[cfg(feature = "os-ext")] pub use self::unix::SourceFd; } diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs index 7804236da..bd2fe7d76 100644 --- a/src/sys/unix/mod.rs +++ b/src/sys/unix/mod.rs @@ -18,6 +18,7 @@ cfg_os_poll! { pub(crate) use self::selector::{event, Event, Events, Selector}; mod sourcefd; + #[cfg(feature = "os-ext")] pub use self::sourcefd::SourceFd; mod waker; @@ -34,7 +35,7 @@ cfg_os_poll! { cfg_io_source! { // Both `kqueue` and `epoll` don't need to hold any user space state. - #[cfg(not(any(mio_unsupported_force_poll_poll, target_os = "vita")))] + #[cfg(not(any(mio_unsupported_force_poll_poll, target_os = "solaris", target_os = "vita")))] mod stateless_io_source { use std::io; use std::os::unix::io::RawFd; @@ -87,10 +88,10 @@ cfg_os_poll! { } } - #[cfg(not(any(mio_unsupported_force_poll_poll, target_os = "vita")))] + #[cfg(not(any(mio_unsupported_force_poll_poll, target_os = "solaris",target_os = "vita")))] pub(crate) use self::stateless_io_source::IoSourceState; - #[cfg(any(mio_unsupported_force_poll_poll, target_os = "vita"))] + #[cfg(any(mio_unsupported_force_poll_poll, target_os = "solaris", target_os = "vita"))] pub(crate) use self::selector::IoSourceState; } @@ -105,6 +106,7 @@ cfg_os_poll! { target_os = "netbsd", target_os = "openbsd", target_os = "redox", + target_os = "solaris", target_os = "vita", ))] pub(crate) mod pipe; @@ -118,6 +120,7 @@ cfg_not_os_poll! { cfg_any_os_ext! { mod sourcefd; + #[cfg(feature = "os-ext")] pub use self::sourcefd::SourceFd; } } diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index 75f015c2f..32f68a663 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -21,6 +21,7 @@ pub(crate) fn new_socket(domain: libc::c_int, socket_type: libc::c_int) -> io::R target_os = "linux", target_os = "netbsd", target_os = "openbsd", + target_os = "solaris", ))] let socket_type = socket_type | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC; @@ -149,7 +150,7 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ sin6_len: 0, #[cfg(target_os = "vita")] sin6_vport: addr.port().to_be(), - #[cfg(target_os = "illumos")] + #[cfg(any(target_os = "illumos", target_os = "solaris"))] __sin6_src_id: 0, }; diff --git a/src/sys/unix/pipe.rs b/src/sys/unix/pipe.rs index 4defd588c..7f23787f7 100644 --- a/src/sys/unix/pipe.rs +++ b/src/sys/unix/pipe.rs @@ -17,6 +17,7 @@ pub(crate) fn new_raw() -> io::Result<[RawFd; 2]> { target_os = "openbsd", target_os = "illumos", target_os = "redox", + target_os = "solaris", target_os = "vita", ))] unsafe { @@ -68,6 +69,7 @@ pub(crate) fn new_raw() -> io::Result<[RawFd; 2]> { target_os = "tvos", target_os = "watchos", target_os = "espidf", + target_os = "solaris", target_os = "vita", )))] compile_error!("unsupported target for `mio::unix::pipe`"); @@ -558,7 +560,7 @@ impl IntoRawFd for Receiver { } } -#[cfg(not(any(target_os = "illumos", target_os = "vita")))] +#[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "vita")))] fn set_nonblocking(fd: RawFd, nonblocking: bool) -> io::Result<()> { let value = nonblocking as libc::c_int; if unsafe { libc::ioctl(fd, libc::FIONBIO, &value) } == -1 { @@ -568,7 +570,7 @@ fn set_nonblocking(fd: RawFd, nonblocking: bool) -> io::Result<()> { } } -#[cfg(any(target_os = "illumos", target_os = "vita"))] +#[cfg(any(target_os = "illumos", target_os = "solaris", target_os = "vita"))] fn set_nonblocking(fd: RawFd, nonblocking: bool) -> io::Result<()> { let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) }; if flags < 0 { diff --git a/src/sys/unix/selector/mod.rs b/src/sys/unix/selector/mod.rs index 9dd3ee44d..322673d1d 100644 --- a/src/sys/unix/selector/mod.rs +++ b/src/sys/unix/selector/mod.rs @@ -20,14 +20,22 @@ mod epoll; ))] pub(crate) use self::epoll::{event, Event, Events, Selector}; -#[cfg(any(mio_unsupported_force_poll_poll, target_os = "vita"))] +#[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" +))] mod poll; -#[cfg(any(mio_unsupported_force_poll_poll, target_os = "vita"))] +#[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" +))] pub(crate) use self::poll::{event, Event, Events, Selector}; cfg_io_source! { - #[cfg(any(mio_unsupported_force_poll_poll, target_os = "vita"))] + #[cfg(any(mio_unsupported_force_poll_poll, target_os = "solaris", target_os = "vita"))] pub(crate) use self::poll::IoSourceState; } diff --git a/src/sys/unix/tcp.rs b/src/sys/unix/tcp.rs index 130f4d685..6f755e870 100644 --- a/src/sys/unix/tcp.rs +++ b/src/sys/unix/tcp.rs @@ -67,6 +67,7 @@ pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, target_os = "linux", target_os = "netbsd", target_os = "openbsd", + target_os = "solaris", ))] let stream = { syscall!(accept4( diff --git a/src/sys/unix/waker.rs b/src/sys/unix/waker.rs index 3a08a8222..968f1a876 100644 --- a/src/sys/unix/waker.rs +++ b/src/sys/unix/waker.rs @@ -10,7 +10,7 @@ target_os = "watchos", ) )), - not(target_os = "vita"), + not(any(target_os = "solaris", target_os = "vita")), ))] mod fdbased { #[cfg(all( @@ -63,7 +63,7 @@ mod fdbased { target_os = "watchos", ) )), - not(target_os = "vita"), + not(any(target_os = "solaris", target_os = "vita")), ))] pub use self::fdbased::Waker; @@ -207,6 +207,7 @@ pub use self::kqueue::Waker; target_os = "netbsd", target_os = "openbsd", target_os = "redox", + target_os = "solaris", target_os = "vita", ))] mod pipe { @@ -253,7 +254,11 @@ mod pipe { } } - #[cfg(any(mio_unsupported_force_poll_poll, target_os = "vita"))] + #[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" + ))] pub fn ack_and_reset(&self) { self.empty(); } @@ -291,11 +296,16 @@ mod pipe { target_os = "redox", ) ), + target_os = "solaris", target_os = "vita", ))] pub(crate) use self::pipe::WakerInternal; -#[cfg(any(mio_unsupported_force_poll_poll, target_os = "vita"))] +#[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" +))] mod poll { use crate::sys::Selector; use crate::Token; @@ -321,5 +331,9 @@ mod poll { } } -#[cfg(any(mio_unsupported_force_poll_poll, target_os = "vita"))] +#[cfg(any( + mio_unsupported_force_poll_poll, + target_os = "solaris", + target_os = "vita" +))] pub use self::poll::Waker; diff --git a/tests/tcp.rs b/tests/tcp.rs index 82ed6bcbf..2c61403d5 100644 --- a/tests/tcp.rs +++ b/tests/tcp.rs @@ -572,6 +572,8 @@ fn connect_error() { for event in &events { if event.token() == Token(0) { assert!(event.is_writable()); + // Solaris poll(2) says POLLHUP and POLLOUT are mutually exclusive. + #[cfg(not(target_os = "solaris"))] assert!(event.is_write_closed()); break 'outer; } @@ -698,7 +700,12 @@ fn write_shutdown() { // Now, shutdown the write half of the socket. socket.shutdown(Shutdown::Write).unwrap(); - wait!(poll, is_readable, true); + // POLLRDHUP isn't supported on Solaris + if cfg!(target_os = "solaris") { + wait!(poll, is_readable, false); + } else { + wait!(poll, is_readable, true); + } } struct MyHandler { diff --git a/tests/tcp_stream.rs b/tests/tcp_stream.rs index df9b3f2e3..ad2224c24 100644 --- a/tests/tcp_stream.rs +++ b/tests/tcp_stream.rs @@ -514,6 +514,7 @@ fn no_events_after_deregister() { windows, ignore = "fails on Windows; client read closed events are not triggered" )] +#[cfg_attr(target_os = "solaris", ignore = "POLLRDHUP isn't supported on Solaris")] fn tcp_shutdown_client_read_close_event() { let (mut poll, mut events) = init_with_poll(); let barrier = Arc::new(Barrier::new(2)); @@ -547,7 +548,12 @@ fn tcp_shutdown_client_read_close_event() { #[test] #[cfg_attr(windows, ignore = "fails; client write_closed events are not found")] #[cfg_attr( - any(target_os = "android", target_os = "illumos", target_os = "linux"), + any( + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "linux" + ), ignore = "fails; client write_closed events are not found" )] fn tcp_shutdown_client_write_close_event() { @@ -581,6 +587,7 @@ fn tcp_shutdown_client_write_close_event() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "POLLRDHUP isn't supported on Solaris")] fn tcp_shutdown_server_write_close_event() { let (mut poll, mut events) = init_with_poll(); let barrier = Arc::new(Barrier::new(2)); @@ -611,6 +618,7 @@ fn tcp_shutdown_server_write_close_event() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "POLLRDHUP isn't supported on Solaris")] fn tcp_reset_close_event() { let (mut poll, mut events) = init_with_poll(); @@ -659,7 +667,7 @@ fn tcp_reset_close_event() { ignore = "fails on Windows; client close events are not found" )] #[cfg_attr( - any(target_os = "illumos"), + any(target_os = "illumos", target_os = "solaris"), ignore = "fails; client write_closed events are not found" )] fn tcp_shutdown_client_both_close_event() { diff --git a/tests/unix_datagram.rs b/tests/unix_datagram.rs index 1b05f5150..31784051c 100644 --- a/tests/unix_datagram.rs +++ b/tests/unix_datagram.rs @@ -166,6 +166,7 @@ fn unix_datagram_pair() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "POLLRDHUP isn't supported on Solaris")] fn unix_datagram_shutdown() { let (mut poll, mut events) = init_with_poll(); let path1 = temp_file("unix_datagram_shutdown1"); diff --git a/tests/unix_stream.rs b/tests/unix_stream.rs index 9bb9d52fd..ecafa5440 100644 --- a/tests/unix_stream.rs +++ b/tests/unix_stream.rs @@ -186,6 +186,7 @@ fn unix_stream_peer_addr() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "POLLRDHUP isn't supported on Solaris")] fn unix_stream_shutdown_read() { let (mut poll, mut events) = init_with_poll(); let (handle, remote_addr) = new_echo_listener(1, "unix_stream_shutdown_read"); @@ -326,6 +327,8 @@ fn unix_stream_shutdown_both() { ); stream.shutdown(Shutdown::Both).unwrap(); + // Solaris never returns POLLHUP for sockets. + #[cfg(not(target_os = "solaris"))] expect_events( &mut poll, &mut events, @@ -361,6 +364,7 @@ fn unix_stream_shutdown_both() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "POLLRDHUP isn't supported on Solaris")] fn unix_stream_shutdown_listener_write() { let (mut poll, mut events) = init_with_poll(); let barrier = Arc::new(Barrier::new(2));