diff --git a/Cargo.toml b/Cargo.toml index e283f58c6..fd989ef0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,9 @@ log = { version = "0.4.8", optional = true } [target.'cfg(unix)'.dependencies] libc = "0.2.149" +[target.'cfg(target_os = "hermit")'.dependencies] +hermit-abi = { version = "0.3.6" } + [target.'cfg(windows)'.dependencies.windows-sys] version = "0.52" features = [ @@ -87,6 +90,7 @@ targets = [ "x86_64-unknown-linux-gnu", "x86_64-unknown-netbsd", "x86_64-unknown-openbsd", + "x86_64-unknown-hermit", ] [package.metadata.playground] diff --git a/examples/tcp_listenfd_server.rs b/examples/tcp_listenfd_server.rs index 941d7f048..2b8b0c495 100644 --- a/examples/tcp_listenfd_server.rs +++ b/examples/tcp_listenfd_server.rs @@ -19,6 +19,8 @@ const DATA: &[u8] = b"Hello world!\n"; #[cfg(not(windows))] fn get_first_listen_fd_listener() -> Option { + #[cfg(target_os = "hermit")] + use std::os::hermit::io::FromRawFd; #[cfg(unix)] use std::os::unix::io::FromRawFd; #[cfg(target_os = "wasi")] diff --git a/src/io_source.rs b/src/io_source.rs index 5a670f935..ec773c3d1 100644 --- a/src/io_source.rs +++ b/src/io_source.rs @@ -1,4 +1,6 @@ use std::ops::{Deref, DerefMut}; +#[cfg(target_os = "hermit")] +use std::os::hermit::io::AsRawFd; #[cfg(unix)] use std::os::unix::io::AsRawFd; #[cfg(target_os = "wasi")] @@ -102,7 +104,7 @@ impl DerefMut for IoSource { } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl event::Source for IoSource where T: AsRawFd, diff --git a/src/lib.rs b/src/lib.rs index 56a7160be..49e1f3699 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,9 @@ //! //! The available features are described in the [`features`] module. +#[cfg(target_os = "hermit")] +extern crate hermit_abi as libc; + // macros used internally #[macro_use] mod macros; diff --git a/src/macros.rs b/src/macros.rs index e380c6b14..b999e1611 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -51,8 +51,8 @@ macro_rules! cfg_net { macro_rules! cfg_io_source { ($($item:item)*) => { $( - #[cfg(any(feature = "net", all(unix, feature = "os-ext")))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "net", all(unix, feature = "os-ext")))))] + #[cfg(any(feature = "net", all(any(unix, target_os = "hermit"), feature = "os-ext")))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "net", all(any(unix, target_os = "hermit"), feature = "os-ext")))))] $item )* } diff --git a/src/net/tcp/listener.rs b/src/net/tcp/listener.rs index df51d57ae..962af2603 100644 --- a/src/net/tcp/listener.rs +++ b/src/net/tcp/listener.rs @@ -1,4 +1,6 @@ use std::net::{self, SocketAddr}; +#[cfg(target_os = "hermit")] +use std::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(unix)] use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(target_os = "wasi")] @@ -9,7 +11,7 @@ use std::{fmt, io}; use crate::io_source::IoSource; use crate::net::TcpStream; -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] use crate::sys::tcp::set_reuseaddr; #[cfg(not(target_os = "wasi"))] use crate::sys::tcp::{bind, listen, new_for_addr}; @@ -58,7 +60,7 @@ impl TcpListener { #[cfg(not(target_os = "wasi"))] pub fn bind(addr: SocketAddr) -> io::Result { let socket = new_for_addr(addr)?; - #[cfg(unix)] + #[cfg(any(unix, target_os = "hermit"))] let listener = unsafe { TcpListener::from_raw_fd(socket) }; #[cfg(windows)] let listener = unsafe { TcpListener::from_raw_socket(socket as _) }; @@ -166,21 +168,21 @@ impl fmt::Debug for TcpListener { } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl IntoRawFd for TcpListener { fn into_raw_fd(self) -> RawFd { self.inner.into_inner().into_raw_fd() } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl AsRawFd for TcpListener { fn as_raw_fd(&self) -> RawFd { self.inner.as_raw_fd() } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl FromRawFd for TcpListener { /// Converts a `RawFd` to a `TcpListener`. /// diff --git a/src/net/tcp/stream.rs b/src/net/tcp/stream.rs index 503f1b81e..3b3d61f64 100644 --- a/src/net/tcp/stream.rs +++ b/src/net/tcp/stream.rs @@ -1,6 +1,8 @@ use std::fmt; use std::io::{self, IoSlice, IoSliceMut, Read, Write}; use std::net::{self, Shutdown, SocketAddr}; +#[cfg(target_os = "hermit")] +use std::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(unix)] use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(target_os = "wasi")] @@ -88,6 +90,8 @@ impl TcpStream { let socket = new_for_addr(addr)?; #[cfg(unix)] let stream = unsafe { TcpStream::from_raw_fd(socket) }; + #[cfg(target_os = "hermit")] + let stream = unsafe { TcpStream::from_raw_fd(socket) }; #[cfg(windows)] let stream = unsafe { TcpStream::from_raw_socket(socket as _) }; connect(&stream.inner, addr)?; @@ -348,21 +352,21 @@ impl fmt::Debug for TcpStream { } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl IntoRawFd for TcpStream { fn into_raw_fd(self) -> RawFd { self.inner.into_inner().into_raw_fd() } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl AsRawFd for TcpStream { fn as_raw_fd(&self) -> RawFd { self.inner.as_raw_fd() } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl FromRawFd for TcpStream { /// Converts a `RawFd` to a `TcpStream`. /// diff --git a/src/net/udp.rs b/src/net/udp.rs index 6129527a7..afde3f884 100644 --- a/src/net/udp.rs +++ b/src/net/udp.rs @@ -14,6 +14,8 @@ use std::fmt; use std::io; use std::net; use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr}; +#[cfg(target_os = "hermit")] +use std::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(unix)] use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(windows)] @@ -642,21 +644,21 @@ impl fmt::Debug for UdpSocket { } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl IntoRawFd for UdpSocket { fn into_raw_fd(self) -> RawFd { self.inner.into_inner().into_raw_fd() } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl AsRawFd for UdpSocket { fn as_raw_fd(&self) -> RawFd { self.inner.as_raw_fd() } } -#[cfg(unix)] +#[cfg(any(unix, target_os = "hermit"))] impl FromRawFd for UdpSocket { /// Converts a `RawFd` to a `UdpSocket`. /// diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 04e0b2000..a4598d07f 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -70,6 +70,12 @@ cfg_os_poll! { pub(crate) use self::wasi::*; } +#[cfg(target_os = "hermit")] +cfg_os_poll! { + mod unix; + pub(crate) use self::unix::*; +} + cfg_not_os_poll! { mod shell; pub(crate) use self::shell::*; diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs index bd2fe7d76..d43990646 100644 --- a/src/sys/unix/mod.rs +++ b/src/sys/unix/mod.rs @@ -5,6 +5,31 @@ macro_rules! syscall { ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{ let res = unsafe { libc::$fn($($arg, )*) }; + #[cfg(target_os = "hermit")] + if res < 0 { + let e = match -res { + libc::errno::EACCES => std::io::ErrorKind::PermissionDenied, + libc::errno::EADDRINUSE => std::io::ErrorKind::AddrInUse, + libc::errno::EADDRNOTAVAIL => std::io::ErrorKind::AddrNotAvailable, + libc::errno::EAGAIN => std::io::ErrorKind::WouldBlock, + libc::errno::ECONNABORTED => std::io::ErrorKind::ConnectionAborted, + libc::errno::ECONNREFUSED => std::io::ErrorKind::ConnectionRefused, + libc::errno::ECONNRESET => std::io::ErrorKind::ConnectionReset, + libc::errno::EEXIST => std::io::ErrorKind::AlreadyExists, + libc::errno::EINTR => std::io::ErrorKind::Interrupted, + libc::errno::EINVAL => std::io::ErrorKind::InvalidInput, + libc::errno::ENOENT => std::io::ErrorKind::NotFound, + libc::errno::ENOTCONN => std::io::ErrorKind::NotConnected, + libc::errno::EPERM => std::io::ErrorKind::PermissionDenied, + libc::errno::EPIPE => std::io::ErrorKind::BrokenPipe, + libc::errno::ETIMEDOUT => std::io::ErrorKind::TimedOut, + _ => panic!("Unknown error {}", res), + }; + Err(std::io::Error::from(e)) + } else { + Ok(res) + } + #[cfg(unix)] if res == -1 { Err(std::io::Error::last_os_error()) } else { @@ -29,13 +54,15 @@ cfg_os_poll! { pub(crate) mod tcp; pub(crate) mod udp; + #[cfg(not(target_os = "hermit"))] pub(crate) mod uds; + #[cfg(not(target_os = "hermit"))] pub use self::uds::SocketAddr; } 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 = "solaris", target_os = "vita")))] + #[cfg(not(any(mio_unsupported_force_poll_poll, target_os = "hermit", target_os = "solaris", target_os = "vita")))] mod stateless_io_source { use std::io; use std::os::unix::io::RawFd; @@ -88,10 +115,10 @@ cfg_os_poll! { } } - #[cfg(not(any(mio_unsupported_force_poll_poll, target_os = "solaris",target_os = "vita")))] + #[cfg(not(any(mio_unsupported_force_poll_poll, target_os = "hermit", target_os = "solaris",target_os = "vita")))] pub(crate) use self::stateless_io_source::IoSourceState; - #[cfg(any(mio_unsupported_force_poll_poll, target_os = "solaris", target_os = "vita"))] + #[cfg(any(mio_unsupported_force_poll_poll, target_os = "hermit", target_os = "solaris", target_os = "vita"))] pub(crate) use self::selector::IoSourceState; } diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index 32f68a663..ed58adaad 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -22,6 +22,7 @@ pub(crate) fn new_socket(domain: libc::c_int, socket_type: libc::c_int) -> io::R target_os = "netbsd", target_os = "openbsd", target_os = "solaris", + target_os = "hermit", ))] let socket_type = socket_type | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC; @@ -115,6 +116,7 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ target_os = "watchos", target_os = "espidf", target_os = "vita", + target_os = "hermit", ))] sin_len: 0, #[cfg(target_os = "vita")] diff --git a/src/sys/unix/selector/mod.rs b/src/sys/unix/selector/mod.rs index 322673d1d..619a7e529 100644 --- a/src/sys/unix/selector/mod.rs +++ b/src/sys/unix/selector/mod.rs @@ -23,19 +23,21 @@ pub(crate) use self::epoll::{event, Event, Events, Selector}; #[cfg(any( mio_unsupported_force_poll_poll, target_os = "solaris", - target_os = "vita" + target_os = "vita", + target_os = "hermit" ))] mod poll; #[cfg(any( mio_unsupported_force_poll_poll, target_os = "solaris", - target_os = "vita" + target_os = "vita", + target_os = "hermit" ))] pub(crate) use self::poll::{event, Event, Events, Selector}; cfg_io_source! { - #[cfg(any(mio_unsupported_force_poll_poll, target_os = "solaris", target_os = "vita"))] + #[cfg(any(mio_unsupported_force_poll_poll, target_os = "hermit", target_os = "solaris", target_os = "vita"))] pub(crate) use self::poll::IoSourceState; } diff --git a/src/sys/unix/selector/poll.rs b/src/sys/unix/selector/poll.rs index 8346e07bc..ec7198f41 100644 --- a/src/sys/unix/selector/poll.rs +++ b/src/sys/unix/selector/poll.rs @@ -8,6 +8,9 @@ use crate::sys::unix::waker::WakerInternal; use crate::{Interest, Token}; use std::collections::HashMap; use std::fmt::{Debug, Formatter}; +#[cfg(target_os = "hermit")] +use std::os::hermit::io::{AsRawFd, RawFd}; +#[cfg(not(target_os = "hermit"))] use std::os::unix::io::{AsRawFd, RawFd}; use std::sync::atomic::AtomicBool; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/sys/unix/sourcefd.rs b/src/sys/unix/sourcefd.rs index 84e776d21..27c34a038 100644 --- a/src/sys/unix/sourcefd.rs +++ b/src/sys/unix/sourcefd.rs @@ -1,6 +1,9 @@ use crate::{event, Interest, Registry, Token}; use std::io; +#[cfg(target_os = "hermit")] +use std::os::hermit::io::RawFd; +#[cfg(not(target_os = "hermit"))] use std::os::unix::io::RawFd; /// Adapter for [`RawFd`] providing an [`event::Source`] implementation. diff --git a/src/sys/unix/tcp.rs b/src/sys/unix/tcp.rs index 6a6d5f28f..0c379b5f8 100644 --- a/src/sys/unix/tcp.rs +++ b/src/sys/unix/tcp.rs @@ -2,6 +2,9 @@ use std::convert::TryInto; use std::io; use std::mem::{size_of, MaybeUninit}; use std::net::{self, SocketAddr}; +#[cfg(target_os = "hermit")] +use std::os::hermit::io::{AsRawFd, FromRawFd}; +#[cfg(not(target_os = "hermit"))] use std::os::unix::io::{AsRawFd, FromRawFd}; use crate::sys::unix::net::{new_socket, socket_addr, to_socket_addr}; @@ -91,6 +94,7 @@ pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, target_os = "watchos", target_os = "espidf", target_os = "vita", + target_os = "hermit", all(target_arch = "x86", target_os = "android"), ))] let stream = { @@ -109,6 +113,7 @@ pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, all(target_arch = "x86", target_os = "android"), target_os = "espidf", target_os = "vita", + target_os = "hermit", ))] syscall!(fcntl(s.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK))?; diff --git a/src/sys/unix/udp.rs b/src/sys/unix/udp.rs index 843ae885c..ecab32473 100644 --- a/src/sys/unix/udp.rs +++ b/src/sys/unix/udp.rs @@ -3,6 +3,9 @@ use crate::sys::unix::net::{new_ip_socket, socket_addr}; use std::io; use std::mem; use std::net::{self, SocketAddr}; +#[cfg(target_os = "hermit")] +use std::os::hermit::io::{AsRawFd, FromRawFd}; +#[cfg(not(target_os = "hermit"))] use std::os::unix::io::{AsRawFd, FromRawFd}; pub fn bind(addr: SocketAddr) -> io::Result { diff --git a/src/sys/unix/waker.rs b/src/sys/unix/waker.rs index 968f1a876..19e9d756e 100644 --- a/src/sys/unix/waker.rs +++ b/src/sys/unix/waker.rs @@ -10,7 +10,7 @@ target_os = "watchos", ) )), - not(any(target_os = "solaris", target_os = "vita")), + not(any(target_os = "solaris", target_os = "vita", target_os = "hermit")), ))] mod fdbased { #[cfg(all( @@ -63,17 +63,25 @@ mod fdbased { target_os = "watchos", ) )), - not(any(target_os = "solaris", target_os = "vita")), + not(any(target_os = "solaris", target_os = "vita", target_os = "hermit")), ))] pub use self::fdbased::Waker; #[cfg(all( not(mio_unsupported_force_waker_pipe), - any(target_os = "linux", target_os = "android", target_os = "espidf") + any( + target_os = "linux", + target_os = "android", + target_os = "espidf", + target_os = "hermit" + ) ))] mod eventfd { use std::fs::File; use std::io::{self, Read, Write}; + #[cfg(target_os = "hermit")] + use std::os::hermit::io::{AsRawFd, FromRawFd, RawFd}; + #[cfg(not(target_os = "hermit"))] use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; /// Waker backed by `eventfd`. @@ -114,7 +122,7 @@ mod eventfd { } } - #[cfg(mio_unsupported_force_poll_poll)] + #[cfg(any(mio_unsupported_force_poll_poll, target_os = "hermit"))] pub fn ack_and_reset(&self) { let _ = self.reset(); } @@ -146,6 +154,9 @@ mod eventfd { ))] pub(crate) use self::eventfd::WakerInternal; +#[cfg(target_os = "hermit")] +pub(crate) use self::eventfd::WakerInternal; + #[cfg(all( not(mio_unsupported_force_waker_pipe), any( @@ -304,7 +315,8 @@ pub(crate) use self::pipe::WakerInternal; #[cfg(any( mio_unsupported_force_poll_poll, target_os = "solaris", - target_os = "vita" + target_os = "vita", + target_os = "hermit" ))] mod poll { use crate::sys::Selector; @@ -334,6 +346,7 @@ mod poll { #[cfg(any( mio_unsupported_force_poll_poll, target_os = "solaris", - target_os = "vita" + target_os = "vita", + target_os = "hermit" ))] pub use self::poll::Waker;