Auto merge of #65167 - hermitcore:rusty-hermit, r=alexcrichton

Redesign the interface to the unikernel HermitCore

We are developing the unikernel HermitCore, where the kernel is written in Rust and is already part of the Rust Standard Library. The interface between the standard library and the kernel based on a small C library. With this pull request, we remove completely the dependency to C and use lld as linker. Currently, the kernel will be linked to the application as static library, which is published at https://github.com/hermitcore/libhermit-rs.

We don’t longer support the C interface to the kernel. Consequently, we remove this part from the Rust Standard Library.
This commit is contained in:
bors 2019-10-26 19:35:59 +00:00
commit fae75cd216
51 changed files with 2322 additions and 450 deletions

View File

@ -1328,6 +1328,17 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f22b8f315b98f415780ddbe9163c7dbbc5a07225b6d102ace1d8aeef85775140"
dependencies = [
"compiler_builtins",
"libc",
"rustc-std-workspace-core",
]
[[package]]
name = "hex"
version = "0.3.2"
@ -4159,6 +4170,7 @@ dependencies = [
"dlmalloc",
"fortanix-sgx-abi",
"hashbrown 0.6.2",
"hermit-abi",
"libc",
"panic_abort",
"panic_unwind",

View File

@ -160,7 +160,7 @@ mod job {
}
}
#[cfg(any(target_os = "haiku", not(any(unix, windows))))]
#[cfg(any(target_os = "haiku", target_os = "hermit", not(any(unix, windows))))]
mod job {
pub unsafe fn setup(_build: &mut crate::Build) {
}

View File

@ -54,7 +54,8 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
core::intrinsics::abort();
}
#[cfg(all(target_vendor="fortanix", target_env="sgx"))]
#[cfg(any(target_os = "hermit",
all(target_vendor="fortanix", target_env="sgx")))]
unsafe fn abort() -> ! {
// call std::sys::abort_internal
extern "C" { pub fn __rust_abort() -> !; }

View File

@ -0,0 +1,21 @@
//! Unwinding for *hermit* target.
//!
//! Right now we don't support this, so this is just stubs.
use alloc::boxed::Box;
use core::ptr;
use core::any::Any;
pub fn payload() -> *mut u8 {
ptr::null_mut()
}
pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
extern "C" { pub fn __rust_abort() -> !; }
__rust_abort();
}
pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
extern "C" { pub fn __rust_abort() -> !; }
__rust_abort();
}

View File

@ -43,6 +43,9 @@ cfg_if::cfg_if! {
} else if #[cfg(target_arch = "wasm32")] {
#[path = "dummy.rs"]
mod imp;
} else if #[cfg(target_os = "hermit")] {
#[path = "hermit.rs"]
mod imp;
} else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] {
#[path = "dummy.rs"]
mod imp;

View File

@ -1,26 +1,26 @@
use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions};
use crate::spec::{LldFlavor, LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
let mut args = LinkArgs::new();
args.insert(LinkerFlavor::Gcc, vec![
"-Wl,-Bstatic".to_string(),
"-Wl,--no-dynamic-linker".to_string(),
"-Wl,--gc-sections".to_string(),
"-Wl,--as-needed".to_string(),
let mut pre_link_args = LinkArgs::new();
pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec![
"--build-id".to_string(),
"--hash-style=gnu".to_string(),
"--Bstatic".to_string(),
]);
TargetOptions {
linker: Some("rust-lld".to_owned()),
executables: true,
has_elf_tls: true,
linker_is_gnu: true,
no_default_libraries: false,
pre_link_args,
no_default_libraries: true,
panic_strategy: PanicStrategy::Abort,
position_independent_executables: false,
pre_link_args: args,
position_independent_executables: true,
relocation_model: "static".to_string(),
target_family: Some("unix".to_string()),
tls_model: "local-exec".to_string(),
target_family: None,
tls_model: "initial-exec".to_string(),
.. Default::default()
}
}

View File

@ -1,11 +1,11 @@
use crate::spec::{LinkerFlavor, Target, TargetResult};
use crate::spec::{LldFlavor, LinkerFlavor, Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::hermit_base::opts();
base.cpu = "x86-64".to_string();
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.linker = Some("x86_64-hermit-gcc".to_string());
base.max_atomic_width = Some(64);
base.features = "+rdrnd,+rdseed".to_string();
base.stack_probes = true;
Ok(Target {
llvm_target: "x86_64-unknown-hermit".to_string(),
@ -17,7 +17,7 @@ pub fn target() -> TargetResult {
target_os: "hermit".to_string(),
target_env: String::new(),
target_vendor: "unknown".to_string(),
linker_flavor: LinkerFlavor::Gcc,
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
options: base,
})
}

View File

@ -346,6 +346,7 @@ impl<'a> fmt::Display for Html<'a> {
"freebsd" => "FreeBSD",
"fuchsia" => "Fuchsia",
"haiku" => "Haiku",
"hermit" => "HermitCore",
"ios" => "iOS",
"l4re" => "L4Re",
"linux" => "Linux",

View File

@ -50,6 +50,9 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
[target.x86_64-fortanix-unknown-sgx.dependencies]
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
[target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
hermit-abi = { version = "0.1", features = ['rustc-dep-of-std'] }
[target.wasm32-wasi.dependencies]
wasi = { version = "0.7.0", features = ['rustc-dep-of-std', 'alloc'] }

View File

@ -54,5 +54,7 @@ fn main() {
}
println!("cargo:rustc-link-lib=c");
println!("cargo:rustc-link-lib=compiler_rt");
} else if target.contains("hermit") {
println!("cargo:rustc-link-lib=hermit");
}
}

View File

@ -1,377 +0,0 @@
#![stable(feature = "metadata_ext", since = "1.1.0")]
use crate::fs::Metadata;
use crate::sys_common::AsInner;
#[allow(deprecated)]
use crate::os::hermit::raw;
/// OS-specific extensions to [`fs::Metadata`].
///
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
/// the raw information returned by the OS.
///
/// The contents of the returned [`stat`] are **not** consistent across
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
///
/// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let stat = meta.as_raw_stat();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
#[rustc_deprecated(since = "1.8.0",
reason = "deprecated in favor of the accessor \
methods of this trait")]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
/// Returns the device ID on which this file resides.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_dev());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_dev(&self) -> u64;
/// Returns the inode number.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ino());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ino(&self) -> u64;
/// Returns the file type and mode.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mode());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mode(&self) -> u32;
/// Returns the number of hard links to file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_nlink());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_nlink(&self) -> u64;
/// Returns the user ID of the file owner.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_uid());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_uid(&self) -> u32;
/// Returns the group ID of the file owner.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_gid());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_gid(&self) -> u32;
/// Returns the device ID that this file represents. Only relevant for special file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_rdev());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_rdev(&self) -> u64;
/// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
///
/// The size of a symbolic link is the length of the pathname it contains,
/// without a terminating null byte.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_size());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_size(&self) -> u64;
/// Returns the last access time.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_atime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime(&self) -> i64;
/// Returns the last access time, nano seconds part.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_atime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime_nsec(&self) -> i64;
/// Returns the last modification time.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mtime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime(&self) -> i64;
/// Returns the last modification time, nano seconds part.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mtime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime_nsec(&self) -> i64;
/// Returns the last status change time.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ctime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime(&self) -> i64;
/// Returns the last status change time, nano seconds part.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ctime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
/// Returns the "preferred" blocksize for efficient filesystem I/O.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_blksize());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blksize(&self) -> u64;
/// Returns the number of blocks allocated to the file, 512-byte units.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_blocks());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blocks(&self) -> u64;
}
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat {
unsafe {
&*(self.as_inner().as_inner() as *const libc::stat64
as *const raw::stat)
}
}
fn st_dev(&self) -> u64 {
self.as_inner().as_inner().st_dev as u64
}
fn st_ino(&self) -> u64 {
self.as_inner().as_inner().st_ino as u64
}
fn st_mode(&self) -> u32 {
self.as_inner().as_inner().st_mode as u32
}
fn st_nlink(&self) -> u64 {
self.as_inner().as_inner().st_nlink as u64
}
fn st_uid(&self) -> u32 {
self.as_inner().as_inner().st_uid as u32
}
fn st_gid(&self) -> u32 {
self.as_inner().as_inner().st_gid as u32
}
fn st_rdev(&self) -> u64 {
self.as_inner().as_inner().st_rdev as u64
}
fn st_size(&self) -> u64 {
self.as_inner().as_inner().st_size as u64
}
fn st_atime(&self) -> i64 {
self.as_inner().as_inner().st_atime as i64
}
fn st_atime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_atime_nsec as i64
}
fn st_mtime(&self) -> i64 {
self.as_inner().as_inner().st_mtime as i64
}
fn st_mtime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_mtime_nsec as i64
}
fn st_ctime(&self) -> i64 {
self.as_inner().as_inner().st_ctime as i64
}
fn st_ctime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_ctime_nsec as i64
}
fn st_blksize(&self) -> u64 {
self.as_inner().as_inner().st_blksize as u64
}
fn st_blocks(&self) -> u64 {
self.as_inner().as_inner().st_blocks as u64
}
}

