| //! System bindings for HermitCore |
| //! |
| //! This module contains the facade (aka platform-specific) implementations of |
| //! OS level functionality for HermitCore. |
| //! |
| //! This is all super highly experimental and not actually intended for |
| //! wide/production use yet, it's still all in the experimental category. This |
| //! will likely change over time. |
| //! |
| //! Currently all functions here are basically stubs that immediately return |
| //! errors. The hope is that with a portability lint we can turn actually just |
| //! remove all this and just omit parts of the standard library if we're |
| //! compiling for wasm. That way it's a compile time error for something that's |
| //! guaranteed to be a runtime error! |
| |
| #![deny(unsafe_op_in_unsafe_fn)] |
| #![allow(missing_docs, nonstandard_style)] |
| |
| use crate::io; |
| use crate::os::hermit::hermit_abi; |
| use crate::os::raw::c_char; |
| use crate::sys::env; |
| |
| pub mod futex; |
| pub mod os; |
| pub mod time; |
| |
| pub fn unsupported<T>() -> io::Result<T> { |
| Err(unsupported_err()) |
| } |
| |
| pub fn unsupported_err() -> io::Error { |
| io::const_error!(io::ErrorKind::Unsupported, "operation not supported on HermitCore yet") |
| } |
| |
| pub fn abort_internal() -> ! { |
| unsafe { hermit_abi::abort() } |
| } |
| |
| // SAFETY: must be called only once during runtime initialization. |
| // NOTE: this is not guaranteed to run, for example when Rust code is called externally. |
| pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { |
| unsafe { |
| crate::sys::args::init(argc, argv); |
| } |
| } |
| |
| // SAFETY: must be called only once during runtime cleanup. |
| // NOTE: this is not guaranteed to run, for example when the program aborts. |
| pub unsafe fn cleanup() {} |
| |
| #[cfg(not(test))] |
| #[unsafe(no_mangle)] |
| pub unsafe extern "C" fn runtime_entry( |
| argc: i32, |
| argv: *const *const c_char, |
| env: *const *const c_char, |
| ) -> ! { |
| unsafe extern "C" { |
| fn main(argc: isize, argv: *const *const c_char) -> i32; |
| } |
| |
| // initialize environment |
| env::init(env); |
| |
| let result = unsafe { main(argc as isize, argv) }; |
| |
| unsafe { |
| crate::sys::thread_local::destructors::run(); |
| } |
| crate::rt::thread_cleanup(); |
| |
| unsafe { |
| hermit_abi::exit(result); |
| } |
| } |
| |
| #[inline] |
| pub(crate) fn is_interrupted(errno: i32) -> bool { |
| errno == hermit_abi::errno::EINTR |
| } |
| |
| pub fn decode_error_kind(errno: i32) -> io::ErrorKind { |
| match errno { |
| hermit_abi::errno::EACCES => io::ErrorKind::PermissionDenied, |
| hermit_abi::errno::EADDRINUSE => io::ErrorKind::AddrInUse, |
| hermit_abi::errno::EADDRNOTAVAIL => io::ErrorKind::AddrNotAvailable, |
| hermit_abi::errno::EAGAIN => io::ErrorKind::WouldBlock, |
| hermit_abi::errno::ECONNABORTED => io::ErrorKind::ConnectionAborted, |
| hermit_abi::errno::ECONNREFUSED => io::ErrorKind::ConnectionRefused, |
| hermit_abi::errno::ECONNRESET => io::ErrorKind::ConnectionReset, |
| hermit_abi::errno::EEXIST => io::ErrorKind::AlreadyExists, |
| hermit_abi::errno::EINTR => io::ErrorKind::Interrupted, |
| hermit_abi::errno::EINVAL => io::ErrorKind::InvalidInput, |
| hermit_abi::errno::ENOENT => io::ErrorKind::NotFound, |
| hermit_abi::errno::ENOTCONN => io::ErrorKind::NotConnected, |
| hermit_abi::errno::EPERM => io::ErrorKind::PermissionDenied, |
| hermit_abi::errno::EPIPE => io::ErrorKind::BrokenPipe, |
| hermit_abi::errno::ETIMEDOUT => io::ErrorKind::TimedOut, |
| _ => io::ErrorKind::Uncategorized, |
| } |
| } |
| |
| #[doc(hidden)] |
| pub trait IsNegative { |
| fn is_negative(&self) -> bool; |
| fn negate(&self) -> i32; |
| } |
| |
| macro_rules! impl_is_negative { |
| ($($t:ident)*) => ($(impl IsNegative for $t { |
| fn is_negative(&self) -> bool { |
| *self < 0 |
| } |
| |
| fn negate(&self) -> i32 { |
| i32::try_from(-(*self)).unwrap() |
| } |
| })*) |
| } |
| |
| impl IsNegative for i32 { |
| fn is_negative(&self) -> bool { |
| *self < 0 |
| } |
| |
| fn negate(&self) -> i32 { |
| -(*self) |
| } |
| } |
| impl_is_negative! { i8 i16 i64 isize } |
| |
| pub fn cvt<T: IsNegative>(t: T) -> io::Result<T> { |
| if t.is_negative() { |
| let e = decode_error_kind(t.negate()); |
| Err(io::Error::from(e)) |
| } else { |
| Ok(t) |
| } |
| } |
| |
| pub fn cvt_r<T, F>(mut f: F) -> io::Result<T> |
| where |
| T: IsNegative, |
| F: FnMut() -> T, |
| { |
| loop { |
| match cvt(f()) { |
| Err(ref e) if e.is_interrupted() => {} |
| other => return other, |
| } |
| } |
| } |