From c4b02659c16d2ad0ac36d2c8602edd002e559f7a Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Thu, 11 Jun 2020 17:44:21 -0700 Subject: Enable some timeouts in SGX platform This would partially resolve https://github.com/fortanix/rust-sgx/issues/31 --- src/libstd/sys/sgx/abi/usercalls/mod.rs | 24 ++++++- src/libstd/sys/sgx/condvar.rs | 6 +- src/libstd/sys/sgx/mod.rs | 45 ++++++++++++- src/libstd/sys/sgx/thread.rs | 6 +- src/libstd/sys/sgx/waitqueue.rs | 113 ++++++++++++++++++++++++++++++-- 5 files changed, 179 insertions(+), 15 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs index ae803ee47a6..b223da9d7e4 100644 --- a/src/libstd/sys/sgx/abi/usercalls/mod.rs +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -1,5 +1,6 @@ use crate::cmp; use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult}; +use crate::sys::rand::rdrand64; use crate::time::Duration; pub(crate) mod alloc; @@ -149,7 +150,28 @@ pub fn exit(panic: bool) -> ! { /// Usercall `wait`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn wait(event_mask: u64, timeout: u64) -> IoResult { +pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult { + if timeout != WAIT_NO && timeout != WAIT_INDEFINITE { + // We don't want people to rely on accuracy of timeouts to make + // security decisions in an SGX enclave. That's why we add a random + // amount not exceeding +/- 10% to the timeout value to discourage + // people from relying on accuracy of timeouts while providing a way + // to make things work in other cases. Note that in the SGX threat + // model the enclave runner which is serving the wait usercall is not + // trusted to ensure accurate timeouts. + let base = cmp::max(1, timeout / 10) * 2 + 1; + let zero = base / 2; + match rdrand64() % base { + jitter if jitter > zero => { + timeout = timeout.checked_add(jitter - zero).unwrap_or(timeout) + } + jitter if jitter < zero => { + timeout = timeout.checked_sub(zero - jitter).unwrap_or(timeout) + } + _ => {} + }; + timeout = cmp::min(u64::MAX - 1, cmp::max(1, timeout)); + } unsafe { raw::wait(event_mask, timeout).from_sgx_result() } } diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs index 9c5c086184d..ed6dbcf4971 100644 --- a/src/libstd/sys/sgx/condvar.rs +++ b/src/libstd/sys/sgx/condvar.rs @@ -31,8 +31,10 @@ impl Condvar { mutex.lock() } - pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { - rtabort!("timeout not supported in SGX"); + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + let success = WaitQueue::wait_timeout(&self.inner, dur, || mutex.unlock()); + mutex.lock(); + success } #[inline] diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index 397dd496ae8..dff9d3b1f07 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -110,6 +110,42 @@ pub fn decode_error_kind(code: i32) -> ErrorKind { } } +// This function makes an effort to sleep at least as long as `duration`. +// Note that in general there is no guarantee about accuracy of time and +// timeouts in SGX model. The enclave runner serving usercalls may lie about +// current time and/or ignore timeout values. +// +// FIXME: note these caveats in documentation of all public types that use this +// function in their execution path. +pub fn wait_timeout_sgx(event_mask: u64, duration: crate::time::Duration) { + use self::abi::usercalls; + use crate::cmp; + use crate::io::ErrorKind; + use crate::time::Instant; + + let start = Instant::now(); + let mut remaining = duration; + loop { + let timeout = cmp::min((u64::MAX - 1) as u128, remaining.as_nanos()) as u64; + match usercalls::wait(event_mask, timeout) { + Ok(eventset) => { + if event_mask != 0 { + rtassert!(eventset & event_mask == event_mask); + return; + } + rtabort!("expected usercalls::wait() to return Err, found Ok."); + } + Err(e) => { + rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock) + } + } + remaining = match duration.checked_sub(start.elapsed()) { + Some(remaining) => remaining, + None => break, + } + } +} + // 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)] @@ -137,8 +173,8 @@ pub extern "C" fn __rust_abort() { abort_internal(); } -pub fn hashmap_random_keys() -> (u64, u64) { - fn rdrand64() -> u64 { +pub mod rand { + pub fn rdrand64() -> u64 { unsafe { let mut ret: u64 = 0; for _ in 0..10 { @@ -149,7 +185,10 @@ pub fn hashmap_random_keys() -> (u64, u64) { rtabort!("Failed to obtain random data"); } } - (rdrand64(), rdrand64()) +} + +pub fn hashmap_random_keys() -> (u64, u64) { + (self::rand::rdrand64(), self::rand::rdrand64()) } pub use crate::sys_common::{AsInner, FromInner, IntoInner}; diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs index 9b515eb82de..8ff0f1fde91 100644 --- a/src/libstd/sys/sgx/thread.rs +++ b/src/libstd/sys/sgx/thread.rs @@ -1,6 +1,8 @@ #![cfg_attr(test, allow(dead_code))] // why is this necessary? + use crate::ffi::CStr; use crate::io; +use crate::sys::wait_timeout_sgx; use crate::time::Duration; use super::abi::usercalls; @@ -73,8 +75,8 @@ impl Thread { // FIXME: could store this pointer in TLS somewhere } - pub fn sleep(_dur: Duration) { - rtabort!("can't sleep"); // FIXME + pub fn sleep(dur: Duration) { + wait_timeout_sgx(0, dur); } pub fn join(self) { diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs index 6e50f161b3b..71d1c22cd61 100644 --- a/src/libstd/sys/sgx/waitqueue.rs +++ b/src/libstd/sys/sgx/waitqueue.rs @@ -1,4 +1,3 @@ -use crate::num::NonZeroUsize; /// A simple queue implementation for synchronization primitives. /// /// This queue is used to implement condition variable and mutexes. @@ -10,7 +9,10 @@ use crate::num::NonZeroUsize; /// Since userspace may send spurious wake-ups, the wakeup event state is /// recorded in the enclave. The wakeup event state is protected by a spinlock. /// The queue and associated wait state are stored in a `WaitVariable`. +use crate::num::NonZeroUsize; use crate::ops::{Deref, DerefMut}; +use crate::sys::wait_timeout_sgx; +use crate::time::Duration; use super::abi::thread; use super::abi::usercalls; @@ -158,6 +160,37 @@ impl WaitQueue { } } + /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait + /// until a wakeup event or timeout. If event was observed, returns true. + /// If not, it will remove the calling thread from the wait queue. + pub fn wait_timeout( + lock: &SpinMutex>, + timeout: Duration, + before_wait: F, + ) -> bool { + // very unsafe: check requirements of UnsafeList::push + unsafe { + let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry { + tcs: thread::current(), + wake: false, + })); + let entry_lock = lock.lock().queue.inner.push(&mut entry); + before_wait(); + // don't panic, this would invalidate `entry` during unwinding + wait_timeout_sgx(EV_UNPARK, timeout); + // acquire the wait queue's lock first to avoid deadlock. + let mut guard = lock.lock(); + let entry_guard = entry_lock.lock(); + let success = entry_guard.wake; + if !success { + // nobody is waking us up, so remove the entry from the wait queue. + drop(entry_guard); + guard.queue.inner.remove(&mut entry); + } + success + } + } + /// Either find the next waiter on the wait queue, or return the mutex /// guard unchanged. /// @@ -325,6 +358,31 @@ mod unsafe_list { Some((*first.as_ptr()).value.as_ref().unwrap()) } } + + /// Removes an entry from the list. + /// + /// # Safety + /// + /// The caller must ensure that entry has been pushed prior to this + /// call and has not moved since push. + pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry) { + rtassert!(!self.is_empty()); + // BEFORE: + // /----\ next ---> /-----\ next ---> /----\ + // ... |prev| |entry| |next| ... + // \----/ <--- prev \-----/ <--- prev \----/ + // + // AFTER: + // /----\ next ---> /----\ + // ... |prev| |next| ... + // \----/ <--- prev \----/ + let mut prev = entry.prev; + let mut next = entry.next; + prev.as_mut().next = next; + next.as_mut().prev = prev; + entry.next = NonNull::dangling(); + entry.prev = NonNull::dangling(); + } } #[cfg(test)] @@ -354,6 +412,51 @@ mod unsafe_list { } } + #[test] + fn push_remove() { + unsafe { + let mut node = UnsafeListEntry::new(1234); + let mut list = UnsafeList::new(); + assert_eq!(list.push(&mut node), &1234); + list.remove(&mut node); + assert_empty(&mut list); + } + } + + #[test] + fn push_remove_pop() { + unsafe { + let mut node1 = UnsafeListEntry::new(11); + let mut node2 = UnsafeListEntry::new(12); + let mut node3 = UnsafeListEntry::new(13); + let mut node4 = UnsafeListEntry::new(14); + let mut node5 = UnsafeListEntry::new(15); + let mut list = UnsafeList::new(); + assert_eq!(list.push(&mut node1), &11); + assert_eq!(list.push(&mut node2), &12); + assert_eq!(list.push(&mut node3), &13); + assert_eq!(list.push(&mut node4), &14); + assert_eq!(list.push(&mut node5), &15); + + list.remove(&mut node1); + assert_eq!(list.pop().unwrap(), &12); + list.remove(&mut node3); + assert_eq!(list.pop().unwrap(), &14); + list.remove(&mut node5); + assert_empty(&mut list); + + assert_eq!(list.push(&mut node1), &11); + assert_eq!(list.pop().unwrap(), &11); + assert_empty(&mut list); + + assert_eq!(list.push(&mut node3), &13); + assert_eq!(list.push(&mut node4), &14); + list.remove(&mut node3); + list.remove(&mut node4); + assert_empty(&mut list); + } + } + #[test] fn complex_pushes_pops() { unsafe { @@ -474,7 +577,7 @@ mod spin_mutex { use super::*; use crate::sync::Arc; use crate::thread; - use crate::time::{Duration, SystemTime}; + use crate::time::Duration; #[test] fn sleep() { @@ -485,11 +588,7 @@ mod spin_mutex { *mutex2.lock() = 1; }); - // "sleep" for 50ms - // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - let start = SystemTime::now(); - let max = Duration::from_millis(50); - while start.elapsed().unwrap() < max {} + thread::sleep(Duration::from_millis(50)); assert_eq!(*guard, 0); drop(guard); -- cgit 1.4.1-3-g733a5 From d7dc64bdfea4fbf8974774800ab51e04eaa4f082 Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Fri, 12 Jun 2020 12:06:41 -0700 Subject: Handle spurious wakeups in wait_timeout_sgx --- src/libstd/sys/sgx/mod.rs | 16 ++++++++++++---- src/libstd/sys/sgx/thread.rs | 2 +- src/libstd/sys/sgx/waitqueue.rs | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index dff9d3b1f07..b72e4fb06f3 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -115,9 +115,15 @@ pub fn decode_error_kind(code: i32) -> ErrorKind { // timeouts in SGX model. The enclave runner serving usercalls may lie about // current time and/or ignore timeout values. // +// Once the event is observed, `stop` will be used to determine whether or not +// we should continue to wait. +// // FIXME: note these caveats in documentation of all public types that use this // function in their execution path. -pub fn wait_timeout_sgx(event_mask: u64, duration: crate::time::Duration) { +pub fn wait_timeout_sgx(event_mask: u64, duration: crate::time::Duration, stop: F) +where + F: Fn() -> bool, +{ use self::abi::usercalls; use crate::cmp; use crate::io::ErrorKind; @@ -129,11 +135,13 @@ pub fn wait_timeout_sgx(event_mask: u64, duration: crate::time::Duration) { let timeout = cmp::min((u64::MAX - 1) as u128, remaining.as_nanos()) as u64; match usercalls::wait(event_mask, timeout) { Ok(eventset) => { - if event_mask != 0 { - rtassert!(eventset & event_mask == event_mask); + if event_mask == 0 { + rtabort!("expected usercalls::wait() to return Err, found Ok."); + } + rtassert!(eventset & event_mask == event_mask); + if stop() { return; } - rtabort!("expected usercalls::wait() to return Err, found Ok."); } Err(e) => { rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock) diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs index 8ff0f1fde91..5636a6f7eab 100644 --- a/src/libstd/sys/sgx/thread.rs +++ b/src/libstd/sys/sgx/thread.rs @@ -76,7 +76,7 @@ impl Thread { } pub fn sleep(dur: Duration) { - wait_timeout_sgx(0, dur); + wait_timeout_sgx(0, dur, || true); } pub fn join(self) { diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs index 71d1c22cd61..36b3f5bcc41 100644 --- a/src/libstd/sys/sgx/waitqueue.rs +++ b/src/libstd/sys/sgx/waitqueue.rs @@ -177,7 +177,7 @@ impl WaitQueue { let entry_lock = lock.lock().queue.inner.push(&mut entry); before_wait(); // don't panic, this would invalidate `entry` during unwinding - wait_timeout_sgx(EV_UNPARK, timeout); + wait_timeout_sgx(EV_UNPARK, timeout, || entry_lock.lock().wake); // acquire the wait queue's lock first to avoid deadlock. let mut guard = lock.lock(); let entry_guard = entry_lock.lock(); -- cgit 1.4.1-3-g733a5 From 3442d23c1a12f1f01a0e07b6bec72b58998f49ef Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Thu, 18 Jun 2020 12:50:10 -0700 Subject: Improve wait_timeout_sgx, simplify usercalls::wait --- src/libstd/sys/sgx/abi/usercalls/mod.rs | 17 +++------ src/libstd/sys/sgx/mod.rs | 67 ++++++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 28 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs index b223da9d7e4..69ff7ebf9a1 100644 --- a/src/libstd/sys/sgx/abi/usercalls/mod.rs +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -1,4 +1,5 @@ use crate::cmp; +use crate::convert::TryFrom; use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult}; use crate::sys::rand::rdrand64; use crate::time::Duration; @@ -159,17 +160,11 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult { // to make things work in other cases. Note that in the SGX threat // model the enclave runner which is serving the wait usercall is not // trusted to ensure accurate timeouts. - let base = cmp::max(1, timeout / 10) * 2 + 1; - let zero = base / 2; - match rdrand64() % base { - jitter if jitter > zero => { - timeout = timeout.checked_add(jitter - zero).unwrap_or(timeout) - } - jitter if jitter < zero => { - timeout = timeout.checked_sub(zero - jitter).unwrap_or(timeout) - } - _ => {} - }; + if let Ok(timeout_signed) = i64::try_from(timeout) { + let tenth = 1 + timeout_signed / 10; + let deviation = (rdrand64() as i64).checked_rem(tenth).unwrap_or(0); + timeout = timeout_signed.saturating_add(deviation) as _; + } timeout = cmp::min(u64::MAX - 1, cmp::max(1, timeout)); } unsafe { raw::wait(event_mask, timeout).from_sgx_result() } diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index b72e4fb06f3..1c957d8ff80 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -110,43 +110,76 @@ pub fn decode_error_kind(code: i32) -> ErrorKind { } } -// This function makes an effort to sleep at least as long as `duration`. -// Note that in general there is no guarantee about accuracy of time and -// timeouts in SGX model. The enclave runner serving usercalls may lie about -// current time and/or ignore timeout values. +// This function makes an effort to wait for a non-spurious event at least as +// long as `duration`. Note that in general there is no guarantee about accuracy +// of time and timeouts in SGX model. The enclave runner serving usercalls may +// lie about current time and/or ignore timeout values. // -// Once the event is observed, `stop` will be used to determine whether or not -// we should continue to wait. +// Once the event is observed, `woken_up` will be used to determine whether or +// not the event was spurious. // // FIXME: note these caveats in documentation of all public types that use this // function in their execution path. -pub fn wait_timeout_sgx(event_mask: u64, duration: crate::time::Duration, stop: F) +pub fn wait_timeout_sgx(event_mask: u64, duration: crate::time::Duration, woken_up: F) where F: Fn() -> bool, { use self::abi::usercalls; use crate::cmp; use crate::io::ErrorKind; - use crate::time::Instant; - - let start = Instant::now(); - let mut remaining = duration; - loop { - let timeout = cmp::min((u64::MAX - 1) as u128, remaining.as_nanos()) as u64; + use crate::time::{Duration, Instant}; + + // Calls the wait usercall and checks the result. Returns true if event was + // returned, and false if WouldBlock/TimedOut was returned. + // If duration is None, it will use WAIT_NO. + fn wait_checked(event_mask: u64, duration: Option) -> bool { + let timeout = duration.map_or(usercalls::raw::WAIT_NO, |duration| { + cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64 + }); match usercalls::wait(event_mask, timeout) { Ok(eventset) => { if event_mask == 0 { rtabort!("expected usercalls::wait() to return Err, found Ok."); } rtassert!(eventset & event_mask == event_mask); - if stop() { - return; - } + true } Err(e) => { - rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock) + rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock); + false } } + } + + match wait_checked(event_mask, Some(duration)) { + false => return, // timed out + true if woken_up() => return, // woken up + true => {} // spurious event + } + + // Drain all cached events. + // Note that `event_mask != 0` is implied if we get here. + loop { + match wait_checked(event_mask, None) { + false => break, // no more cached events + true if woken_up() => return, // woken up + true => {} // spurious event + } + } + + // Continue waiting, but take note of time spent waiting so we don't wait + // forever. We intentionally don't call `Instant::now()` before this point + // to avoid the cost of the `insecure_time` usercall in case there are no + // spurious wakeups. + + let start = Instant::now(); + let mut remaining = duration; + loop { + match wait_checked(event_mask, Some(remaining)) { + false => return, // timed out + true if woken_up() => return, // woken up + true => {} // spurious event + } remaining = match duration.checked_sub(start.elapsed()) { Some(remaining) => remaining, None => break, -- cgit 1.4.1-3-g733a5 From c457b67af394c37826f75d73cca10319ee96b910 Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Wed, 1 Jul 2020 12:45:11 -0700 Subject: Remove unnecessary check in SGX wait usercall --- src/libstd/sys/sgx/abi/usercalls/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs index 69ff7ebf9a1..6ee147d1704 100644 --- a/src/libstd/sys/sgx/abi/usercalls/mod.rs +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -161,11 +161,10 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult { // model the enclave runner which is serving the wait usercall is not // trusted to ensure accurate timeouts. if let Ok(timeout_signed) = i64::try_from(timeout) { - let tenth = 1 + timeout_signed / 10; + let tenth = timeout_signed / 10; let deviation = (rdrand64() as i64).checked_rem(tenth).unwrap_or(0); timeout = timeout_signed.saturating_add(deviation) as _; } - timeout = cmp::min(u64::MAX - 1, cmp::max(1, timeout)); } unsafe { raw::wait(event_mask, timeout).from_sgx_result() } } -- cgit 1.4.1-3-g733a5 From 1466598e19321bc6b97aef8271a317e78211d54d Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Fri, 10 Jul 2020 19:57:31 -0700 Subject: Address review comments --- src/libstd/sys/sgx/mod.rs | 31 +++++++++++++++---------------- src/libstd/sys/sgx/thread.rs | 5 ++--- src/libstd/sys/sgx/waitqueue.rs | 37 +++++++++++++++++-------------------- src/test/ui/mpsc_stress.rs | 1 + 4 files changed, 35 insertions(+), 39 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index 1c957d8ff80..c412053112b 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -115,12 +115,9 @@ pub fn decode_error_kind(code: i32) -> ErrorKind { // of time and timeouts in SGX model. The enclave runner serving usercalls may // lie about current time and/or ignore timeout values. // -// Once the event is observed, `woken_up` will be used to determine whether or -// not the event was spurious. -// -// FIXME: note these caveats in documentation of all public types that use this -// function in their execution path. -pub fn wait_timeout_sgx(event_mask: u64, duration: crate::time::Duration, woken_up: F) +// Once the event is observed, `should_wake_up` will be used to determine +// whether or not the event was spurious. +pub fn usercall_wait_timeout(event_mask: u64, duration: crate::time::Duration, should_wake_up: F) where F: Fn() -> bool, { @@ -141,7 +138,9 @@ where if event_mask == 0 { rtabort!("expected usercalls::wait() to return Err, found Ok."); } - rtassert!(eventset & event_mask == event_mask); + // A matching event is one whose bits are equal to or a subset + // of `event_mask`. + rtassert!(eventset & !event_mask == 0); true } Err(e) => { @@ -152,18 +151,18 @@ where } match wait_checked(event_mask, Some(duration)) { - false => return, // timed out - true if woken_up() => return, // woken up - true => {} // spurious event + false => return, // timed out + true if should_wake_up() => return, // woken up + true => {} // spurious event } // Drain all cached events. // Note that `event_mask != 0` is implied if we get here. loop { match wait_checked(event_mask, None) { - false => break, // no more cached events - true if woken_up() => return, // woken up - true => {} // spurious event + false => break, // no more cached events + true if should_wake_up() => return, // woken up + true => {} // spurious event } } @@ -176,9 +175,9 @@ where let mut remaining = duration; loop { match wait_checked(event_mask, Some(remaining)) { - false => return, // timed out - true if woken_up() => return, // woken up - true => {} // spurious event + false => return, // timed out + true if should_wake_up() => return, // woken up + true => {} // spurious event } remaining = match duration.checked_sub(start.elapsed()) { Some(remaining) => remaining, diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs index 5636a6f7eab..58b6f4346bc 100644 --- a/src/libstd/sys/sgx/thread.rs +++ b/src/libstd/sys/sgx/thread.rs @@ -1,8 +1,7 @@ #![cfg_attr(test, allow(dead_code))] // why is this necessary? - use crate::ffi::CStr; use crate::io; -use crate::sys::wait_timeout_sgx; +use crate::sys::usercall_wait_timeout; use crate::time::Duration; use super::abi::usercalls; @@ -76,7 +75,7 @@ impl Thread { } pub fn sleep(dur: Duration) { - wait_timeout_sgx(0, dur, || true); + usercall_wait_timeout(0, dur, || true); } pub fn join(self) { diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs index 36b3f5bcc41..c8ccab2247a 100644 --- a/src/libstd/sys/sgx/waitqueue.rs +++ b/src/libstd/sys/sgx/waitqueue.rs @@ -1,17 +1,17 @@ -/// A simple queue implementation for synchronization primitives. -/// -/// This queue is used to implement condition variable and mutexes. -/// -/// Users of this API are expected to use the `WaitVariable` type. Since -/// that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to -/// allow shared access. -/// -/// Since userspace may send spurious wake-ups, the wakeup event state is -/// recorded in the enclave. The wakeup event state is protected by a spinlock. -/// The queue and associated wait state are stored in a `WaitVariable`. +//! A simple queue implementation for synchronization primitives. +//! +//! This queue is used to implement condition variable and mutexes. +//! +//! Users of this API are expected to use the `WaitVariable` type. Since +//! that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to +//! allow shared access. +//! +//! Since userspace may send spurious wake-ups, the wakeup event state is +//! recorded in the enclave. The wakeup event state is protected by a spinlock. +//! The queue and associated wait state are stored in a `WaitVariable`. use crate::num::NonZeroUsize; use crate::ops::{Deref, DerefMut}; -use crate::sys::wait_timeout_sgx; +use crate::sys::usercall_wait_timeout; use crate::time::Duration; use super::abi::thread; @@ -176,15 +176,12 @@ impl WaitQueue { })); let entry_lock = lock.lock().queue.inner.push(&mut entry); before_wait(); - // don't panic, this would invalidate `entry` during unwinding - wait_timeout_sgx(EV_UNPARK, timeout, || entry_lock.lock().wake); + usercall_wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake); // acquire the wait queue's lock first to avoid deadlock. let mut guard = lock.lock(); - let entry_guard = entry_lock.lock(); - let success = entry_guard.wake; + let success = entry_lock.lock().wake; if !success { - // nobody is waking us up, so remove the entry from the wait queue. - drop(entry_guard); + // nobody is waking us up, so remove our entry from the wait queue. guard.queue.inner.remove(&mut entry); } success @@ -363,8 +360,8 @@ mod unsafe_list { /// /// # Safety /// - /// The caller must ensure that entry has been pushed prior to this - /// call and has not moved since push. + /// The caller must ensure that `entry` has been pushed onto `self` + /// prior to this call and has not moved since then. pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry) { rtassert!(!self.is_empty()); // BEFORE: diff --git a/src/test/ui/mpsc_stress.rs b/src/test/ui/mpsc_stress.rs index 81c000839bd..a889542fec0 100644 --- a/src/test/ui/mpsc_stress.rs +++ b/src/test/ui/mpsc_stress.rs @@ -36,6 +36,7 @@ impl Barrier { fn wait(self) { self.shared.fetch_add(1, Ordering::SeqCst); while self.shared.load(Ordering::SeqCst) != self.count { + #[cfg(target_env = "sgx")] thread::yield_now(); } } -- cgit 1.4.1-3-g733a5 From 6e9a1de0d146734e51cc7e761b288e9b9b138d4f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 31 May 2020 18:09:25 -0700 Subject: Introduce restricted-std feature. --- src/libpanic_unwind/lib.rs | 2 +- src/libproc_macro/lib.rs | 1 + src/librustc_passes/stability.rs | 3 +- src/libstd/build.rs | 3 + src/libstd/lib.rs | 9 +- src/libstd/sys/mod.rs | 3 +- src/libstd/sys/unsupported/alloc.rs | 22 ++ src/libstd/sys/unsupported/args.rs | 38 +++ src/libstd/sys/unsupported/cmath.rs | 29 ++ src/libstd/sys/unsupported/common.rs | 48 ++++ src/libstd/sys/unsupported/condvar.rs | 30 ++ src/libstd/sys/unsupported/env.rs | 9 + src/libstd/sys/unsupported/fs.rs | 308 ++++++++++++++++++++ src/libstd/sys/unsupported/io.rs | 47 +++ src/libstd/sys/unsupported/mod.rs | 24 ++ src/libstd/sys/unsupported/mutex.rs | 67 +++++ src/libstd/sys/unsupported/net.rs | 361 ++++++++++++++++++++++++ src/libstd/sys/unsupported/os.rs | 104 +++++++ src/libstd/sys/unsupported/path.rs | 19 ++ src/libstd/sys/unsupported/pipe.rs | 38 +++ src/libstd/sys/unsupported/process.rs | 149 ++++++++++ src/libstd/sys/unsupported/rwlock.rs | 69 +++++ src/libstd/sys/unsupported/stack_overflow.rs | 3 + src/libstd/sys/unsupported/stdio.rs | 59 ++++ src/libstd/sys/unsupported/thread.rs | 41 +++ src/libstd/sys/unsupported/thread_local_dtor.rs | 9 + src/libstd/sys/unsupported/thread_local_key.rs | 26 ++ src/libstd/sys/unsupported/time.rs | 53 ++++ src/libstd/sys/wasi/mod.rs | 45 +-- src/libstd/sys/wasm/cmath.rs | 29 -- src/libstd/sys/wasm/condvar.rs | 30 -- src/libstd/sys/wasm/fs.rs | 308 -------------------- src/libstd/sys/wasm/io.rs | 47 --- src/libstd/sys/wasm/memchr.rs | 1 - src/libstd/sys/wasm/mod.rs | 63 ++--- src/libstd/sys/wasm/mutex.rs | 66 ----- src/libstd/sys/wasm/net.rs | 361 ------------------------ src/libstd/sys/wasm/os.rs | 107 ------- src/libstd/sys/wasm/path.rs | 19 -- src/libstd/sys/wasm/pipe.rs | 38 --- src/libstd/sys/wasm/process.rs | 149 ---------- src/libstd/sys/wasm/rwlock.rs | 69 ----- src/libstd/sys/wasm/stack_overflow.rs | 3 - src/libstd/sys/wasm/stdio.rs | 59 ---- src/libstd/sys/wasm/thread_local_dtor.rs | 9 - src/libstd/sys/wasm/thread_local_key.rs | 26 -- src/libstd/sys/wasm/time.rs | 53 ---- src/libstd/sys_common/mod.rs | 2 + src/libstd/sys_common/mutex.rs | 1 + src/libunwind/lib.rs | 11 +- src/tools/rustc-std-workspace-std/lib.rs | 1 + 51 files changed, 1614 insertions(+), 1457 deletions(-) create mode 100644 src/libstd/sys/unsupported/alloc.rs create mode 100644 src/libstd/sys/unsupported/args.rs create mode 100644 src/libstd/sys/unsupported/cmath.rs create mode 100644 src/libstd/sys/unsupported/common.rs create mode 100644 src/libstd/sys/unsupported/condvar.rs create mode 100644 src/libstd/sys/unsupported/env.rs create mode 100644 src/libstd/sys/unsupported/fs.rs create mode 100644 src/libstd/sys/unsupported/io.rs create mode 100644 src/libstd/sys/unsupported/mod.rs create mode 100644 src/libstd/sys/unsupported/mutex.rs create mode 100644 src/libstd/sys/unsupported/net.rs create mode 100644 src/libstd/sys/unsupported/os.rs create mode 100644 src/libstd/sys/unsupported/path.rs create mode 100644 src/libstd/sys/unsupported/pipe.rs create mode 100644 src/libstd/sys/unsupported/process.rs create mode 100644 src/libstd/sys/unsupported/rwlock.rs create mode 100644 src/libstd/sys/unsupported/stack_overflow.rs create mode 100644 src/libstd/sys/unsupported/stdio.rs create mode 100644 src/libstd/sys/unsupported/thread.rs create mode 100644 src/libstd/sys/unsupported/thread_local_dtor.rs create mode 100644 src/libstd/sys/unsupported/thread_local_key.rs create mode 100644 src/libstd/sys/unsupported/time.rs delete mode 100644 src/libstd/sys/wasm/cmath.rs delete mode 100644 src/libstd/sys/wasm/condvar.rs delete mode 100644 src/libstd/sys/wasm/fs.rs delete mode 100644 src/libstd/sys/wasm/io.rs delete mode 100644 src/libstd/sys/wasm/memchr.rs delete mode 100644 src/libstd/sys/wasm/mutex.rs delete mode 100644 src/libstd/sys/wasm/net.rs delete mode 100644 src/libstd/sys/wasm/os.rs delete mode 100644 src/libstd/sys/wasm/path.rs delete mode 100644 src/libstd/sys/wasm/pipe.rs delete mode 100644 src/libstd/sys/wasm/process.rs delete mode 100644 src/libstd/sys/wasm/rwlock.rs delete mode 100644 src/libstd/sys/wasm/stack_overflow.rs delete mode 100644 src/libstd/sys/wasm/stdio.rs delete mode 100644 src/libstd/sys/wasm/thread_local_dtor.rs delete mode 100644 src/libstd/sys/wasm/thread_local_key.rs delete mode 100644 src/libstd/sys/wasm/time.rs (limited to 'src/libstd/sys') diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index f361354da2a..26b503cb792 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -41,7 +41,7 @@ cfg_if::cfg_if! { if #[cfg(target_os = "emscripten")] { #[path = "emcc.rs"] mod real_imp; - } else if #[cfg(target_arch = "wasm32")] { + } else if #[cfg(any(target_arch = "wasm32", target_os = "none"))] { #[path = "dummy.rs"] mod real_imp; } else if #[cfg(target_os = "hermit")] { diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 2d5bd7e872b..f960bdecc57 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -26,6 +26,7 @@ #![feature(in_band_lifetimes)] #![feature(negative_impls)] #![feature(optin_builtin_traits)] +#![feature(restricted_std)] #![feature(rustc_attrs)] #![feature(min_specialization)] #![recursion_limit = "256"] diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs index 76bc6b6c85f..5d972c70d13 100644 --- a/src/librustc_passes/stability.rs +++ b/src/librustc_passes/stability.rs @@ -502,7 +502,8 @@ impl Visitor<'tcx> for Checker<'tcx> { match item.kind { hir::ItemKind::ExternCrate(_) => { // compiler-generated `extern crate` items have a dummy span. - if item.span.is_dummy() { + // `std` is still checked for the `restricted-std` feature. + if item.span.is_dummy() && item.ident.as_str() != "std" { return; } diff --git a/src/libstd/build.rs b/src/libstd/build.rs index f33af1ef7f6..8317eedd53f 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -64,4 +64,7 @@ fn main() { println!("cargo:rustc-link-lib=compiler_rt"); } println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap()); + if target.contains("-none") || target.contains("nvptx") { + println!("cargo:rustc-cfg=feature=\"restricted-std\""); + } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 5215db7cdb3..23863b77068 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -197,7 +197,8 @@ //! [primitive types]: ../book/ch03-02-data-types.html //! [rust-discord]: https://discord.gg/rust-lang -#![stable(feature = "rust1", since = "1.0.0")] +#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))] +#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", @@ -552,3 +553,9 @@ include!("primitive_docs.rs"); // the rustdoc documentation for the existing keywords. Using `include!` // because rustdoc only looks for these modules at the crate level. include!("keyword_docs.rs"); + +// This is required to avoid an unstable error when `restricted-std` is not +// enabled. The use of #![feature(restricted_std)] in rustc-std-workspace-std +// is unconditional, so the unstable feature needs to be defined somewhere. +#[cfg_attr(not(feature = "restricted-std"), unstable(feature = "restricted_std", issue = "none"))] +mod __restricted_std_workaround {} diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index 875ff1af920..7b5fac922d0 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -48,7 +48,8 @@ cfg_if::cfg_if! { mod sgx; pub use self::sgx::*; } else { - compile_error!("libstd doesn't compile for this platform yet"); + mod unsupported; + pub use self::unsupported::*; } } diff --git a/src/libstd/sys/unsupported/alloc.rs b/src/libstd/sys/unsupported/alloc.rs new file mode 100644 index 00000000000..8d5d0a2f5cc --- /dev/null +++ b/src/libstd/sys/unsupported/alloc.rs @@ -0,0 +1,22 @@ +use crate::alloc::{GlobalAlloc, Layout, System}; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { + 0 as *mut u8 + } + + #[inline] + unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 { + 0 as *mut u8 + } + + #[inline] + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} + + #[inline] + unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 { + 0 as *mut u8 + } +} diff --git a/src/libstd/sys/unsupported/args.rs b/src/libstd/sys/unsupported/args.rs new file mode 100644 index 00000000000..71d0c5fa13e --- /dev/null +++ b/src/libstd/sys/unsupported/args.rs @@ -0,0 +1,38 @@ +use crate::ffi::OsString; + +pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} +pub unsafe fn cleanup() {} + +pub struct Args {} + +pub fn args() -> Args { + Args {} +} + +impl Args { + pub fn inner_debug(&self) -> &[OsString] { + &[] + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { + None + } + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + 0 + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + None + } +} diff --git a/src/libstd/sys/unsupported/cmath.rs b/src/libstd/sys/unsupported/cmath.rs new file mode 100644 index 00000000000..304cf906b2a --- /dev/null +++ b/src/libstd/sys/unsupported/cmath.rs @@ -0,0 +1,29 @@ +// These symbols are all defined in `compiler-builtins` +extern "C" { + 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/unsupported/common.rs b/src/libstd/sys/unsupported/common.rs new file mode 100644 index 00000000000..80311d26819 --- /dev/null +++ b/src/libstd/sys/unsupported/common.rs @@ -0,0 +1,48 @@ +use crate::io as std_io; + +pub mod memchr { + pub use core::slice::memchr::{memchr, memrchr}; +} + +pub use crate::sys_common::os_str_bytes as os_str; + +// This is not necessarily correct. May want to consider making it part of the +// spec definition? +use crate::os::raw::c_char; + +#[cfg(not(test))] +pub fn init() {} + +pub fn unsupported() -> std_io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> std_io::Error { + std_io::Error::new(std_io::ErrorKind::Other, "operation not supported on this platform") +} + +pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { + crate::io::ErrorKind::Other +} + +pub fn abort_internal() -> ! { + core::intrinsics::abort(); +} + +pub fn hashmap_random_keys() -> (u64, u64) { + (1, 2) +} + +// 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(mut s: *const c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.offset(1); + } + return n; +} diff --git a/src/libstd/sys/unsupported/condvar.rs b/src/libstd/sys/unsupported/condvar.rs new file mode 100644 index 00000000000..a578eee8ccc --- /dev/null +++ b/src/libstd/sys/unsupported/condvar.rs @@ -0,0 +1,30 @@ +use crate::sys::mutex::Mutex; +use crate::time::Duration; + +pub struct Condvar {} + +impl Condvar { + pub const fn new() -> Condvar { + Condvar {} + } + + #[inline] + pub unsafe fn init(&mut self) {} + + #[inline] + pub unsafe fn notify_one(&self) {} + + #[inline] + pub unsafe fn notify_all(&self) {} + + pub unsafe fn wait(&self, _mutex: &Mutex) { + panic!("condvar wait not supported") + } + + pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { + panic!("condvar wait not supported"); + } + + #[inline] + pub unsafe fn destroy(&self) {} +} diff --git a/src/libstd/sys/unsupported/env.rs b/src/libstd/sys/unsupported/env.rs new file mode 100644 index 00000000000..d2efec506c5 --- /dev/null +++ b/src/libstd/sys/unsupported/env.rs @@ -0,0 +1,9 @@ +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = ""; + 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/unsupported/fs.rs b/src/libstd/sys/unsupported/fs.rs new file mode 100644 index 00000000000..ecb5b51cccd --- /dev/null +++ b/src/libstd/sys/unsupported/fs.rs @@ -0,0 +1,308 @@ +use crate::ffi::OsString; +use crate::fmt; +use crate::hash::{Hash, Hasher}; +use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; +use crate::path::{Path, PathBuf}; +use crate::sys::time::SystemTime; +use crate::sys::{unsupported, Void}; + +pub struct File(Void); + +pub struct FileAttr(Void); + +pub struct ReadDir(Void); + +pub struct DirEntry(Void); + +#[derive(Clone, Debug)] +pub struct OpenOptions {} + +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 {} + } + + pub fn read(&mut self, _read: bool) {} + pub fn write(&mut self, _write: bool) {} + pub fn append(&mut self, _append: bool) {} + pub fn truncate(&mut self, _truncate: bool) {} + pub fn create(&mut self, _create: bool) {} + pub fn create_new(&mut self, _create_new: bool) {} +} + +impl File { + pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { + unsupported() + } + + pub fn file_attr(&self) -> io::Result { + match self.0 {} + } + + pub fn fsync(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn datasync(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + match self.0 {} + } + + 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 is_read_vectored(&self) -> bool { + 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 is_write_vectored(&self) -> bool { + match self.0 {} + } + + pub fn flush(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn seek(&self, _pos: SeekFrom) -> io::Result { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder {} + } + + pub fn mkdir(&self, _p: &Path) -> io::Result<()> { + unsupported() + } +} + +impl fmt::Debug for File { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.0 {} + } +} + +pub fn readdir(_p: &Path) -> io::Result { + unsupported() +} + +pub fn unlink(_p: &Path) -> io::Result<()> { + unsupported() +} + +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() +} + +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() +} + +pub fn copy(_from: &Path, _to: &Path) -> io::Result { + unsupported() +} diff --git a/src/libstd/sys/unsupported/io.rs b/src/libstd/sys/unsupported/io.rs new file mode 100644 index 00000000000..d5f475b4310 --- /dev/null +++ b/src/libstd/sys/unsupported/io.rs @@ -0,0 +1,47 @@ +use crate::mem; + +#[derive(Copy, Clone)] +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/unsupported/mod.rs b/src/libstd/sys/unsupported/mod.rs new file mode 100644 index 00000000000..87f655eecd5 --- /dev/null +++ b/src/libstd/sys/unsupported/mod.rs @@ -0,0 +1,24 @@ +pub mod alloc; +pub mod args; +pub mod cmath; +pub mod condvar; +pub mod env; +pub mod fs; +pub mod io; +pub mod mutex; +pub mod net; +pub mod os; +pub mod path; +pub mod pipe; +pub mod process; +pub mod rwlock; +pub mod stack_overflow; +pub mod stdio; +pub mod thread; +#[cfg(target_thread_local)] +pub mod thread_local_dtor; +pub mod thread_local_key; +pub mod time; + +mod common; +pub use common::*; diff --git a/src/libstd/sys/unsupported/mutex.rs b/src/libstd/sys/unsupported/mutex.rs new file mode 100644 index 00000000000..9ef8af52eb5 --- /dev/null +++ b/src/libstd/sys/unsupported/mutex.rs @@ -0,0 +1,67 @@ +use crate::cell::UnsafeCell; + +pub struct Mutex { + locked: UnsafeCell, +} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} // no threads on this platform + +impl Mutex { + #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")] + pub const fn new() -> Mutex { + Mutex { locked: UnsafeCell::new(false) } + } + + #[inline] + pub unsafe fn init(&mut self) {} + + #[inline] + pub unsafe fn lock(&self) { + let locked = self.locked.get(); + assert!(!*locked, "cannot recursively acquire mutex"); + *locked = true; + } + + #[inline] + pub unsafe fn unlock(&self) { + *self.locked.get() = false; + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + let locked = self.locked.get(); + if *locked { + false + } else { + *locked = true; + true + } + } + + #[inline] + pub unsafe fn destroy(&self) {} +} + +// All empty stubs because this platform does not yet support threads, so lock +// acquisition always succeeds. +pub struct ReentrantMutex {} + +impl ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { + ReentrantMutex {} + } + + pub unsafe fn init(&self) {} + + pub unsafe fn lock(&self) {} + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + true + } + + pub unsafe fn unlock(&self) {} + + pub unsafe fn destroy(&self) {} +} diff --git a/src/libstd/sys/unsupported/net.rs b/src/libstd/sys/unsupported/net.rs new file mode 100644 index 00000000000..5c9f1098f9b --- /dev/null +++ b/src/libstd/sys/unsupported/net.rs @@ -0,0 +1,361 @@ +use crate::convert::TryFrom; +use crate::fmt; +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::sys::{unsupported, Void}; +use crate::time::Duration; + +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 is_read_vectored(&self) -> bool { + 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 is_write_vectored(&self) -> bool { + 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/unsupported/os.rs b/src/libstd/sys/unsupported/os.rs new file mode 100644 index 00000000000..0615780c242 --- /dev/null +++ b/src/libstd/sys/unsupported/os.rs @@ -0,0 +1,104 @@ +use super::{unsupported, Void}; +use crate::error::Error as StdError; +use crate::ffi::{OsStr, OsString}; +use crate::fmt; +use crate::io; +use crate::path::{self, PathBuf}; + +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 this platform yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + #[allow(deprecated)] + fn description(&self) -> &str { + "not supported on this platform yet" + } +} + +pub fn current_exe() -> io::Result { + unsupported() +} + +pub struct Env(Void); + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + match self.0 {} + } +} + +pub fn env() -> Env { + panic!("not supported on this platform") +} + +pub fn getenv(_: &OsStr) -> io::Result> { + Ok(None) +} + +pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on this platform")) +} + +pub fn unsetenv(_: &OsStr) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on this platform")) +} + +pub fn temp_dir() -> PathBuf { + panic!("no filesystem on this platform") +} + +pub fn home_dir() -> Option { + None +} + +pub fn exit(_code: i32) -> ! { + crate::intrinsics::abort() +} + +pub fn getpid() -> u32 { + panic!("no pids on this platform") +} diff --git a/src/libstd/sys/unsupported/path.rs b/src/libstd/sys/unsupported/path.rs new file mode 100644 index 00000000000..840a7ae0426 --- /dev/null +++ b/src/libstd/sys/unsupported/path.rs @@ -0,0 +1,19 @@ +use crate::ffi::OsStr; +use crate::path::Prefix; + +#[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/unsupported/pipe.rs b/src/libstd/sys/unsupported/pipe.rs new file mode 100644 index 00000000000..10d0925823e --- /dev/null +++ b/src/libstd/sys/unsupported/pipe.rs @@ -0,0 +1,38 @@ +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 is_read_vectored(&self) -> bool { + 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 is_write_vectored(&self) -> bool { + 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/unsupported/process.rs b/src/libstd/sys/unsupported/process.rs new file mode 100644 index 00000000000..4702e5c5492 --- /dev/null +++ b/src/libstd/sys/unsupported/process.rs @@ -0,0 +1,149 @@ +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/unsupported/rwlock.rs b/src/libstd/sys/unsupported/rwlock.rs new file mode 100644 index 00000000000..d37f34ac935 --- /dev/null +++ b/src/libstd/sys/unsupported/rwlock.rs @@ -0,0 +1,69 @@ +use crate::cell::UnsafeCell; + +pub struct RWLock { + mode: UnsafeCell, +} + +unsafe impl Send for RWLock {} +unsafe impl Sync for RWLock {} // no threads on this platform + +impl RWLock { + pub const fn new() -> RWLock { + RWLock { mode: UnsafeCell::new(0) } + } + + #[inline] + pub unsafe fn read(&self) { + let mode = self.mode.get(); + if *mode >= 0 { + *mode += 1; + } else { + rtabort!("rwlock locked for writing"); + } + } + + #[inline] + pub unsafe fn try_read(&self) -> bool { + let mode = self.mode.get(); + if *mode >= 0 { + *mode += 1; + true + } else { + false + } + } + + #[inline] + pub unsafe fn write(&self) { + let mode = self.mode.get(); + if *mode == 0 { + *mode = -1; + } else { + rtabort!("rwlock locked for reading") + } + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + let mode = self.mode.get(); + if *mode == 0 { + *mode = -1; + true + } else { + false + } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + *self.mode.get() -= 1; + } + + #[inline] + pub unsafe fn write_unlock(&self) { + *self.mode.get() += 1; + } + + #[inline] + pub unsafe fn destroy(&self) {} +} diff --git a/src/libstd/sys/unsupported/stack_overflow.rs b/src/libstd/sys/unsupported/stack_overflow.rs new file mode 100644 index 00000000000..32555394cd5 --- /dev/null +++ b/src/libstd/sys/unsupported/stack_overflow.rs @@ -0,0 +1,3 @@ +pub unsafe fn init() {} + +pub unsafe fn cleanup() {} diff --git a/src/libstd/sys/unsupported/stdio.rs b/src/libstd/sys/unsupported/stdio.rs new file mode 100644 index 00000000000..5a4e4505e93 --- /dev/null +++ b/src/libstd/sys/unsupported/stdio.rs @@ -0,0 +1,59 @@ +use crate::io; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; + +impl Stdin { + pub fn new() -> io::Result { + Ok(Stdin) + } +} + +impl io::Read for Stdin { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + Ok(0) + } +} + +impl Stdout { + pub fn new() -> io::Result { + Ok(Stdout) + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub fn new() -> io::Result { + Ok(Stderr) + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +pub fn panic_output() -> Option> { + None +} diff --git a/src/libstd/sys/unsupported/thread.rs b/src/libstd/sys/unsupported/thread.rs new file mode 100644 index 00000000000..20ae309db30 --- /dev/null +++ b/src/libstd/sys/unsupported/thread.rs @@ -0,0 +1,41 @@ +use super::{unsupported, Void}; +use crate::ffi::CStr; +use crate::io; +use crate::time::Duration; + +pub struct Thread(Void); + +pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; + +impl Thread { + // unsafe: see thread::Builder::spawn_unchecked for safety requirements + pub unsafe fn new(_stack: usize, _p: Box) -> io::Result { + unsupported() + } + + pub fn yield_now() { + // do nothing + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(_dur: Duration) { + panic!("can't sleep"); + } + + pub fn join(self) { + match self.0 {} + } +} + +pub mod guard { + pub type Guard = !; + pub unsafe fn current() -> Option { + None + } + pub unsafe fn init() -> Option { + None + } +} diff --git a/src/libstd/sys/unsupported/thread_local_dtor.rs b/src/libstd/sys/unsupported/thread_local_dtor.rs new file mode 100644 index 00000000000..85d66098302 --- /dev/null +++ b/src/libstd/sys/unsupported/thread_local_dtor.rs @@ -0,0 +1,9 @@ +#![unstable(feature = "thread_local_internals", issue = "none")] + +pub unsafe fn register_dtor(_t: *mut u8, _dtor: unsafe extern "C" fn(*mut u8)) { + // FIXME: right now there is no concept of "thread exit", but this is likely + // going to show up at some point in the form of an exported symbol that the + // wasm runtime is going to be expected to call. For now we basically just + // ignore the arguments, but if such a function starts to exist it will + // likely look like the OSX implementation in `unix/fast_thread_local.rs` +} diff --git a/src/libstd/sys/unsupported/thread_local_key.rs b/src/libstd/sys/unsupported/thread_local_key.rs new file mode 100644 index 00000000000..c31b61cbf56 --- /dev/null +++ b/src/libstd/sys/unsupported/thread_local_key.rs @@ -0,0 +1,26 @@ +pub type Key = usize; + +#[inline] +pub unsafe fn create(_dtor: Option) -> Key { + panic!("should not be used on this target"); +} + +#[inline] +pub unsafe fn set(_key: Key, _value: *mut u8) { + panic!("should not be used on this target"); +} + +#[inline] +pub unsafe fn get(_key: Key) -> *mut u8 { + panic!("should not be used on this target"); +} + +#[inline] +pub unsafe fn destroy(_key: Key) { + panic!("should not be used on this target"); +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + panic!("should not be used on this target"); +} diff --git a/src/libstd/sys/unsupported/time.rs b/src/libstd/sys/unsupported/time.rs new file mode 100644 index 00000000000..8aaf1777f24 --- /dev/null +++ b/src/libstd/sys/unsupported/time.rs @@ -0,0 +1,53 @@ +use crate::time::Duration; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(Duration); + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); + +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); + +impl Instant { + pub fn now() -> Instant { + panic!("time not implemented on this platform") + } + + pub const fn zero() -> Instant { + Instant(Duration::from_secs(0)) + } + + pub fn actually_monotonic() -> bool { + false + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_sub(*other)?)) + } +} + +impl SystemTime { + pub fn now() -> SystemTime { + panic!("time not implemented on this platform") + } + + pub fn sub_time(&self, other: &SystemTime) -> Result { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_sub(*other)?)) + } +} diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index 85f5282034f..2704ff484f9 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -16,21 +16,18 @@ use crate::io as std_io; use crate::mem; -use crate::os::raw::c_char; pub mod alloc; pub mod args; -#[path = "../wasm/cmath.rs"] +#[path = "../unsupported/cmath.rs"] pub mod cmath; -#[path = "../wasm/condvar.rs"] +#[path = "../unsupported/condvar.rs"] pub mod condvar; pub mod env; pub mod fd; pub mod fs; pub mod io; -#[path = "../wasm/memchr.rs"] -pub mod memchr; -#[path = "../wasm/mutex.rs"] +#[path = "../unsupported/mutex.rs"] pub mod mutex; pub mod net; pub mod os; @@ -39,28 +36,22 @@ pub mod ext; pub mod path; pub mod pipe; pub mod process; -#[path = "../wasm/rwlock.rs"] +#[path = "../unsupported/rwlock.rs"] pub mod rwlock; -#[path = "../wasm/stack_overflow.rs"] +#[path = "../unsupported/stack_overflow.rs"] pub mod stack_overflow; pub mod stdio; pub mod thread; -#[path = "../wasm/thread_local_dtor.rs"] +#[path = "../unsupported/thread_local_dtor.rs"] pub mod thread_local_dtor; -#[path = "../wasm/thread_local_key.rs"] +#[path = "../unsupported/thread_local_key.rs"] pub mod thread_local_key; pub mod time; -#[cfg(not(test))] -pub fn init() {} - -pub fn unsupported() -> std_io::Result { - Err(unsupported_err()) -} - -pub fn unsupported_err() -> std_io::Error { - std_io::Error::new(std_io::ErrorKind::Other, "operation not supported on wasm yet") -} +#[path = "../unsupported/common.rs"] +#[allow(unused)] +mod common; +pub use common::*; pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { use std_io::ErrorKind::*; @@ -86,20 +77,6 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { } } -// 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(mut s: *const c_char) -> usize { - let mut n = 0; - while *s != 0 { - n += 1; - s = s.offset(1); - } - return n; -} - pub fn abort_internal() -> ! { unsafe { libc::abort() } } diff --git a/src/libstd/sys/wasm/cmath.rs b/src/libstd/sys/wasm/cmath.rs deleted file mode 100644 index 304cf906b2a..00000000000 --- a/src/libstd/sys/wasm/cmath.rs +++ /dev/null @@ -1,29 +0,0 @@ -// These symbols are all defined in `compiler-builtins` -extern "C" { - 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/wasm/condvar.rs b/src/libstd/sys/wasm/condvar.rs deleted file mode 100644 index 9fd781c7282..00000000000 --- a/src/libstd/sys/wasm/condvar.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::sys::mutex::Mutex; -use crate::time::Duration; - -pub struct Condvar {} - -impl Condvar { - pub const fn new() -> Condvar { - Condvar {} - } - - #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - pub unsafe fn notify_one(&self) {} - - #[inline] - pub unsafe fn notify_all(&self) {} - - pub unsafe fn wait(&self, _mutex: &Mutex) { - panic!("can't block with web assembly") - } - - pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { - panic!("can't block with web assembly"); - } - - #[inline] - pub unsafe fn destroy(&self) {} -} diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs deleted file mode 100644 index ecb5b51cccd..00000000000 --- a/src/libstd/sys/wasm/fs.rs +++ /dev/null @@ -1,308 +0,0 @@ -use crate::ffi::OsString; -use crate::fmt; -use crate::hash::{Hash, Hasher}; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; -use crate::path::{Path, PathBuf}; -use crate::sys::time::SystemTime; -use crate::sys::{unsupported, Void}; - -pub struct File(Void); - -pub struct FileAttr(Void); - -pub struct ReadDir(Void); - -pub struct DirEntry(Void); - -#[derive(Clone, Debug)] -pub struct OpenOptions {} - -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 {} - } - - pub fn read(&mut self, _read: bool) {} - pub fn write(&mut self, _write: bool) {} - pub fn append(&mut self, _append: bool) {} - pub fn truncate(&mut self, _truncate: bool) {} - pub fn create(&mut self, _create: bool) {} - pub fn create_new(&mut self, _create_new: bool) {} -} - -impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() - } - - pub fn file_attr(&self) -> io::Result { - match self.0 {} - } - - pub fn fsync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn datasync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn truncate(&self, _size: u64) -> io::Result<()> { - match self.0 {} - } - - 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 is_read_vectored(&self) -> bool { - 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 is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn flush(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder {} - } - - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() - } -} - -impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -pub fn readdir(_p: &Path) -> io::Result { - unsupported() -} - -pub fn unlink(_p: &Path) -> io::Result<()> { - unsupported() -} - -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() -} - -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() -} - -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} diff --git a/src/libstd/sys/wasm/io.rs b/src/libstd/sys/wasm/io.rs deleted file mode 100644 index d5f475b4310..00000000000 --- a/src/libstd/sys/wasm/io.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::mem; - -#[derive(Copy, Clone)] -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/wasm/memchr.rs b/src/libstd/sys/wasm/memchr.rs deleted file mode 100644 index 9967482197e..00000000000 --- a/src/libstd/sys/wasm/memchr.rs +++ /dev/null @@ -1 +0,0 @@ -pub use core::slice::memchr::{memchr, memrchr}; diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index 6939596e52d..3de58904043 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -14,25 +14,35 @@ //! 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; - pub mod alloc; pub mod args; +#[path = "../unsupported/cmath.rs"] pub mod cmath; pub mod env; +#[path = "../unsupported/fs.rs"] pub mod fs; +#[path = "../unsupported/io.rs"] pub mod io; -pub mod memchr; +#[path = "../unsupported/net.rs"] pub mod net; +#[path = "../unsupported/os.rs"] pub mod os; +#[path = "../unsupported/path.rs"] pub mod path; +#[path = "../unsupported/pipe.rs"] pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; +#[path = "../unsupported/stack_overflow.rs"] pub mod stack_overflow; +#[path = "../unsupported/stdio.rs"] pub mod stdio; pub mod thread; +#[path = "../unsupported/thread_local_dtor.rs"] pub mod thread_local_dtor; +#[path = "../unsupported/thread_local_key.rs"] pub mod thread_local_key; +#[path = "../unsupported/time.rs"] pub mod time; pub use crate::sys_common::os_str_bytes as os_str; @@ -46,50 +56,15 @@ cfg_if::cfg_if! { #[path = "rwlock_atomics.rs"] pub mod rwlock; } else { + #[path = "../unsupported/condvar.rs"] pub mod condvar; + #[path = "../unsupported/mutex.rs"] pub mod mutex; + #[path = "../unsupported/rwlock.rs"] pub mod rwlock; } } -#[cfg(not(test))] -pub fn init() {} - -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 wasm yet") -} - -pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { - crate::io::ErrorKind::Other -} - -// 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(mut s: *const c_char) -> usize { - let mut n = 0; - while *s != 0 { - n += 1; - s = s.offset(1); - } - return n; -} - -pub fn abort_internal() -> ! { - unsafe { crate::arch::wasm32::unreachable() } -} - -// We don't have randomness yet, but I totally used a random number generator to -// generate these numbers. -// -// More seriously though this is just for DOS protection in hash maps. It's ok -// if we don't do that on wasm just yet. -pub fn hashmap_random_keys() -> (u64, u64) { - (1, 2) -} +#[path = "../unsupported/common.rs"] +mod common; +pub use common::*; diff --git a/src/libstd/sys/wasm/mutex.rs b/src/libstd/sys/wasm/mutex.rs deleted file mode 100644 index 7aaf1b3a343..00000000000 --- a/src/libstd/sys/wasm/mutex.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::cell::UnsafeCell; - -pub struct Mutex { - locked: UnsafeCell, -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} // no threads on wasm - -impl Mutex { - pub const fn new() -> Mutex { - Mutex { locked: UnsafeCell::new(false) } - } - - #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - pub unsafe fn lock(&self) { - let locked = self.locked.get(); - assert!(!*locked, "cannot recursively acquire mutex"); - *locked = true; - } - - #[inline] - pub unsafe fn unlock(&self) { - *self.locked.get() = false; - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - let locked = self.locked.get(); - if *locked { - false - } else { - *locked = true; - true - } - } - - #[inline] - pub unsafe fn destroy(&self) {} -} - -// All empty stubs because wasm has no threads yet, so lock acquisition always -// succeeds. -pub struct ReentrantMutex {} - -impl ReentrantMutex { - pub const unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex {} - } - - pub unsafe fn init(&self) {} - - pub unsafe fn lock(&self) {} - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - true - } - - pub unsafe fn unlock(&self) {} - - pub unsafe fn destroy(&self) {} -} diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs deleted file mode 100644 index 5c9f1098f9b..00000000000 --- a/src/libstd/sys/wasm/net.rs +++ /dev/null @@ -1,361 +0,0 @@ -use crate::convert::TryFrom; -use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; -use crate::sys::{unsupported, Void}; -use crate::time::Duration; - -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 is_read_vectored(&self) -> bool { - 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 is_write_vectored(&self) -> bool { - 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/wasm/os.rs b/src/libstd/sys/wasm/os.rs deleted file mode 100644 index 91afdc8a5a0..00000000000 --- a/src/libstd/sys/wasm/os.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::error::Error as StdError; -use crate::ffi::{OsStr, OsString}; -use crate::fmt; -use crate::io; -use crate::path::{self, PathBuf}; -use crate::str; -use crate::sys::{unsupported, Void}; - -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 wasm yet".fmt(f) - } -} - -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on wasm yet" - } -} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub struct Env(Void); - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - match self.0 {} - } -} - -pub fn env() -> Env { - panic!("not supported on web assembly") -} - -pub fn getenv(_: &OsStr) -> io::Result> { - Ok(None) -} - -pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on wasm32-unknown-unknown")) -} - -pub fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on wasm32-unknown-unknown")) -} - -pub fn temp_dir() -> PathBuf { - panic!("no filesystem on wasm") -} - -pub fn home_dir() -> Option { - None -} - -pub fn exit(_code: i32) -> ! { - unsafe { - crate::arch::wasm32::unreachable(); - } -} - -pub fn getpid() -> u32 { - panic!("no pids on wasm") -} diff --git a/src/libstd/sys/wasm/path.rs b/src/libstd/sys/wasm/path.rs deleted file mode 100644 index 840a7ae0426..00000000000 --- a/src/libstd/sys/wasm/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[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/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs deleted file mode 100644 index 10d0925823e..00000000000 --- a/src/libstd/sys/wasm/pipe.rs +++ /dev/null @@ -1,38 +0,0 @@ -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 is_read_vectored(&self) -> bool { - 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 is_write_vectored(&self) -> bool { - 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/wasm/process.rs b/src/libstd/sys/wasm/process.rs deleted file mode 100644 index 4702e5c5492..00000000000 --- a/src/libstd/sys/wasm/process.rs +++ /dev/null @@ -1,149 +0,0 @@ -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/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs deleted file mode 100644 index a59944482e9..00000000000 --- a/src/libstd/sys/wasm/rwlock.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::cell::UnsafeCell; - -pub struct RWLock { - mode: UnsafeCell, -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} // no threads on wasm - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { mode: UnsafeCell::new(0) } - } - - #[inline] - pub unsafe fn read(&self) { - let mode = self.mode.get(); - if *mode >= 0 { - *mode += 1; - } else { - rtabort!("rwlock locked for writing"); - } - } - - #[inline] - pub unsafe fn try_read(&self) -> bool { - let mode = self.mode.get(); - if *mode >= 0 { - *mode += 1; - true - } else { - false - } - } - - #[inline] - pub unsafe fn write(&self) { - let mode = self.mode.get(); - if *mode == 0 { - *mode = -1; - } else { - rtabort!("rwlock locked for reading") - } - } - - #[inline] - pub unsafe fn try_write(&self) -> bool { - let mode = self.mode.get(); - if *mode == 0 { - *mode = -1; - true - } else { - false - } - } - - #[inline] - pub unsafe fn read_unlock(&self) { - *self.mode.get() -= 1; - } - - #[inline] - pub unsafe fn write_unlock(&self) { - *self.mode.get() += 1; - } - - #[inline] - pub unsafe fn destroy(&self) {} -} diff --git a/src/libstd/sys/wasm/stack_overflow.rs b/src/libstd/sys/wasm/stack_overflow.rs deleted file mode 100644 index 32555394cd5..00000000000 --- a/src/libstd/sys/wasm/stack_overflow.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub unsafe fn init() {} - -pub unsafe fn cleanup() {} diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs deleted file mode 100644 index 5a4e4505e93..00000000000 --- a/src/libstd/sys/wasm/stdio.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::io; - -pub struct Stdin; -pub struct Stdout; -pub struct Stderr; - -impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin) - } -} - -impl io::Read for Stdin { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - Ok(0) - } -} - -impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout) - } -} - -impl io::Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr) - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub const STDIN_BUF_SIZE: usize = 0; - -pub fn is_ebadf(_err: &io::Error) -> bool { - true -} - -pub fn panic_output() -> Option> { - None -} diff --git a/src/libstd/sys/wasm/thread_local_dtor.rs b/src/libstd/sys/wasm/thread_local_dtor.rs deleted file mode 100644 index 85d66098302..00000000000 --- a/src/libstd/sys/wasm/thread_local_dtor.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![unstable(feature = "thread_local_internals", issue = "none")] - -pub unsafe fn register_dtor(_t: *mut u8, _dtor: unsafe extern "C" fn(*mut u8)) { - // FIXME: right now there is no concept of "thread exit", but this is likely - // going to show up at some point in the form of an exported symbol that the - // wasm runtime is going to be expected to call. For now we basically just - // ignore the arguments, but if such a function starts to exist it will - // likely look like the OSX implementation in `unix/fast_thread_local.rs` -} diff --git a/src/libstd/sys/wasm/thread_local_key.rs b/src/libstd/sys/wasm/thread_local_key.rs deleted file mode 100644 index f8be9863ed5..00000000000 --- a/src/libstd/sys/wasm/thread_local_key.rs +++ /dev/null @@ -1,26 +0,0 @@ -pub type Key = usize; - -#[inline] -pub unsafe fn create(_dtor: Option) -> Key { - panic!("should not be used on the wasm target"); -} - -#[inline] -pub unsafe fn set(_key: Key, _value: *mut u8) { - panic!("should not be used on the wasm target"); -} - -#[inline] -pub unsafe fn get(_key: Key) -> *mut u8 { - panic!("should not be used on the wasm target"); -} - -#[inline] -pub unsafe fn destroy(_key: Key) { - panic!("should not be used on the wasm target"); -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - panic!("should not be used on the wasm target"); -} diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs deleted file mode 100644 index d9edc7fdc44..00000000000 --- a/src/libstd/sys/wasm/time.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::time::Duration; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime(Duration); - -pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); - -impl Instant { - pub fn now() -> Instant { - panic!("time not implemented on wasm32-unknown-unknown") - } - - pub const fn zero() -> Instant { - Instant(Duration::from_secs(0)) - } - - pub fn actually_monotonic() -> bool { - false - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_add(*other)?)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_sub(*other)?)) - } -} - -impl SystemTime { - pub fn now() -> SystemTime { - panic!("time not implemented on wasm32-unknown-unknown") - } - - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_add(*other)?)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_sub(*other)?)) - } -} diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index e57bb267cbd..c3e6a5570e6 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -57,6 +57,7 @@ pub mod mutex; target_os = "cloudabi", target_os = "hermit", target_arch = "wasm32", + feature = "restricted-std", all(target_vendor = "fortanix", target_env = "sgx")))] pub mod os_str_bytes; pub mod poison; @@ -74,6 +75,7 @@ cfg_if::cfg_if! { if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "hermit", + feature = "restricted-std", all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))] { pub use crate::sys::net; diff --git a/src/libstd/sys_common/mutex.rs b/src/libstd/sys_common/mutex.rs index 899fc6a7235..e66d8994147 100644 --- a/src/libstd/sys_common/mutex.rs +++ b/src/libstd/sys_common/mutex.rs @@ -17,6 +17,7 @@ impl Mutex { /// Also, until `init` is called, behavior is undefined if this /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock` /// are called by the thread currently holding the lock. + #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")] pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) } diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index cc025da1af5..c705ed31fd5 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -10,7 +10,16 @@ cfg_if::cfg_if! { if #[cfg(target_env = "msvc")] { // no extra unwinder support needed - } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] { + } else if #[cfg( + any( + all(target_arch = "wasm32", not(target_os = "emscripten")), + target_os = "none", + target_os = "hermit", + target_os = "uefi", + target_os = "cuda", + target_os = "l4re", + ))] + { // no unwinder on the system! } else { mod libunwind; diff --git a/src/tools/rustc-std-workspace-std/lib.rs b/src/tools/rustc-std-workspace-std/lib.rs index f40d09cafbb..1e955c61ac8 100644 --- a/src/tools/rustc-std-workspace-std/lib.rs +++ b/src/tools/rustc-std-workspace-std/lib.rs @@ -1 +1,2 @@ +#![feature(restricted_std)] pub use std::*; -- cgit 1.4.1-3-g733a5 From 85c25aed510ce599504b172f7c7bef280e91637b Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Wed, 15 Jul 2020 15:48:36 -0700 Subject: Move usercall_wait_timeout to abi::usercalls::wait_timeout --- src/libstd/sys/sgx/abi/usercalls/mod.rs | 74 +++++++++++++++++++++++++++++++- src/libstd/sys/sgx/mod.rs | 76 --------------------------------- src/libstd/sys/sgx/thread.rs | 3 +- src/libstd/sys/sgx/waitqueue.rs | 3 +- 4 files changed, 74 insertions(+), 82 deletions(-) (limited to 'src/libstd/sys') diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs index 6ee147d1704..73f1b951e74 100644 --- a/src/libstd/sys/sgx/abi/usercalls/mod.rs +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -1,8 +1,8 @@ use crate::cmp; use crate::convert::TryFrom; -use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult}; +use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult}; use crate::sys::rand::rdrand64; -use crate::time::Duration; +use crate::time::{Duration, Instant}; pub(crate) mod alloc; #[macro_use] @@ -169,6 +169,76 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult { unsafe { raw::wait(event_mask, timeout).from_sgx_result() } } +/// This function makes an effort to wait for a non-spurious event at least as +/// long as `duration`. Note that in general there is no guarantee about accuracy +/// of time and timeouts in SGX model. The enclave runner serving usercalls may +/// lie about current time and/or ignore timeout values. +/// +/// Once the event is observed, `should_wake_up` will be used to determine +/// whether or not the event was spurious. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub fn wait_timeout(event_mask: u64, duration: Duration, should_wake_up: F) +where + F: Fn() -> bool, +{ + // Calls the wait usercall and checks the result. Returns true if event was + // returned, and false if WouldBlock/TimedOut was returned. + // If duration is None, it will use WAIT_NO. + fn wait_checked(event_mask: u64, duration: Option) -> bool { + let timeout = duration.map_or(raw::WAIT_NO, |duration| { + cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64 + }); + match wait(event_mask, timeout) { + Ok(eventset) => { + if event_mask == 0 { + rtabort!("expected wait() to return Err, found Ok."); + } + rtassert!(eventset != 0 && eventset & !event_mask == 0); + true + } + Err(e) => { + rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock); + false + } + } + } + + match wait_checked(event_mask, Some(duration)) { + false => return, // timed out + true if should_wake_up() => return, // woken up + true => {} // spurious event + } + + // Drain all cached events. + // Note that `event_mask != 0` is implied if we get here. + loop { + match wait_checked(event_mask, None) { + false => break, // no more cached events + true if should_wake_up() => return, // woken up + true => {} // spurious event + } + } + + // Continue waiting, but take note of time spent waiting so we don't wait + // forever. We intentionally don't call `Instant::now()` before this point + // to avoid the cost of the `insecure_time` usercall in case there are no + // spurious wakeups. + + let start = Instant::now(); + let mut remaining = duration; + loop { + match wait_checked(event_mask, Some(remaining)) { + false => return, // timed out + true if should_wake_up() => return, // woken up + true => {} // spurious event + } + remaining = match duration.checked_sub(start.elapsed()) { + Some(remaining) => remaining, + None => break, + } + } +} + /// Usercall `send`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] pub fn send(event_set: u64, tcs: Option) -> IoResult<()> { diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index c412053112b..7a3a3eb2049 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -110,82 +110,6 @@ pub fn decode_error_kind(code: i32) -> ErrorKind { } } -// This function makes an effort to wait for a non-spurious event at least as -// long as `duration`. Note that in general there is no guarantee about accuracy -// of time and timeouts in SGX model. The enclave runner serving usercalls may -// lie about current time and/or ignore timeout values. -// -// Once the event is observed, `should_wake_up` will be used to determine -// whether or not the event was spurious. -pub fn usercall_wait_timeout(event_mask: u64, duration: crate::time::Duration, should_wake_up: F) -where - F: Fn() -> bool, -{ - use self::abi::usercalls; - use crate::cmp; - use crate::io::ErrorKind; - use crate::time::{Duration, Instant}; - - // Calls the wait usercall and checks the result. Returns true if event was - // returned, and false if WouldBlock/TimedOut was returned. - // If duration is None, it will use WAIT_NO. - fn wait_checked(event_mask: u64, duration: Option) -> bool { - let timeout = duration.map_or(usercalls::raw::WAIT_NO, |duration| { - cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64 - }); - match usercalls::wait(event_mask, timeout) { - Ok(eventset) => { - if event_mask == 0 { - rtabort!("expected usercalls::wait() to return Err, found Ok."); - } - // A matching event is one whose bits are equal to or a subset - // of `event_mask`. - rtassert!(eventset & !event_mask == 0); - true - } - Err(e) => { - rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock); - false - } - } - } - - match wait_checked(event_mask, Some(duration)) { - false => return, // timed out - true if should_wake_up() => return, // woken up - true => {} // spurious event - } - - // Drain all cached events. - // Note that `event_mask != 0` is implied if we get here. - loop { - match wait_checked(event_mask, None) { - false => break, // no more cached events - true if should_wake_up() => return, // woken up - true => {} // spurious event - } - } - - // Continue waiting, but take note of time spent waiting so we don't wait - // forever. We intentionally don't call `Instant::now()` before this point - // to avoid the cost of the `insecure_time` usercall in case there are no - // spurious wakeups. - - let start = Instant::now(); - let mut remaining = duration; - loop { - match wait_checked(event_mask, Some(remaining)) { - false => return, // timed out - true if should_wake_up() => return, // woken up - true => {} // spurious event - } - remaining = match duration.checked_sub(start.elapsed()) { - Some(remaining) => remaining, - None => break, - } - } -} - // 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)] diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs index 58b6f4346bc..5895f70436e 100644 --- a/src/libstd/sys/sgx/thread.rs +++ b/src/libstd/sys/sgx/thread.rs @@ -1,7 +1,6 @@ #![cfg_attr(test, allow(dead_code))] // why is this necessary? use crate::ffi::CStr; use crate::io; -use crate::sys::usercall_wait_timeout; use crate::time::Duration; use super::abi::usercalls; @@ -75,7 +74,7 @@ impl Thread { } pub fn sleep(dur: Duration) { - usercall_wait_timeout(0, dur, || true); + usercalls::wait_timeout(0, dur, || true); } pub fn join(self) { diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs index c8ccab2247a..070afa55f30 100644 --- a/src/libstd/sys/sgx/waitqueue.rs +++ b/src/libstd/sys/sgx/waitqueue.rs @@ -11,7 +11,6 @@ //! The queue and associated wait state are stored in a `WaitVariable`. use crate::num::NonZeroUsize; use crate::ops::{Deref, DerefMut}; -use crate::sys::usercall_wait_timeout; use crate::time::Duration; use super::abi::thread; @@ -176,7 +175,7 @@ impl WaitQueue { })); let entry_lock = lock.lock().queue.inner.push(&mut entry); before_wait(); - usercall_wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake); + usercalls::wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake); // acquire the wait queue's lock first to avoid deadlock. let mut guard = lock.lock(); let success = entry_lock.lock().wake; -- cgit 1.4.1-3-g733a5