View File

@ -1,6 +0,0 @@
//! HermitCore-specific definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
pub mod raw;
pub mod fs;

View File

@ -1,17 +0,0 @@
//! HermitCore-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
#![rustc_deprecated(since = "1.8.0",
reason = "these type aliases are no longer supported by \
the standard library, the `libc` crate on \
crates.io should be used instead for the correct \
definitions")]
#![allow(deprecated)]
#![allow(missing_debug_implementations)]
#[stable(feature = "pthread_t", since = "1.8.0")]
pub use libc::pthread_t;
#[doc(inline)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub use libc::{dev_t, mode_t, off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};

View File

@ -49,7 +49,6 @@ cfg_if::cfg_if! {
#[cfg(target_os = "solaris")] pub mod solaris;
#[cfg(target_os = "emscripten")] pub mod emscripten;
#[cfg(target_os = "fuchsia")] pub mod fuchsia;
#[cfg(target_os = "hermit")] pub mod hermit;
#[cfg(target_os = "redox")] pub mod redox;
#[cfg(target_os = "wasi")] pub mod wasi;
#[cfg(target_os = "vxworks")] pub mod vxworks;

View File

@ -0,0 +1,35 @@
use crate::alloc::{GlobalAlloc, Layout, System};
use crate::ptr;
use crate::sys::hermit::abi;
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
abi::malloc(layout.size(), layout.align())
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let addr = abi::malloc(layout.size(), layout.align());
if !addr.is_null() {
ptr::write_bytes(
addr,
0x00,
layout.size()
);
}
addr
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
abi::free(ptr, layout.size(), layout.align())
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
abi::realloc(ptr, layout.size(), layout.align(), new_size)
}
}

View File

@ -0,0 +1,82 @@
use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::vec;
/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
/// One-time global cleanup.
pub unsafe fn cleanup() { imp::cleanup() }
/// Returns the command line arguments
pub fn args() -> Args {
imp::args()
}
pub struct Args {
iter: vec::IntoIter<OsString>,
_dont_send_or_sync_me: PhantomData<*mut ()>,
}
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
self.iter.as_slice()
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> { self.iter.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize { self.iter.len() }
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
}
mod imp {
use crate::sys_common::os_str_bytes::*;
use crate::ptr;
use crate::ffi::{CStr, OsString};
use crate::marker::PhantomData;
use super::Args;
use crate::sys_common::mutex::Mutex;
static mut ARGC: isize = 0;
static mut ARGV: *const *const u8 = ptr::null();
static LOCK: Mutex = Mutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
let _guard = LOCK.lock();
ARGC = argc;
ARGV = argv;
}
pub unsafe fn cleanup() {
let _guard = LOCK.lock();
ARGC = 0;
ARGV = ptr::null();
}
pub fn args() -> Args {
Args {
iter: clone().into_iter(),
_dont_send_or_sync_me: PhantomData
}
}
fn clone() -> Vec<OsString> {
unsafe {
let _guard = LOCK.lock();
(0..ARGC).map(|i| {
let cstr = CStr::from_ptr(*ARGV.offset(i) as *const i8);
OsStringExt::from_vec(cstr.to_bytes().to_vec())
}).collect()
}
}
}

View File

@ -0,0 +1,29 @@
// These symbols are all defined in `compiler-builtins`
extern {
pub fn acos(n: f64) -> f64;
pub fn acosf(n: f32) -> f32;
pub fn asin(n: f64) -> f64;
pub fn asinf(n: f32) -> f32;
pub fn atan(n: f64) -> f64;
pub fn atan2(a: f64, b: f64) -> f64;
pub fn atan2f(a: f32, b: f32) -> f32;
pub fn atanf(n: f32) -> f32;
pub fn cbrt(n: f64) -> f64;
pub fn cbrtf(n: f32) -> f32;
pub fn cosh(n: f64) -> f64;
pub fn coshf(n: f32) -> f32;
pub fn expm1(n: f64) -> f64;
pub fn expm1f(n: f32) -> f32;
pub fn fdim(a: f64, b: f64) -> f64;
pub fn fdimf(a: f32, b: f32) -> f32;
pub fn hypot(x: f64, y: f64) -> f64;
pub fn hypotf(x: f32, y: f32) -> f32;
pub fn log1p(n: f64) -> f64;
pub fn log1pf(n: f32) -> f32;
pub fn sinh(n: f64) -> f64;
pub fn sinhf(n: f32) -> f32;
pub fn tan(n: f64) -> f64;
pub fn tanf(n: f32) -> f32;
pub fn tanh(n: f64) -> f64;
pub fn tanhf(n: f32) -> f32;
}

View File

@ -0,0 +1,62 @@
use crate::cmp;
use crate::sys::hermit::abi;
use crate::sys::mutex::Mutex;
use crate::time::Duration;
pub struct Condvar {
identifier: usize,
}
impl Condvar {
pub const fn new() -> Condvar {
Condvar { identifier: 0 }
}
#[inline]
pub unsafe fn init(&mut self) {
// nothing to do
}
pub unsafe fn notify_one(&self) {
let _ = abi::notify(self.id(), 1);
}
#[inline]
pub unsafe fn notify_all(&self) {
let _ = abi::notify(self.id(), -1 /* =all */);
}
pub unsafe fn wait(&self, mutex: &Mutex) {
// add current task to the wait queue
let _ = abi::add_queue(self.id(), -1 /* no timeout */);
mutex.unlock();
let _ = abi::wait(self.id());
mutex.lock();
}
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
let nanos = dur.as_nanos();
let nanos = cmp::min(i64::max_value() as u128, nanos);
// add current task to the wait queue
let _ = abi::add_queue(self.id(), nanos as i64);
mutex.unlock();
// If the return value is !0 then a timeout happened, so we return
// `false` as we weren't actually notified.
let ret = abi::wait(self.id()) == 0;
mutex.lock();
ret
}
#[inline]
pub unsafe fn destroy(&self) {
let _ = abi::destroy_queue(self.id());
}
#[inline]
fn id(&self) -> usize {
&self.identifier as *const usize as usize
}
}

