redesign of the interface to the unikernel HermitCore

- the old interface between HermitCore and the Rust Standard Library
  based on a small C library (newlib)
- remove this interface and call directly the unikernel
- remove the dependency to the HermitCore linker
- use rust-lld as linker
This commit is contained in:
Stefan Lankes 2019-10-06 15:26:14 +00:00
parent 7870050796
commit c1e440a90f
51 changed files with 2388 additions and 451 deletions

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

@ -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

@ -59,7 +59,6 @@ fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindS
#[cfg(not(test))]
#[lang = "start"]
fn lang_start<T: crate::process::Termination + 'static>
(main: fn() -> T, argc: isize, argv: *const *const u8) -> isize
{
(main: fn() -> T, argc: isize, argv: *const *const u8) -> isize {
lang_start_internal(&move || main().report(), argc, argv)
}

View file

@ -0,0 +1,40 @@
use crate::alloc::{GlobalAlloc, Layout, System};
use crate::ptr;
extern "C" {
fn sys_malloc(size: usize, align: usize) -> *mut u8;
fn sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8;
fn sys_free(ptr: *mut u8, size: usize, align: usize);
}
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
sys_malloc(layout.size(), layout.align())
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let addr = sys_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) {
sys_free(ptr, layout.size(), layout.align())
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
sys_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,68 @@
use crate::cmp;
use crate::sys::mutex::Mutex;
use crate::time::Duration;
pub struct Condvar {
identifier: usize,
}
extern "C" {
fn sys_notify(id: usize, count: i32) -> i32;
fn sys_add_queue(id: usize, timeout_ns: i64) -> i32;
fn sys_wait(id: usize) -> i32;
fn sys_destroy_queue(id: usize) -> i32;
}
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 _ = sys_notify(self.id(), 1);
}
#[inline]
pub unsafe fn notify_all(&self) {
let _ = sys_notify(self.id(), -1 /* =all */);
}
pub unsafe fn wait(&self, mutex: &Mutex) {
// add current task to the wait queue
let _ = sys_add_queue(self.id(), -1 /* no timeout */);
mutex.unlock();
let _ = sys_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 _ = sys_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 = sys_wait(self.id()) == 0;
mutex.lock();
ret
}
#[inline]
pub unsafe fn destroy(&self) {
let _ = sys_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,87 @@
#![unstable(reason = "not public", issue = "0", feature = "fd")]
use crate::io::{self, Read, ErrorKind};
use crate::mem;
use crate::sys::cvt;
use crate::sys_common::AsInner;
extern {
fn sys_read(fd: i32, buf: *mut u8, len: usize) -> isize;
fn sys_write(fd: i32, buf: *const u8, len: usize) -> isize;
fn sys_close(fd: i32) -> i32;
}
#[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 { sys_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 { sys_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 { sys_close(self.fd) };
}
}

389
src/libstd/sys/hermit/fs.rs Normal file
View file

@ -0,0 +1,389 @@
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::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;
extern {
fn sys_open(name: *const i8, flags: i32, mode: i32) -> i32;
fn sys_unlink(name: *const i8) -> i32;
}
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(sys_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(sys_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,148 @@
//! 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;
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() -> ! {
extern "C" {
fn sys_abort() ->!;
}
sys_abort();
}
// TODO: 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;
fn sys_exit(arg: i32) ->!;
}
// initialize environment
os::init_environment(env as *const *const i8);
let result = main(argc as isize, argv);
sys_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,88 @@
use crate::ptr;
use crate::ffi::c_void;
extern "C" {
fn sys_sem_init(sem: *mut *const c_void, value: u32) -> i32;
fn sys_sem_destroy(sem: *const c_void) -> i32;
fn sys_sem_post(sem: *const c_void) -> i32;
fn sys_sem_trywait(sem: *const c_void) -> i32;
fn sys_sem_timedwait(sem: *const c_void, ms: u32) -> i32;
fn sys_recmutex_init(recmutex: *mut *const c_void) -> i32;
fn sys_recmutex_destroy(recmutex: *const c_void) -> i32;
fn sys_recmutex_lock(recmutex: *const c_void) -> i32;
fn sys_recmutex_unlock(recmutex: *const c_void) -> i32;
}
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 _ = sys_sem_init(&mut self.inner as *mut *const c_void, 1);
}
#[inline]
pub unsafe fn lock(&self) {
let _ = sys_sem_timedwait(self.inner, 0);
}
#[inline]
pub unsafe fn unlock(&self) {
let _ = sys_sem_post(self.inner);
}
#[inline]
pub unsafe fn try_lock(&self) -> bool {
let result = sys_sem_trywait(self.inner);
result == 0
}
#[inline]
pub unsafe fn destroy(&self) {
let _ = sys_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 _ = sys_recmutex_init(&mut self.inner as *mut *const c_void);
}
#[inline]
pub unsafe fn lock(&self) {
let _ = sys_recmutex_lock(self.inner);
}
#[inline]
pub unsafe fn try_lock(&self) -> bool {
true
}
#[inline]
pub unsafe fn unlock(&self) {
let _ = sys_recmutex_unlock(self.inner);
}
#[inline]
pub unsafe fn destroy(&self) {
let _ = sys_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;
}

