diff --git a/Cargo.lock b/Cargo.lock index fb81c0637cca9..75fc148535597 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1316,6 +1316,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" @@ -4147,6 +4158,7 @@ dependencies = [ "dlmalloc", "fortanix-sgx-abi", "hashbrown 0.6.2", + "hermit-abi", "libc", "panic_abort", "panic_unwind", diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d1cf1cbca7844..cbdb174c02d97 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -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) { } diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index fd144d6b67e75..5509f47bc8858 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -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() -> !; } diff --git a/src/libpanic_unwind/hermit.rs b/src/libpanic_unwind/hermit.rs new file mode 100644 index 0000000000000..8bee6ff09e551 --- /dev/null +++ b/src/libpanic_unwind/hermit.rs @@ -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 { + extern "C" { pub fn __rust_abort() -> !; } + __rust_abort(); +} + +pub unsafe fn panic(_data: Box) -> u32 { + extern "C" { pub fn __rust_abort() -> !; } + __rust_abort(); +} diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 06e6e768f459c..2089a02083c59 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -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; diff --git a/src/librustc_target/spec/hermit_base.rs b/src/librustc_target/spec/hermit_base.rs index ee753393ddb3d..f31de4dbd5194 100644 --- a/src/librustc_target/spec/hermit_base.rs +++ b/src/librustc_target/spec/hermit_base.rs @@ -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() } } diff --git a/src/librustc_target/spec/x86_64_unknown_hermit.rs b/src/librustc_target/spec/x86_64_unknown_hermit.rs index a696ee16d7c9e..b8be43be09766 100644 --- a/src/librustc_target/spec/x86_64_unknown_hermit.rs +++ b/src/librustc_target/spec/x86_64_unknown_hermit.rs @@ -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, }) } diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index d5ce9456f7f66..11f45c5f6d01c 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -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", diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index efe5c9d28f0d2..c55911a33f524 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -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'] } diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 8db7bc12cd308..1f839f165320f 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -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"); } } diff --git a/src/libstd/os/hermit/fs.rs b/src/libstd/os/hermit/fs.rs deleted file mode 100644 index eb28a839ba865..0000000000000 --- a/src/libstd/os/hermit/fs.rs +++ /dev/null @@ -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 - } -} diff --git a/src/libstd/os/hermit/mod.rs b/src/libstd/os/hermit/mod.rs deleted file mode 100644 index 4dee2a6d43397..0000000000000 --- a/src/libstd/os/hermit/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! HermitCore-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/src/libstd/os/hermit/raw.rs b/src/libstd/os/hermit/raw.rs deleted file mode 100644 index 0e232a808a097..0000000000000 --- a/src/libstd/os/hermit/raw.rs +++ /dev/null @@ -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}; diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index fcd81f0a1b2de..d44c8ca544e80 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -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; diff --git a/src/libstd/sys/hermit/alloc.rs b/src/libstd/sys/hermit/alloc.rs new file mode 100644 index 0000000000000..86cc446363288 --- /dev/null +++ b/src/libstd/sys/hermit/alloc.rs @@ -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) + } +} diff --git a/src/libstd/sys/hermit/args.rs b/src/libstd/sys/hermit/args.rs new file mode 100644 index 0000000000000..5b1f3add51fe0 --- /dev/null +++ b/src/libstd/sys/hermit/args.rs @@ -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, + _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 { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { 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 { 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 { + 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() + } + } +} diff --git a/src/libstd/sys/hermit/cmath.rs b/src/libstd/sys/hermit/cmath.rs new file mode 100644 index 0000000000000..fa7783122c2e9 --- /dev/null +++ b/src/libstd/sys/hermit/cmath.rs @@ -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; +} diff --git a/src/libstd/sys/hermit/condvar.rs b/src/libstd/sys/hermit/condvar.rs new file mode 100644 index 0000000000000..8e52b3da1b170 --- /dev/null +++ b/src/libstd/sys/hermit/condvar.rs @@ -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 + } +} diff --git a/src/libstd/sys/hermit/env.rs b/src/libstd/sys/hermit/env.rs new file mode 100644 index 0000000000000..7a0fcb31ef2e8 --- /dev/null +++ b/src/libstd/sys/hermit/env.rs @@ -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 = ""; +} diff --git a/src/libstd/sys/hermit/fast_thread_local.rs b/src/libstd/sys/hermit/fast_thread_local.rs new file mode 100644 index 0000000000000..05464787a05d3 --- /dev/null +++ b/src/libstd/sys/hermit/fast_thread_local.rs @@ -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; diff --git a/src/libstd/sys/hermit/fd.rs b/src/libstd/sys/hermit/fd.rs new file mode 100644 index 0000000000000..84c547366473a --- /dev/null +++ b/src/libstd/sys/hermit/fd.rs @@ -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 { + 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) -> io::Result { + let mut me = self; + (&mut me).read_to_end(buf) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + let result = unsafe { abi::write(self.fd, buf.as_ptr(), buf.len()) }; + cvt(result as i32) + } + + pub fn duplicate(&self) -> io::Result { + self.duplicate_path(&[]) + } + pub fn duplicate_path(&self, _path: &[u8]) -> io::Result { + Err(io::Error::new(ErrorKind::Other, "duplicate isn't supported")) + } + + pub fn nonblocking(&self) -> io::Result { + 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 { + (**self).read(buf) + } +} + +impl AsInner 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) }; + } +} diff --git a/src/libstd/sys/hermit/fs.rs b/src/libstd/sys/hermit/fs.rs new file mode 100644 index 0000000000000..f8e5844a1678d --- /dev/null +++ b/src/libstd/sys/hermit/fs.rs @@ -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 { + 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 { + match self.0 {} + } + + pub fn accessed(&self) -> io::Result { + match self.0 {} + } + + pub fn created(&self) -> io::Result { + 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(&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; + + fn next(&mut self) -> Option> { + 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 { + match self.0 {} + } + + pub fn file_type(&self) -> io::Result { + 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 { + 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 { + 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 { + let path = cstr(path)?; + File::open_c(&path, opts) + } + + pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result { + 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 { + 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 { + self.0.read(buf) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + 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 { + Err(Error::from_raw_os_error(22)) + } + + pub fn duplicate(&self) -> io::Result { + 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 { + 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 { + 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 { + unsupported() +} + +pub fn lstat(_p: &Path) -> io::Result { + unsupported() +} + +pub fn canonicalize(_p: &Path) -> io::Result { + unsupported() +} diff --git a/src/libstd/sys/hermit/io.rs b/src/libstd/sys/hermit/io.rs new file mode 100644 index 0000000000000..976e122463d1b --- /dev/null +++ b/src/libstd/sys/hermit/io.rs @@ -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 + } +} diff --git a/src/libstd/sys/hermit/memchr.rs b/src/libstd/sys/hermit/memchr.rs new file mode 100644 index 0000000000000..9967482197eb3 --- /dev/null +++ b/src/libstd/sys/hermit/memchr.rs @@ -0,0 +1 @@ +pub use core::slice::memchr::{memchr, memrchr}; diff --git a/src/libstd/sys/hermit/mod.rs b/src/libstd/sys/hermit/mod.rs new file mode 100644 index 0000000000000..d4359631769da --- /dev/null +++ b/src/libstd/sys/hermit/mod.rs @@ -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() -> crate::io::Result { + 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 { + if result < 0 { + Err(crate::io::Error::from_raw_os_error(-result)) + } else { + Ok(result as usize) + } +} diff --git a/src/libstd/sys/hermit/mutex.rs b/src/libstd/sys/hermit/mutex.rs new file mode 100644 index 0000000000000..9414bf8fbbbd4 --- /dev/null +++ b/src/libstd/sys/hermit/mutex.rs @@ -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); + } +} diff --git a/src/libstd/sys/hermit/net.rs b/src/libstd/sys/hermit/net.rs new file mode 100644 index 0000000000000..5b7ff642271c5 --- /dev/null +++ b/src/libstd/sys/hermit/net.rs @@ -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 { + unsupported() + } + + pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { + unsupported() + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn read_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn write_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn read(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { + match self.0 {} + } + + pub fn write(&self, _: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { + match self.0 {} + } + + pub fn peer_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn socket_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn nodelay(&self) -> io::Result { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result> { + 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 { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result { + match self.0 {} + } + + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn only_v6(&self) -> io::Result { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result> { + 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 { + unsupported() + } + + pub fn peer_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn socket_addr(&self) -> io::Result { + 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 { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn read_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn write_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_broadcast(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn broadcast(&self) -> io::Result { + match self.0 {} + } + + pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_loop_v4(&self) -> io::Result { + match self.0 {} + } + + pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + match self.0 {} + } + + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_loop_v6(&self) -> io::Result { + 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 { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn recv(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn send(&self, _: &[u8]) -> io::Result { + 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 { + match self.0 {} + } +} + +impl TryFrom<&str> for LookupHost { + type Error = io::Error; + + fn try_from(_v: &str) -> io::Result { + unsupported() + } +} + +impl<'a> TryFrom<(&'a str, u16)> for LookupHost { + type Error = io::Error; + + fn try_from(_v: (&'a str, u16)) -> io::Result { + 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; +} diff --git a/src/libstd/sys/hermit/os.rs b/src/libstd/sys/hermit/os.rs new file mode 100644 index 0000000000000..8a25cbcf07b9c --- /dev/null +++ b/src/libstd/sys/hermit/os.rs @@ -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 { + 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 { + match *self.0 {} + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(_paths: I) -> Result + where I: Iterator, T: AsRef +{ + 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 { + unsupported() +} + +static mut ENV: Option>> = 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) { 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> { + 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 { + None +} + +pub fn exit(code: i32) -> ! { + unsafe { + abi::exit(code); + } +} + +pub fn getpid() -> u32 { + unsafe { + abi::getpid() + } +} diff --git a/src/libstd/sys/hermit/path.rs b/src/libstd/sys/hermit/path.rs new file mode 100644 index 0000000000000..7a18395610785 --- /dev/null +++ b/src/libstd/sys/hermit/path.rs @@ -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> { + None +} + +pub const MAIN_SEP_STR: &str = "/"; +pub const MAIN_SEP: char = '/'; diff --git a/src/libstd/sys/hermit/pipe.rs b/src/libstd/sys/hermit/pipe.rs new file mode 100644 index 0000000000000..9f07f054362fe --- /dev/null +++ b/src/libstd/sys/hermit/pipe.rs @@ -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 { + match self.0 {} + } + + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self.0 {} + } + + pub fn write(&self, _buf: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +pub fn read2(p1: AnonPipe, + _v1: &mut Vec, + _p2: AnonPipe, + _v2: &mut Vec) -> io::Result<()> { + match p1.0 {} +} diff --git a/src/libstd/sys/hermit/process.rs b/src/libstd/sys/hermit/process.rs new file mode 100644 index 0000000000000..edf933d10e074 --- /dev/null +++ b/src/libstd/sys/hermit/process.rs @@ -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, + pub stdout: Option, + pub stderr: Option, +} + +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 for Stdio { + fn from(pipe: AnonPipe) -> Stdio { + pipe.diverge() + } +} + +impl From 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 { + 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 { + match self.0 {} + } + + pub fn try_wait(&mut self) -> io::Result> { + match self.0 {} + } +} diff --git a/src/libstd/sys/hermit/rwlock.rs b/src/libstd/sys/hermit/rwlock.rs new file mode 100644 index 0000000000000..990e7551114bb --- /dev/null +++ b/src/libstd/sys/hermit/rwlock.rs @@ -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(); + } +} diff --git a/src/libstd/sys/hermit/stack_overflow.rs b/src/libstd/sys/hermit/stack_overflow.rs new file mode 100644 index 0000000000000..b339e433e77de --- /dev/null +++ b/src/libstd/sys/hermit/stack_overflow.rs @@ -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() { +} diff --git a/src/libstd/sys/hermit/stdio.rs b/src/libstd/sys/hermit/stdio.rs new file mode 100644 index 0000000000000..9505f02fda83b --- /dev/null +++ b/src/libstd/sys/hermit/stdio.rs @@ -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 { + Ok(Stdin) + } + + pub fn read(&self, data: &mut [u8]) -> io::Result { + self.read_vectored(&mut [IoSliceMut::new(data)]) + } + + pub fn read_vectored(&self, _data: &mut [IoSliceMut<'_>]) -> io::Result { + //ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) }) + // .read(data) + Ok(0) + } + +} + +impl Stdout { + pub fn new() -> io::Result { + Ok(Stdout) + } + + pub fn write(&self, data: &[u8]) -> io::Result { + 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 { + 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 { + Ok(Stderr) + } + + pub fn write(&self, data: &[u8]) -> io::Result { + 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 { + 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 { + (&*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 { + Stderr::new().ok() +} diff --git a/src/libstd/sys/hermit/thread.rs b/src/libstd/sys/hermit/thread.rs new file mode 100644 index 0000000000000..99a9c830c9e0a --- /dev/null +++ b/src/libstd/sys/hermit/thread.rs @@ -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, core_id: isize) + -> io::Result + { + 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) + -> io::Result + { + 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 { None } + pub unsafe fn init() -> Option { None } +} diff --git a/src/libstd/sys/hermit/thread_local.rs b/src/libstd/sys/hermit/thread_local.rs new file mode 100644 index 0000000000000..4bc8c4d5883da --- /dev/null +++ b/src/libstd/sys/hermit/thread_local.rs @@ -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> = ptr::null_mut(); + +#[thread_local] +static mut LOCALS: *mut BTreeMap = ptr::null_mut(); + +unsafe fn keys() -> &'static mut BTreeMap> { + if KEYS == ptr::null_mut() { + KEYS = Box::into_raw(Box::new(BTreeMap::new())); + } + &mut *KEYS +} + +unsafe fn locals() -> &'static mut BTreeMap { + if LOCALS == ptr::null_mut() { + LOCALS = Box::into_raw(Box::new(BTreeMap::new())); + } + &mut *LOCALS +} + +#[inline] +pub unsafe fn create(dtor: Option) -> 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 +} diff --git a/src/libstd/sys/hermit/time.rs b/src/libstd/sys/hermit/time.rs new file mode 100644 index 0000000000000..8372189546d07 --- /dev/null +++ b/src/libstd/sys/hermit/time.rs @@ -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 { + 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 { + 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 { + 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 { + 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(&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 { + self.t.sub_timespec(&other.t).ok() + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant { t: self.t.checked_add_duration(other)? }) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + 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 { + self.t.sub_timespec(&other.t) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(SystemTime { t: self.t.checked_add_duration(other)? }) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime { t: self.t.checked_sub_duration(other)? }) + } +} diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index 5a5859a6ad873..16b0539cdb9f9 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -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 diff --git a/src/libstd/sys/unix/alloc.rs b/src/libstd/sys/unix/alloc.rs index f47dc92d2de93..cf4900b48943e 100644 --- a/src/libstd/sys/unix/alloc.rs +++ b/src/libstd/sys/unix/alloc.rs @@ -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] diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index 288e9b5c12620..82ef35ea7b5d5 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -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::*; diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index 0a93fbf8ea779..6be844ded1936 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -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; diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs index d724eeb8b3fde..984bcfa45099b 100644 --- a/src/libstd/sys/unix/env.rs +++ b/src/libstd/sys/unix/env.rs @@ -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"; diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 39cc120594aab..b34ebf7dae6ef 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -489,12 +489,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 { 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 { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -517,7 +517,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 @@ -548,8 +547,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() diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index b1f7aac8b4b40..d0bed0f038e6c 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -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; diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 169bb57ef78df..10cdb25999ca9 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -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 { 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 { use crate::io::ErrorKind; Err(io::Error::new(ErrorKind::Other, "Not yet implemented!")) diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 988881e35966f..72b0ac493da15 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -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. diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index fd6796ad22c12..a9122defa5506 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -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 { diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index cba3eca538625..7a0bcd03d758f 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -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; diff --git a/src/libunwind/Cargo.toml b/src/libunwind/Cargo.toml index f10df8c85ba0a..77bcfffd506c9 100644 --- a/src/libunwind/Cargo.toml +++ b/src/libunwind/Cargo.toml @@ -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" diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index c0d2deab2f8ba..2a189a92f4b12 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -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] = &[ diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 8e46ca6cd2990..e6ea1c75e2899 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -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.