View File

@ -0,0 +1,9 @@
pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "hermit";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = "";
pub const DLL_EXTENSION: &str = "";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}

View File

@ -0,0 +1,4 @@
#![cfg(target_thread_local)]
#![unstable(feature = "thread_local_internals", issue = "0")]
pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;

View File

@ -0,0 +1,82 @@
#![unstable(reason = "not public", issue = "0", feature = "fd")]
use crate::io::{self, Read, ErrorKind};
use crate::mem;
use crate::sys::cvt;
use crate::sys::hermit::abi;
use crate::sys_common::AsInner;
#[derive(Debug)]
pub struct FileDesc {
fd: i32,
}
impl FileDesc {
pub fn new(fd: i32) -> FileDesc {
FileDesc { fd }
}
pub fn raw(&self) -> i32 { self.fd }
/// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> i32 {
let fd = self.fd;
mem::forget(self);
fd
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let result = unsafe { abi::read(self.fd, buf.as_mut_ptr(), buf.len()) };
cvt(result as i32)
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut me = self;
(&mut me).read_to_end(buf)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let result = unsafe { abi::write(self.fd, buf.as_ptr(), buf.len()) };
cvt(result as i32)
}
pub fn duplicate(&self) -> io::Result<FileDesc> {
self.duplicate_path(&[])
}
pub fn duplicate_path(&self, _path: &[u8]) -> io::Result<FileDesc> {
Err(io::Error::new(ErrorKind::Other, "duplicate isn't supported"))
}
pub fn nonblocking(&self) -> io::Result<bool> {
Ok(false)
}
pub fn set_cloexec(&self) -> io::Result<()> {
Err(io::Error::new(ErrorKind::Other, "cloexec isn't supported"))
}
pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> {
Err(io::Error::new(ErrorKind::Other, "nonblocking isn't supported"))
}
}
impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
}
impl AsInner<i32> for FileDesc {
fn as_inner(&self) -> &i32 { &self.fd }
}
impl Drop for FileDesc {
fn drop(&mut self) {
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// (opened after we closed ours.
let _ = unsafe { abi::close(self.fd) };
}
}

387
src/libstd/sys/hermit/fs.rs Normal file
View File

@ -0,0 +1,387 @@
use crate::ffi::{OsString, CString, CStr};
use crate::fmt;
use crate::io::{self, Error, ErrorKind};
use crate::hash::{Hash, Hasher};
use crate::io::{SeekFrom, IoSlice, IoSliceMut};
use crate::path::{Path, PathBuf};
use crate::sys::time::SystemTime;
use crate::sys::{unsupported, Void};
use crate::sys::hermit::abi;
use crate::sys::hermit::fd::FileDesc;
use crate::sys::cvt;
use crate::sys_common::os_str_bytes::OsStrExt;
pub use crate::sys_common::fs::copy;
//pub use crate::sys_common::fs::remove_dir_all;
fn cstr(path: &Path) -> io::Result<CString> {
Ok(CString::new(path.as_os_str().as_bytes())?)
}
//const O_ACCMODE: i32 = 00000003;
const O_RDONLY: i32 = 00000000;
const O_WRONLY: i32 = 00000001;
const O_RDWR: i32 = 00000002;
const O_CREAT: i32 = 00000100;
const O_EXCL: i32 = 00000200;
const O_TRUNC: i32 = 00001000;
const O_APPEND: i32 = 00002000;
#[derive(Debug)]
pub struct File(FileDesc);
pub struct FileAttr(Void);
pub struct ReadDir(Void);
pub struct DirEntry(Void);
#[derive(Clone, Debug)]
pub struct OpenOptions {
// generic
read: bool,
write: bool,
append: bool,
truncate: bool,
create: bool,
create_new: bool,
// system-specific
mode: i32
}
pub struct FilePermissions(Void);
pub struct FileType(Void);
#[derive(Debug)]
pub struct DirBuilder { }
impl FileAttr {
pub fn size(&self) -> u64 {
match self.0 {}
}
pub fn perm(&self) -> FilePermissions {
match self.0 {}
}
pub fn file_type(&self) -> FileType {
match self.0 {}
}
pub fn modified(&self) -> io::Result<SystemTime> {
match self.0 {}
}
pub fn accessed(&self) -> io::Result<SystemTime> {
match self.0 {}
}
pub fn created(&self) -> io::Result<SystemTime> {
match self.0 {}
}
}
impl Clone for FileAttr {
fn clone(&self) -> FileAttr {
match self.0 {}
}
}
impl FilePermissions {
pub fn readonly(&self) -> bool {
match self.0 {}
}
pub fn set_readonly(&mut self, _readonly: bool) {
match self.0 {}
}
}
impl Clone for FilePermissions {
fn clone(&self) -> FilePermissions {
match self.0 {}
}
}
impl PartialEq for FilePermissions {
fn eq(&self, _other: &FilePermissions) -> bool {
match self.0 {}
}
}
impl Eq for FilePermissions {
}
impl fmt::Debug for FilePermissions {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {}
}
}
impl FileType {
pub fn is_dir(&self) -> bool {
match self.0 {}
}
pub fn is_file(&self) -> bool {
match self.0 {}
}
pub fn is_symlink(&self) -> bool {
match self.0 {}
}
}
impl Clone for FileType {
fn clone(&self) -> FileType {
match self.0 {}
}
}
impl Copy for FileType {}
impl PartialEq for FileType {
fn eq(&self, _other: &FileType) -> bool {
match self.0 {}
}
}
impl Eq for FileType {
}
impl Hash for FileType {
fn hash<H: Hasher>(&self, _h: &mut H) {
match self.0 {}
}
}
impl fmt::Debug for FileType {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {}
}
}
impl fmt::Debug for ReadDir {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {}
}
}
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
fn next(&mut self) -> Option<io::Result<DirEntry>> {
match self.0 {}
}
}
impl DirEntry {
pub fn path(&self) -> PathBuf {
match self.0 {}
}
pub fn file_name(&self) -> OsString {
match self.0 {}
}
pub fn metadata(&self) -> io::Result<FileAttr> {
match self.0 {}
}
pub fn file_type(&self) -> io::Result<FileType> {
match self.0 {}
}
}
impl OpenOptions {
pub fn new() -> OpenOptions {
OpenOptions {
// generic
read: false,
write: false,
append: false,
truncate: false,
create: false,
create_new: false,
// system-specific
mode: 0x777
}
}
pub fn read(&mut self, read: bool) { self.read = read; }
pub fn write(&mut self, write: bool) { self.write = write; }
pub fn append(&mut self, append: bool) { self.append = append; }
pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
pub fn create(&mut self, create: bool) { self.create = create; }
pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
fn get_access_mode(&self) -> io::Result<i32> {
match (self.read, self.write, self.append) {
(true, false, false) => Ok(O_RDONLY),
(false, true, false) => Ok(O_WRONLY),
(true, true, false) => Ok(O_RDWR),
(false, _, true) => Ok(O_WRONLY | O_APPEND),
(true, _, true) => Ok(O_RDWR | O_APPEND),
(false, false, false) => {
Err(io::Error::new(ErrorKind::InvalidInput, "invalid access mode"))
},
}
}
fn get_creation_mode(&self) -> io::Result<i32> {
match (self.write, self.append) {
(true, false) => {}
(false, false) =>
if self.truncate || self.create || self.create_new {
return Err(io::Error::new(ErrorKind::InvalidInput, "invalid creation mode"));
},
(_, true) =>
if self.truncate && !self.create_new {
return Err(io::Error::new(ErrorKind::InvalidInput, "invalid creation mode"));
},
}
Ok(match (self.create, self.truncate, self.create_new) {
(false, false, false) => 0,
(true, false, false) => O_CREAT,
(false, true, false) => O_TRUNC,
(true, true, false) => O_CREAT | O_TRUNC,
(_, _, true) => O_CREAT | O_EXCL,
})
}
}
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let path = cstr(path)?;
File::open_c(&path, opts)
}
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
let mut flags = opts.get_access_mode()?;
flags = flags | opts.get_creation_mode()?;
let mode;
if flags & O_CREAT == O_CREAT {
mode = opts.mode;
} else {
mode = 0;
}
let fd = unsafe { cvt(abi::open(path.as_ptr(), flags, mode))? };
Ok(File(FileDesc::new(fd as i32)))
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
Err(Error::from_raw_os_error(22))
}
pub fn fsync(&self) -> io::Result<()> {
Err(Error::from_raw_os_error(22))
}
pub fn datasync(&self) -> io::Result<()> {
self.fsync()
}
pub fn truncate(&self, _size: u64) -> io::Result<()> {
Err(Error::from_raw_os_error(22))
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
crate::io::default_read_vectored(|buf| self.read(buf), bufs)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
crate::io::default_write_vectored(|buf| self.write(buf), bufs)
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
Err(Error::from_raw_os_error(22))
}
pub fn duplicate(&self) -> io::Result<File> {
Err(Error::from_raw_os_error(22))
}
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
Err(Error::from_raw_os_error(22))
}
pub fn diverge(&self) -> ! {
loop {}
}
}
impl DirBuilder {
pub fn new() -> DirBuilder {
DirBuilder { }
}
pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
unsupported()
}
}
pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
unsupported()
}
pub fn unlink(path: &Path) -> io::Result<()> {
let name = cstr(path)?;
let _ = unsafe { cvt(abi::unlink(name.as_ptr()))? };
Ok(())
}
pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
unsupported()
}
pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
match perm.0 {}
}
pub fn rmdir(_p: &Path) -> io::Result<()> {
unsupported()
}
pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
//unsupported()
Ok(())
}
pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
unsupported()
}
pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
unsupported()
}
pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
unsupported()
}
pub fn stat(_p: &Path) -> io::Result<FileAttr> {
unsupported()
}
pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
unsupported()
}
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
unsupported()
}