178
src/libstd/sys/hermit/os.rs Normal file
View file

@ -0,0 +1,178 @@
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::*;
extern "C" {
fn sys_getpid() -> u32;
fn sys_exit(arg: i32) ->!;
}
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 {
sys_exit(code);
}
}
pub fn getpid() -> u32 {
unsafe {
sys_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,122 @@
use crate::io;
use crate::io::{IoSlice, IoSliceMut};
extern "C" {
fn sys_write(fd: i32, buf: *const u8, len: usize) -> isize;
}
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 = sys_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 = sys_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 = sys_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 = sys_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,121 @@
#![allow(dead_code)]
use crate::ffi::CStr;
use crate::io;
use crate::time::Duration;
use crate::mem;
use crate::fmt;
use core::u32;
use crate::sys_common::thread::*;
pub type Tid = u32;
/// 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);
extern "C" {
fn sys_usleep(usecs: u64);
fn sys_spawn(id: *mut Tid, func: extern "C" fn(usize), arg: usize, prio: u8, core_id: isize) -> i32;
fn sys_join(id: Tid) -> i32;
fn sys_yield();
}
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 = sys_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 {
sys_yield();
}
}
#[inline]
pub fn set_name(_name: &CStr) {
// nope
}
#[inline]
pub fn sleep(dur: Duration) {
unsafe {
sys_usleep(dur.as_micros() as u64);
}
}
pub fn join(self) {
unsafe {
let _ = sys_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,188 @@
#![allow(dead_code)]
use crate::time::Duration;
use crate::cmp::Ordering;
use crate::convert::TryInto;
use core::hash::{Hash, Hasher};
const NSEC_PER_SEC: u64 = 1_000_000_000;
const CLOCK_REALTIME: u64 = 1;
const CLOCK_MONOTONIC: u64 = 4;
extern "C" {
fn sys_clock_gettime(clock_id: u64, tp: *mut timespec) -> i32;
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct timespec {
pub tv_sec: i64,
pub tv_nsec: i64,
}
#[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 { sys_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 { sys_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

@ -319,12 +319,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 }),
@ -347,7 +347,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
@ -378,8 +377,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

@ -1052,6 +1052,7 @@ fn use_color(opts: &TestOpts) -> bool {
#[cfg(any(
target_os = "cloudabi",
target_os = "hermit",
all(target_arch = "wasm32", not(target_os = "emscripten")),
all(target_vendor = "fortanix", target_env = "sgx")
))]
@ -1308,6 +1309,12 @@ fn get_concurrency() -> usize {
1
}
#[cfg(target_os = "hermit")]
fn num_cpus() -> usize {
// FIXME: Implement num_cpus on HermitCore
1
}
#[cfg(any(
all(target_arch = "wasm32", not(target_os = "emscripten")),
all(target_vendor = "fortanix", target_env = "sgx")

View file

@ -43,6 +43,8 @@ fn main() {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("redox") {
// redox is handled in lib.rs
} else if target.contains("hermit") {
//println!("cargo:rustc-link-lib=unwind");
} else if target.contains("cloudabi") {
println!("cargo:rustc-link-lib=unwind");
}

View file

@ -1,7 +1,26 @@
#![allow(nonstandard_style)]
#[cfg(not(target_os = "hermit"))]
use libc::{c_int, c_void, uintptr_t};
#[cfg(target_os = "hermit")]
pub type c_int = i32;
#[cfg(target_os = "hermit")]
pub type uintptr_t = usize;
#[cfg(target_os = "hermit")]
#[repr(u8)]
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub enum c_void {
// Two dummy variants so the #[repr] attribute can be used.
#[doc(hidden)]
__variant1,
#[doc(hidden)]
__variant2,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum _Unwind_Reason_Code {

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] = &[