View File

@ -0,0 +1,46 @@
use crate::mem;
pub struct IoSlice<'a>(&'a [u8]);
impl<'a> IoSlice<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
IoSlice(buf)
}
#[inline]
pub fn advance(&mut self, n: usize) {
self.0 = &self.0[n..]
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
self.0
}
}
pub struct IoSliceMut<'a>(&'a mut [u8]);
impl<'a> IoSliceMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
IoSliceMut(buf)
}
#[inline]
pub fn advance(&mut self, n: usize) {
let slice = mem::replace(&mut self.0, &mut []);
let (_, remaining) = slice.split_at_mut(n);
self.0 = remaining;
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
self.0
}
}

View File

@ -0,0 +1 @@
pub use core::slice::memchr::{memchr, memrchr};

View File

@ -0,0 +1,147 @@
//! 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!
use crate::os::raw::c_char;
use crate::intrinsics;
pub mod alloc;
pub mod args;
pub mod condvar;
pub mod stdio;
pub mod memchr;
pub mod io;
pub mod mutex;
pub mod rwlock;
pub mod os;
pub mod cmath;
pub mod thread;
pub mod env;
pub mod fs;
pub mod fd;
pub mod net;
pub mod path;
pub mod pipe;
pub mod process;
pub mod stack_overflow;
pub mod time;
pub mod thread_local;
pub mod fast_thread_local;
pub use crate::sys_common::os_str_bytes as os_str;
use crate::io::ErrorKind;
#[allow(unused_extern_crates)]
pub extern crate hermit_abi as abi;
pub fn unsupported<T>() -> crate::io::Result<T> {
Err(unsupported_err())
}
pub fn unsupported_err() -> crate::io::Error {
crate::io::Error::new(crate::io::ErrorKind::Other,
"operation not supported on HermitCore yet")
}
// This enum is used as the storage for a bunch of types which can't actually
// exist.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum Void {}
pub unsafe fn strlen(start: *const c_char) -> usize {
let mut str = start;
while *str != 0 {
str = str.offset(1);
}
(str as usize) - (start as usize)
}
#[no_mangle]
pub extern "C" fn floor(x: f64) -> f64 {
unsafe {
intrinsics::floorf64(x)
}
}
pub unsafe fn abort_internal() -> ! {
abi::abort();
}
// FIXME: just a workaround to test the system
pub fn hashmap_random_keys() -> (u64, u64) {
(1, 2)
}
// This function is needed by the panic runtime. The symbol is named in
// pre-link args for the target specification, so keep that in sync.
#[cfg(not(test))]
#[no_mangle]
// NB. used by both libunwind and libpanic_abort
pub unsafe extern "C" fn __rust_abort() {
abort_internal();
}
#[cfg(not(test))]
pub fn init() {
unsafe {
let _ = net::init();
}
}
#[cfg(not(test))]
#[no_mangle]
pub unsafe extern "C" fn runtime_entry(argc: i32, argv: *const *const c_char,
env: *const *const c_char) -> ! {
extern "C" {
fn main(argc: isize, argv: *const *const c_char) -> i32;
}
// initialize environment
os::init_environment(env as *const *const i8);
let result = main(argc as isize, argv);
abi::exit(result);
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno {
x if x == 13 as i32 => ErrorKind::PermissionDenied,
x if x == 98 as i32 => ErrorKind::AddrInUse,
x if x == 99 as i32 => ErrorKind::AddrNotAvailable,
x if x == 11 as i32 => ErrorKind::WouldBlock,
x if x == 103 as i32 => ErrorKind::ConnectionAborted,
x if x == 111 as i32 => ErrorKind::ConnectionRefused,
x if x == 104 as i32 => ErrorKind::ConnectionReset,
x if x == 17 as i32 => ErrorKind::AlreadyExists,
x if x == 4 as i32 => ErrorKind::Interrupted,
x if x == 22 as i32 => ErrorKind::InvalidInput,
x if x == 2 as i32 => ErrorKind::NotFound,
x if x == 107 as i32 => ErrorKind::NotConnected,
x if x == 1 as i32 => ErrorKind::PermissionDenied,
x if x == 32 as i32 => ErrorKind::BrokenPipe,
x if x == 110 as i32 => ErrorKind::TimedOut,
_ => ErrorKind::Other,
}
}
pub fn cvt(result: i32) -> crate::io::Result<usize> {
if result < 0 {
Err(crate::io::Error::from_raw_os_error(-result))
} else {
Ok(result as usize)
}
}

View File

@ -0,0 +1,77 @@
use crate::ptr;
use crate::ffi::c_void;
use crate::sys::hermit::abi;
pub struct Mutex {
inner: *const c_void
}
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
impl Mutex {
pub const fn new() -> Mutex {
Mutex { inner: ptr::null() }
}
#[inline]
pub unsafe fn init(&mut self) {
let _ = abi::sem_init(&mut self.inner as *mut *const c_void, 1);
}
#[inline]
pub unsafe fn lock(&self) {
let _ = abi::sem_timedwait(self.inner, 0);
}
#[inline]
pub unsafe fn unlock(&self) {
let _ = abi::sem_post(self.inner);
}
#[inline]
pub unsafe fn try_lock(&self) -> bool {
let result = abi::sem_trywait(self.inner);
result == 0
}
#[inline]
pub unsafe fn destroy(&self) {
let _ = abi::sem_destroy(self.inner);
}
}
pub struct ReentrantMutex {
inner: *const c_void
}
impl ReentrantMutex {
pub unsafe fn uninitialized() -> ReentrantMutex {
ReentrantMutex { inner: ptr::null() }
}
#[inline]
pub unsafe fn init(&mut self) {
let _ = abi::recmutex_init(&mut self.inner as *mut *const c_void);
}
#[inline]
pub unsafe fn lock(&self) {
let _ = abi::recmutex_lock(self.inner);
}
#[inline]
pub unsafe fn try_lock(&self) -> bool {
true
}
#[inline]
pub unsafe fn unlock(&self) {
let _ = abi::recmutex_unlock(self.inner);
}
#[inline]
pub unsafe fn destroy(&self) {
let _ = abi::recmutex_destroy(self.inner);
}
}

View File

@ -0,0 +1,364 @@
use crate::fmt;
use crate::convert::TryFrom;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
use crate::str;
use crate::sys::{unsupported, Void};
use crate::time::Duration;
//// Iinitializes HermitCore's network stack
pub unsafe fn init() -> io::Result<()> {
Ok(())
}
pub struct TcpStream(Void);
impl TcpStream {
pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
unsupported()
}
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
unsupported()
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
match self.0 {}
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
match self.0 {}
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
match self.0 {}
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
match self.0 {}
}
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn nodelay(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn ttl(&self) -> io::Result<u32> {
match self.0 {}
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match self.0 {}
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
}
impl fmt::Debug for TcpStream {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {}
}
}
pub struct TcpListener(Void);
impl TcpListener {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
unsupported()
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
match self.0 {}
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
match self.0 {}
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn ttl(&self) -> io::Result<u32> {
match self.0 {}
}
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn only_v6(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match self.0 {}
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
}
impl fmt::Debug for TcpListener {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {}
}
}
pub struct UdpSocket(Void);
impl UdpSocket {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
unsupported()
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
match self.0 {}
}
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
match self.0 {}
}
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
match self.0 {}
}
pub fn duplicate(&self) -> io::Result<UdpSocket> {
match self.0 {}
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
}
pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn broadcast(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
match self.0 {}
}
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
-> io::Result<()> {
match self.0 {}
}
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
-> io::Result<()> {
match self.0 {}
}
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
-> io::Result<()> {
match self.0 {}
}
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
-> io::Result<()> {
match self.0 {}
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn ttl(&self) -> io::Result<u32> {
match self.0 {}
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match self.0 {}
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn send(&self, _: &[u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
match self.0 {}
}
}
impl fmt::Debug for UdpSocket {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {}
}
}
pub struct LookupHost(Void);
impl LookupHost {
pub fn port(&self) -> u16 {
match self.0 {}
}
}
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
match self.0 {}
}
}
impl TryFrom<&str> for LookupHost {
type Error = io::Error;
fn try_from(_v: &str) -> io::Result<LookupHost> {
unsupported()
}
}
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
type Error = io::Error;
fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
unsupported()
}
}
#[allow(nonstandard_style)]
pub mod netc {
pub const AF_INET: u8 = 0;
pub const AF_INET6: u8 = 1;
pub type sa_family_t = u8;
#[derive(Copy, Clone)]
pub struct in_addr {
pub s_addr: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: u16,
pub sin_addr: in_addr,
}
#[derive(Copy, Clone)]
pub struct in6_addr {
pub s6_addr: [u8; 16],
}
#[derive(Copy, Clone)]
pub struct sockaddr_in6 {
pub sin6_family: sa_family_t,
pub sin6_port: u16,
pub sin6_addr: in6_addr,
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr {
}
pub type socklen_t = usize;
}

174
src/libstd/sys/hermit/os.rs Normal file
View File

@ -0,0 +1,174 @@
use crate::error::Error as StdError;
use crate::ffi::{CStr, OsString, OsStr};
use crate::fmt;
use crate::io;
use crate::marker::PhantomData;
use crate::memchr;
use crate::path::{self, PathBuf};
use crate::ptr;
use crate::str;
use crate::sys::{unsupported, Void};
use crate::collections::HashMap;
use crate::vec;
use crate::sync::Mutex;
use crate::sys_common::os_str_bytes::*;
use crate::sys::hermit::abi;
pub fn errno() -> i32 {
0
}
pub fn error_string(_errno: i32) -> String {
"operation successful".to_string()
}
pub fn getcwd() -> io::Result<PathBuf> {
unsupported()
}
pub fn chdir(_: &path::Path) -> io::Result<()> {
unsupported()
}
pub struct SplitPaths<'a>(&'a Void);
pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
panic!("unsupported")
}
impl<'a> Iterator for SplitPaths<'a> {
type Item = PathBuf;
fn next(&mut self) -> Option<PathBuf> {
match *self.0 {}
}
}
#[derive(Debug)]
pub struct JoinPathsError;
pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
where I: Iterator<Item=T>, T: AsRef<OsStr>
{
Err(JoinPathsError)
}
impl fmt::Display for JoinPathsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"not supported on hermit yet".fmt(f)
}
}
impl StdError for JoinPathsError {
fn description(&self) -> &str {
"not supported on hermit yet"
}
}
pub fn current_exe() -> io::Result<PathBuf> {
unsupported()
}
static mut ENV: Option<Mutex<HashMap<OsString, OsString>>> = None;
pub fn init_environment(env: *const *const i8) {
unsafe {
ENV = Some(Mutex::new(HashMap::new()));
let mut guard = ENV.as_ref().unwrap().lock().unwrap();
let mut environ = env;
while environ != ptr::null() && *environ != ptr::null() {
if let Some((key,value)) = parse(CStr::from_ptr(*environ).to_bytes()) {
guard.insert(key, value);
}
environ = environ.offset(1);
}
}
fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
// Strategy (copied from glibc): Variable name and value are separated
// by an ASCII equals sign '='. Since a variable name must not be
// empty, allow variable names starting with an equals sign. Skip all
// malformed lines.
if input.is_empty() {
return None;
}
let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
pos.map(|p| (
OsStringExt::from_vec(input[..p].to_vec()),
OsStringExt::from_vec(input[p+1..].to_vec()),
))
}
}
pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
_dont_send_or_sync_me: PhantomData<*mut ()>,
}
impl Iterator for Env {
type Item = (OsString, OsString);
fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}
/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
unsafe {
let guard = ENV.as_ref().unwrap().lock().unwrap();
let mut result = Vec::new();
for (key, value) in guard.iter() {
result.push((key.clone(), value.clone()));
}
return Env {
iter: result.into_iter(),
_dont_send_or_sync_me: PhantomData,
}
}
}
pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
unsafe {
match ENV.as_ref().unwrap().lock().unwrap().get_mut(k) {
Some(value) => { Ok(Some(value.clone())) },
None => { Ok(None) },
}
}
}
pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
unsafe {
let (k, v) = (k.to_owned(), v.to_owned());
ENV.as_ref().unwrap().lock().unwrap().insert(k, v);
}
Ok(())
}
pub fn unsetenv(k: &OsStr) -> io::Result<()> {
unsafe {
ENV.as_ref().unwrap().lock().unwrap().remove(k);
}
Ok(())
}
pub fn temp_dir() -> PathBuf {
panic!("no filesystem on hermit")
}
pub fn home_dir() -> Option<PathBuf> {
None
}
pub fn exit(code: i32) -> ! {
unsafe {
abi::exit(code);
}
}
pub fn getpid() -> u32 {
unsafe {
abi::getpid()
}
}

View File

@ -0,0 +1,19 @@
use crate::path::Prefix;
use crate::ffi::OsStr;
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
b == b'/'
}
#[inline]
pub fn is_verbatim_sep(b: u8) -> bool {
b == b'/'
}
pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
None
}
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';

View File

@ -0,0 +1,33 @@
use crate::io::{self, IoSlice, IoSliceMut};
use crate::sys::Void;
pub struct AnonPipe(Void);
impl AnonPipe {
pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
match self.0 {}
}
pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
match self.0 {}
}
pub fn diverge(&self) -> ! {
match self.0 {}
}
}
pub fn read2(p1: AnonPipe,
_v1: &mut Vec<u8>,
_p2: AnonPipe,
_v2: &mut Vec<u8>) -> io::Result<()> {
match p1.0 {}
}

View File

@ -0,0 +1,154 @@
use crate::ffi::OsStr;
use crate::fmt;
use crate::io;
use crate::sys::fs::File;
use crate::sys::pipe::AnonPipe;
use crate::sys::{unsupported, Void};
use crate::sys_common::process::CommandEnv;
pub use crate::ffi::OsString as EnvKey;
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
pub struct Command {
env: CommandEnv,
}
// passed back to std::process with the pipes connected to the child, if any
// were requested
pub struct StdioPipes {
pub stdin: Option<AnonPipe>,
pub stdout: Option<AnonPipe>,
pub stderr: Option<AnonPipe>,
}
pub enum Stdio {
Inherit,
Null,
MakePipe,
}
impl Command {
pub fn new(_program: &OsStr) -> Command {
Command {
env: Default::default()
}
}
pub fn arg(&mut self, _arg: &OsStr) {
}
pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}
pub fn cwd(&mut self, _dir: &OsStr) {
}
pub fn stdin(&mut self, _stdin: Stdio) {
}
pub fn stdout(&mut self, _stdout: Stdio) {
}
pub fn stderr(&mut self, _stderr: Stdio) {
}
pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool)
-> io::Result<(Process, StdioPipes)> {
unsupported()
}
}
impl From<AnonPipe> for Stdio {
fn from(pipe: AnonPipe) -> Stdio {
pipe.diverge()
}
}
impl From<File> for Stdio {
fn from(file: File) -> Stdio {
file.diverge()
}
}
impl fmt::Debug for Command {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
pub struct ExitStatus(Void);
impl ExitStatus {
pub fn success(&self) -> bool {
match self.0 {}
}
pub fn code(&self) -> Option<i32> {
match self.0 {}
}
}
impl Clone for ExitStatus {
fn clone(&self) -> ExitStatus {
match self.0 {}
}
}
impl Copy for ExitStatus {}
impl PartialEq for ExitStatus {
fn eq(&self, _other: &ExitStatus) -> bool {
match self.0 {}
}
}
impl Eq for ExitStatus {
}
impl fmt::Debug for ExitStatus {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {}
}
}
impl fmt::Display for ExitStatus {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {}
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitCode(bool);
impl ExitCode {
pub const SUCCESS: ExitCode = ExitCode(false);
pub const FAILURE: ExitCode = ExitCode(true);
pub fn as_i32(&self) -> i32 {
self.0 as i32
}
}
pub struct Process(Void);
impl Process {
pub fn id(&self) -> u32 {
match self.0 {}
}
pub fn kill(&mut self) -> io::Result<()> {
match self.0 {}
}
pub fn wait(&mut self) -> io::Result<ExitStatus> {
match self.0 {}
}
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
match self.0 {}
}
}

View File

@ -0,0 +1,51 @@
use super::mutex::Mutex;
pub struct RWLock {
mutex: Mutex
}
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
impl RWLock {
pub const fn new() -> RWLock {
RWLock {
mutex: Mutex::new()
}
}
#[inline]
pub unsafe fn read(&self) {
self.mutex.lock();
}
#[inline]
pub unsafe fn try_read(&self) -> bool {
self.mutex.try_lock()
}
#[inline]
pub unsafe fn write(&self) {
self.mutex.lock();
}
#[inline]
pub unsafe fn try_write(&self) -> bool {
self.mutex.try_lock()
}
#[inline]
pub unsafe fn read_unlock(&self) {
self.mutex.unlock();
}
#[inline]
pub unsafe fn write_unlock(&self) {
self.mutex.unlock();
}
#[inline]
pub unsafe fn destroy(&self) {
self.mutex.destroy();
}
}

View File

@ -0,0 +1,15 @@
pub struct Handler;
impl Handler {
pub unsafe fn new() -> Handler {
Handler
}
}
#[inline]
pub unsafe fn init() {
}
#[inline]
pub unsafe fn cleanup() {
}

View File

@ -0,0 +1,119 @@
use crate::io;
use crate::io::{IoSlice, IoSliceMut};
use crate::sys::hermit::abi;
pub struct Stdin;
pub struct Stdout;
pub struct Stderr;
impl Stdin {
pub fn new() -> io::Result<Stdin> {
Ok(Stdin)
}
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
self.read_vectored(&mut [IoSliceMut::new(data)])
}
pub fn read_vectored(&self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
//ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) })
// .read(data)
Ok(0)
}
}
impl Stdout {
pub fn new() -> io::Result<Stdout> {
Ok(Stdout)
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
let len;
unsafe {
len = abi::write(1, data.as_ptr() as *const u8, data.len())
}
if len < 0 {
Err(io::Error::new(io::ErrorKind::Other, "Stdout is not able to print"))
} else {
Ok(len as usize)
}
}
pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
let len;
unsafe {
len = abi::write(1, data.as_ptr() as *const u8, data.len())
}
if len < 0 {
Err(io::Error::new(io::ErrorKind::Other, "Stdout is not able to print"))
} else {
Ok(len as usize)
}
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
}
impl Stderr {
pub fn new() -> io::Result<Stderr> {
Ok(Stderr)
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
let len;
unsafe {
len = abi::write(2, data.as_ptr() as *const u8, data.len())
}
if len < 0 {
Err(io::Error::new(io::ErrorKind::Other, "Stderr is not able to print"))
} else {
Ok(len as usize)
}
}
pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
let len;
unsafe {
len = abi::write(2, data.as_ptr() as *const u8, data.len())
}
if len < 0 {
Err(io::Error::new(io::ErrorKind::Other, "Stderr is not able to print"))
} else {
Ok(len as usize)
}
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
}
impl io::Write for Stderr {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
(&*self).write(data)
}
fn flush(&mut self) -> io::Result<()> {
(&*self).flush()
}
}
pub const STDIN_BUF_SIZE: usize = 0;
pub fn is_ebadf(_err: &io::Error) -> bool {
true
}
pub fn panic_output() -> Option<impl io::Write> {
Stderr::new().ok()
}

View File

@ -0,0 +1,116 @@
#![allow(dead_code)]
use crate::ffi::CStr;
use crate::io;
use crate::sys::hermit::abi;
use crate::time::Duration;
use crate::mem;
use crate::fmt;
use core::u32;
use crate::sys_common::thread::*;
pub type Tid = abi::Tid;
/// Priority of a task
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub struct Priority(u8);
impl Priority {
pub const fn into(self) -> u8 {
self.0
}
pub const fn from(x: u8) -> Self {
Priority(x)
}
}
impl fmt::Display for Priority {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
pub const NORMAL_PRIO: Priority = Priority::from(2);
pub struct Thread {
tid: Tid
}
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
pub const DEFAULT_MIN_STACK_SIZE: usize = 262144;
impl Thread {
pub unsafe fn new_with_coreid(_stack: usize, p: Box<dyn FnOnce()>, core_id: isize)
-> io::Result<Thread>
{
let p = box p;
let mut tid: Tid = u32::MAX;
let ret = abi::spawn(&mut tid as *mut Tid, thread_start,
&*p as *const _ as *const u8 as usize,
Priority::into(NORMAL_PRIO), core_id);
return if ret == 0 {
mem::forget(p); // ownership passed to pthread_create
Ok(Thread { tid: tid })
} else {
Err(io::Error::new(io::ErrorKind::Other, "Unable to create thread!"))
};
extern fn thread_start(main: usize) {
unsafe {
start_thread(main as *mut u8);
}
}
}
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>)
-> io::Result<Thread>
{
Thread::new_with_coreid(stack, p, -1 /* = no specific core */)
}
#[inline]
pub fn yield_now() {
unsafe {
abi::yield_now();
}
}
#[inline]
pub fn set_name(_name: &CStr) {
// nope
}
#[inline]
pub fn sleep(dur: Duration) {
unsafe {
abi::usleep(dur.as_micros() as u64);
}
}
pub fn join(self) {
unsafe {
let _ = abi::join(self.tid);
}
}
#[inline]
pub fn id(&self) -> Tid { self.tid }
#[inline]
pub fn into_id(self) -> Tid {
let id = self.tid;
mem::forget(self);
id
}
}
pub mod guard {
pub type Guard = !;
pub unsafe fn current() -> Option<Guard> { None }
pub unsafe fn init() -> Option<Guard> { None }
}

View File

@ -0,0 +1,61 @@
#![allow(dead_code)] // not used on all platforms
use crate::collections::BTreeMap;
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering};
pub type Key = usize;
type Dtor = unsafe extern fn(*mut u8);
static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();
#[thread_local]
static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();
unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
if KEYS == ptr::null_mut() {
KEYS = Box::into_raw(Box::new(BTreeMap::new()));
}
&mut *KEYS
}
unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
if LOCALS == ptr::null_mut() {
LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
}
&mut *LOCALS
}
#[inline]
pub unsafe fn create(dtor: Option<Dtor>) -> Key {
let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
keys().insert(key, dtor);
key
}
#[inline]
pub unsafe fn get(key: Key) -> *mut u8 {
if let Some(&entry) = locals().get(&key) {
entry
} else {
ptr::null_mut()
}
}
#[inline]
pub unsafe fn set(key: Key, value: *mut u8) {
locals().insert(key, value);
}
#[inline]
pub unsafe fn destroy(key: Key) {
keys().remove(&key);
}
#[inline]
pub fn requires_synchronized_create() -> bool {
false
}

View File

@ -0,0 +1,176 @@
#![allow(dead_code)]
use crate::time::Duration;
use crate::cmp::Ordering;
use crate::convert::TryInto;
use core::hash::{Hash, Hasher};
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::{CLOCK_REALTIME, CLOCK_MONOTONIC, NSEC_PER_SEC};
use crate::sys::hermit::abi::timespec;
#[derive(Copy, Clone, Debug)]
struct Timespec {
t: timespec
}
impl Timespec {
const fn zero() -> Timespec {
Timespec {
t: timespec { tv_sec: 0, tv_nsec: 0 },
}
}
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
if self >= other {
Ok(if self.t.tv_nsec >= other.t.tv_nsec {
Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
(self.t.tv_nsec - other.t.tv_nsec) as u32)
} else {
Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
other.t.tv_nsec as u32)
})
} else {
match other.sub_timespec(self) {
Ok(d) => Err(d),
Err(d) => Ok(d),
}
}
}
fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
.try_into() // <- target type would be `libc::time_t`
.ok()
.and_then(|secs| self.t.tv_sec.checked_add(secs))?;
// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
if nsec >= NSEC_PER_SEC as u32 {
nsec -= NSEC_PER_SEC as u32;
secs = secs.checked_add(1)?;
}
Some(Timespec {
t: timespec {
tv_sec: secs,
tv_nsec: nsec as _,
},
})
}
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
.try_into() // <- target type would be `libc::time_t`
.ok()
.and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
// Similar to above, nanos can't overflow.
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
if nsec < 0 {
nsec += NSEC_PER_SEC as i32;
secs = secs.checked_sub(1)?;
}
Some(Timespec {
t: timespec {
tv_sec: secs,
tv_nsec: nsec as _,
},
})
}
}
impl PartialEq for Timespec {
fn eq(&self, other: &Timespec) -> bool {
self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
}
}
impl Eq for Timespec {}
impl PartialOrd for Timespec {
fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Timespec {
fn cmp(&self, other: &Timespec) -> Ordering {
let me = (self.t.tv_sec, self.t.tv_nsec);
let other = (other.t.tv_sec, other.t.tv_nsec);
me.cmp(&other)
}
}
impl Hash for Timespec {
fn hash<H : Hasher>(&self, state: &mut H) {
self.t.tv_sec.hash(state);
self.t.tv_nsec.hash(state);
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant {
t: Timespec,
}
impl Instant {
pub fn now() -> Instant {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, &mut time.t as *mut timespec) };
Instant { t: time }
}
pub const fn zero() -> Instant {
Instant { t: Timespec::zero() }
}
pub fn actually_monotonic() -> bool {
true
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.t.sub_timespec(&other.t).ok()
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_add_duration(other)? })
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_sub_duration(other)? })
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct SystemTime {
t: Timespec,
}
pub const UNIX_EPOCH: SystemTime = SystemTime {
t: Timespec::zero(),
};
impl SystemTime {
pub fn now() -> SystemTime {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, &mut time.t as *mut timespec) };
SystemTime { t: time }
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_add_duration(other)? })
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
}
}

View File

@ -35,6 +35,9 @@ cfg_if::cfg_if! {
} else if #[cfg(target_os = "cloudabi")] {
mod cloudabi;
pub use self::cloudabi::*;
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use self::hermit::*;
} else if #[cfg(target_os = "wasi")] {
mod wasi;
pub use self::wasi::*;
@ -60,6 +63,7 @@ cfg_if::cfg_if! {
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::ext as unix_ext;
} else if #[cfg(any(target_os = "cloudabi",
target_os = "hermit",
target_arch = "wasm32",
all(target_vendor = "fortanix", target_env = "sgx")))] {
// On CloudABI and wasm right now the module below doesn't compile

View File

@ -53,7 +53,6 @@ unsafe impl GlobalAlloc for System {
}
#[cfg(any(target_os = "android",
target_os = "hermit",
target_os = "redox",
target_os = "solaris"))]
#[inline]
@ -79,7 +78,6 @@ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
}
#[cfg(not(any(target_os = "android",
target_os = "hermit",
target_os = "redox",
target_os = "solaris")))]
#[inline]

View File

@ -56,7 +56,6 @@ impl DoubleEndedIterator for Args {
target_os = "haiku",
target_os = "l4re",
target_os = "fuchsia",
target_os = "hermit",
target_os = "redox"))]
mod imp {
use crate::os::unix::prelude::*;

View File

@ -31,7 +31,6 @@ impl Condvar {
target_os = "ios",
target_os = "l4re",
target_os = "android",
target_os = "hermit",
target_os = "redox"))]
pub unsafe fn init(&mut self) {}
@ -39,7 +38,6 @@ impl Condvar {
target_os = "ios",
target_os = "l4re",
target_os = "android",
target_os = "hermit",
target_os = "redox")))]
pub unsafe fn init(&mut self) {
use crate::mem::MaybeUninit;
@ -78,8 +76,7 @@ impl Condvar {
// from changes made to the system time.
#[cfg(not(any(target_os = "macos",
target_os = "ios",
target_os = "android",
target_os = "hermit")))]
target_os = "android")))]
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
use crate::mem;
@ -109,7 +106,7 @@ impl Condvar {
// This implementation is modeled after libcxx's condition_variable
// https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
// https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))]
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
use crate::ptr;
use crate::time::Instant;

View File

@ -152,17 +152,6 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "hermit")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "hermit";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "redox")]
pub mod os {
pub const FAMILY: &str = "unix";

View File

@ -502,12 +502,12 @@ impl DirEntry {
lstat(&self.path())
}
#[cfg(any(target_os = "solaris", target_os = "haiku", target_os = "hermit"))]
#[cfg(any(target_os = "solaris", target_os = "haiku"))]
pub fn file_type(&self) -> io::Result<FileType> {
lstat(&self.path()).map(|m| m.file_type())
}
#[cfg(not(any(target_os = "solaris", target_os = "haiku", target_os = "hermit")))]
#[cfg(not(any(target_os = "solaris", target_os = "haiku")))]
pub fn file_type(&self) -> io::Result<FileType> {
match self.entry.d_type {
libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
@ -530,7 +530,6 @@ impl DirEntry {
target_os = "haiku",
target_os = "l4re",
target_os = "fuchsia",
target_os = "hermit",
target_os = "redox"))]
pub fn ino(&self) -> u64 {
self.entry.d_ino as u64
@ -561,8 +560,7 @@ impl DirEntry {
target_os = "linux",
target_os = "emscripten",
target_os = "l4re",
target_os = "haiku",
target_os = "hermit"))]
target_os = "haiku"))]
fn name_bytes(&self) -> &[u8] {
unsafe {
CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()

View File

@ -16,7 +16,6 @@ use crate::io::ErrorKind;
#[cfg(all(not(rustdoc), target_os = "emscripten"))] pub use crate::os::emscripten as platform;
#[cfg(all(not(rustdoc), target_os = "fuchsia"))] pub use crate::os::fuchsia as platform;
#[cfg(all(not(rustdoc), target_os = "l4re"))] pub use crate::os::linux as platform;
#[cfg(all(not(rustdoc), target_os = "hermit"))] pub use crate::os::hermit as platform;
#[cfg(all(not(rustdoc), target_os = "redox"))] pub use crate::os::redox as platform;
pub use self::rand::hashmap_random_keys;

View File

@ -43,7 +43,6 @@ extern {
#[cfg_attr(any(target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
target_os = "hermit",
target_os = "redox",
target_env = "newlib"),
link_name = "__errno")]
@ -394,7 +393,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
crate::fs::read_to_string("sys:exe").map(PathBuf::from)
}
#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))]
#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
Err(io::Error::new(ErrorKind::Other, "Not yet implemented!"))

View File

@ -140,7 +140,6 @@ impl Thread {
target_os = "haiku",
target_os = "l4re",
target_os = "emscripten",
target_os = "hermit",
target_os = "redox"))]
pub fn set_name(_name: &CStr) {
// Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.

View File

@ -371,9 +371,9 @@ mod inner {
}
}
#[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))]
#[cfg(not(target_os = "dragonfly"))]
pub type clock_t = libc::c_int;
#[cfg(any(target_os = "dragonfly", target_os = "hermit"))]
#[cfg(target_os = "dragonfly")]
pub type clock_t = libc::c_ulong;
fn now(clock: clock_t) -> Timespec {

View File

@ -49,6 +49,7 @@ pub mod mutex;
unix,
target_os = "redox",
target_os = "cloudabi",
target_os = "hermit",
target_arch = "wasm32",
all(target_vendor = "fortanix", target_env = "sgx")))]
pub mod os_str_bytes;
@ -67,6 +68,7 @@ pub mod fs;
cfg_if::cfg_if! {
if #[cfg(any(target_os = "cloudabi",
target_os = "l4re",
target_os = "hermit",
all(target_arch = "wasm32", not(target_os = "emscripten")),
all(target_vendor = "fortanix", target_env = "sgx")))] {
pub use crate::sys::net;

View File

@ -17,7 +17,7 @@ doc = false
[dependencies]
core = { path = "../libcore" }
libc = { version = "0.2.43", features = ['rustc-dep-of-std'], default-features = false }
libc = { version = "0.2.51", features = ['rustc-dep-of-std'], default-features = false }
compiler_builtins = "0.1.0"
cfg-if = "0.1.8"

View File

@ -52,6 +52,7 @@ static TARGETS: &[&str] = &[
"aarch64-linux-android",
"aarch64-pc-windows-msvc",
"aarch64-unknown-cloudabi",
"aarch64-unknown-hermit",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"aarch64-unknown-redox",
@ -136,6 +137,7 @@ static TARGETS: &[&str] = &[
"x86_64-unknown-linux-musl",
"x86_64-unknown-netbsd",
"x86_64-unknown-redox",
"x86_64-unknown-hermit",
];
static DOCS_TARGETS: &[&str] = &[

View File

@ -181,6 +181,7 @@ const WHITELIST: &[Crate<'_>] = &[
Crate("winapi-util"),
Crate("winapi-x86_64-pc-windows-gnu"),
Crate("wincolor"),
Crate("hermit-abi"),
];
// Some types for Serde to deserialize the output of `cargo metadata` to.