Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make compatible as submodule to libstd #119

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,16 @@
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![cfg_attr(
all(target_env = "sgx", target_vendor = "fortanix"),
all(
not(feature = "i-am-libstd"),
target_env = "sgx",
target_vendor = "fortanix"
),
feature(sgx_platform)
)]
#![cfg_attr(
all(
not(feature = "i-am-libstd"),
feature = "nightly",
target_arch = "wasm32",
target_feature = "atomics"
Expand All @@ -56,10 +61,18 @@
feature(thread_local, checked_duration_since)
)]

#[cfg(not(feature = "i-am-libstd"))]
use cfg_if::cfg_if;

mod libstd {
#[cfg(feature = "i-am-libstd")]
pub use crate::*;
#[cfg(not(feature = "i-am-libstd"))]
pub use std::*;
}

cfg_if! {
if #[cfg(all(has_sized_atomics, target_os = "linux"))] {
if #[cfg(all(any(has_sized_atomics, feature = "i-am-libstd"), target_os = "linux"))] {
#[path = "thread_parker/linux.rs"]
mod thread_parker;
} else if #[cfg(unix)] {
Expand All @@ -68,22 +81,24 @@ cfg_if! {
} else if #[cfg(windows)] {
#[path = "thread_parker/windows/mod.rs"]
mod thread_parker;
} else if #[cfg(all(has_sized_atomics, target_os = "redox"))] {
} else if #[cfg(all(any(has_sized_atomics, feature = "i-am-libstd"), target_os = "redox"))] {
#[path = "thread_parker/redox.rs"]
mod thread_parker;
} else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
#[path = "thread_parker/sgx.rs"]
mod thread_parker;
} else if #[cfg(all(
feature = "nightly",
any(feature = "nightly", feature = "i-am-libstd"),
target_arch = "wasm32",
target_feature = "atomics"
))] {
#[path = "thread_parker/wasm.rs"]
mod thread_parker;
} else if #[cfg(all(feature = "nightly", target_os = "cloudabi"))] {
} else if #[cfg(all(any(feature = "nightly", feature = "i-am-libstd"), target_os = "cloudabi"))] {
#[path = "thread_parker/cloudabi.rs"]
mod thread_parker;
} else if #[cfg(all(feature = "i-am-libstd", not(target_arch = "wasm32")))] {
compile_error!("Not allowed to fall back to generic spin lock based thread parker");
} else {
#[path = "thread_parker/generic.rs"]
mod thread_parker;
Expand Down
43 changes: 38 additions & 5 deletions core/src/parking_lot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,40 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::thread_parker::ThreadParker;
use crate::util::UncheckedOptionExt;
use crate::word_lock::WordLock;
use super::libstd::time::{Duration, Instant};
use super::thread_parker::ThreadParker;
use super::util::UncheckedOptionExt;
use super::word_lock::WordLock;
use core::{
cell::{Cell, UnsafeCell},
ptr,
sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
};
#[cfg(not(feature = "i-am-libstd"))]
use rand::{rngs::SmallRng, FromEntropy, Rng};
#[cfg(not(feature = "i-am-libstd"))]
use smallvec::SmallVec;
use std::time::{Duration, Instant};

// When compiling the tests of std, there are basically two copies of std:
// one normal one, and one with cfg(test). This means that during testing of
// std there will be two instances of NUM_THREADS and HASHTABLE unless we make
// sure both versions of std link to the same instance. It's usually not a
// problem that different locks are based on different HASHTABLEs. Except if
// the two locks both think they guard a global resource. Such as the mutexes
// around the stdio file descriptors.
// Here we use #[linkage] and #[export_name] to make both versions point to
// the same instance.
#[cfg_attr(all(test, feature = "i-am-libstd"), linkage = "available_externally")]
#[cfg_attr(
feature = "i-am-libstd",
export_name = "_ZN3std16parking_lot_core11parking_lot11NUM_THREADSE"
)]
static NUM_THREADS: AtomicUsize = AtomicUsize::new(0);
#[cfg_attr(all(test, feature = "i-am-libstd"), linkage = "available_externally")]
#[cfg_attr(
feature = "i-am-libstd",
export_name = "_ZN3std16parking_lot_core11parking_lot9HASHTABLEE"
)]
faern marked this conversation as resolved.
Show resolved Hide resolved
static HASHTABLE: AtomicPtr<HashTable> = AtomicPtr::new(ptr::null_mut());

// Even with 3x more buckets than threads, the memory overhead per thread is
Expand Down Expand Up @@ -85,6 +106,7 @@ struct FairTimeout {
timeout: Instant,

// Random number generator for calculating the next timeout
#[cfg(not(feature = "i-am-libstd"))]
rng: SmallRng,
}

Expand All @@ -93,6 +115,7 @@ impl FairTimeout {
fn new(timeout: Instant) -> FairTimeout {
FairTimeout {
timeout,
#[cfg(not(feature = "i-am-libstd"))]
rng: SmallRng::from_entropy(),
}
}
Expand All @@ -102,7 +125,11 @@ impl FairTimeout {
fn should_timeout(&mut self) -> bool {
let now = Instant::now();
if now > self.timeout {
self.timeout = now + Duration::new(0, self.rng.gen_range(0, 1000000));
#[cfg(not(feature = "i-am-libstd"))]
let ns_offset = self.rng.gen_range(0, 1000000);
#[cfg(feature = "i-am-libstd")]
let ns_offset = 500000;
self.timeout = now + Duration::new(0, ns_offset);
true
} else {
false
Expand Down Expand Up @@ -767,7 +794,10 @@ pub unsafe fn unpark_all(key: usize, unpark_token: UnparkToken) -> usize {
let mut link = &bucket.queue_head;
let mut current = bucket.queue_head.get();
let mut previous = ptr::null();
#[cfg(not(feature = "i-am-libstd"))]
let mut threads = SmallVec::<[_; 8]>::new();
#[cfg(feature = "i-am-libstd")]
let mut threads = Vec::new();
while !current.is_null() {
if (*current).key.load(Ordering::Relaxed) == key {
// Remove the thread from the queue
Expand Down Expand Up @@ -978,7 +1008,10 @@ where
let mut link = &bucket.queue_head;
let mut current = bucket.queue_head.get();
let mut previous = ptr::null();
#[cfg(not(feature = "i-am-libstd"))]
let mut threads = SmallVec::<[_; 8]>::new();
#[cfg(feature = "i-am-libstd")]
let mut threads = Vec::new();
let mut result = UnparkResult::default();
while !current.is_null() {
if (*current).key.load(Ordering::Relaxed) == key {
Expand Down
4 changes: 2 additions & 2 deletions core/src/spinwait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::thread_parker;
use std::sync::atomic::spin_loop_hint;
use super::thread_parker;
use core::sync::atomic::spin_loop_hint;

// Wastes some CPU time for the given number of iterations,
// using a hint to indicate to the CPU that we are spinning.
Expand Down
6 changes: 5 additions & 1 deletion core/src/thread_parker/cloudabi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#[cfg(not(feature = "i-am-libstd"))]
use cloudabi as abi;
#[cfg(feature = "i-am-libstd")]
use crate::sys::abi;
use core::{
cell::Cell,
mem,
sync::atomic::{AtomicU32, Ordering},
convert::TryFrom,
};
use std::{convert::TryFrom, thread, time::Instant};
use super::libstd::{thread, time::Instant};

extern "C" {
#[thread_local]
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
//! A simple spin lock based thread parker. Used on platforms without better
//! parking facilities available.

use super::libstd::{thread, time::Instant};
use core::sync::atomic::{spin_loop_hint, AtomicBool, Ordering};
use std::{thread, time::Instant};

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::libstd::{thread, time::Instant};
use core::{
ptr,
sync::atomic::{AtomicI32, Ordering},
};
use libc;
use std::{thread, time::Instant};

const FUTEX_WAIT: i32 = 0;
const FUTEX_WAKE: i32 = 1;
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/redox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use core::{
ptr,
sync::atomic::{AtomicI32, Ordering},
};
use std::{thread, time::Instant};
use super::libstd::{thread, time::Instant};
use syscall::{
call::futex,
data::TimeSpec,
Expand Down
32 changes: 21 additions & 11 deletions core/src/thread_parker/sgx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use core::sync::atomic::{AtomicBool, Ordering};
use std::{
use super::libstd::{
io,
os::fortanix_sgx::{
thread::current as current_tcs,
Expand All @@ -18,6 +17,16 @@ use std::{
thread,
time::Instant,
};
use core::sync::atomic::{AtomicBool, Ordering};

macro_rules! abort {
($($t:tt)*) => {{
#[cfg(not(feature = "i-am-libstd"))]
std::process::abort();
#[cfg(feature = "i-am-libstd")]
rtabort!($($t)*);
}}
}

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
Expand Down Expand Up @@ -55,7 +64,10 @@ impl ThreadParker {
pub fn park(&self) {
while self.parked.load(Ordering::Acquire) {
let result = usercalls::wait(EV_UNPARK, WAIT_INDEFINITE);
debug_assert_eq!(result.expect("wait returned error") & EV_UNPARK, EV_UNPARK);
match result.map(|eventset| eventset & EV_UNPARK) {
Ok(EV_UNPARK) => {}
_ => abort!("usercall wait returned an invalid value"),
}
}
}

Expand All @@ -65,7 +77,7 @@ impl ThreadParker {
#[inline]
pub fn park_until(&self, _timeout: Instant) -> bool {
// FIXME: https://github.com/fortanix/rust-sgx/issues/31
panic!("timeout not supported in SGX");
abort!("timeout not supported in SGX");
}

// Locks the parker to prevent the target thread from exiting. This is
Expand All @@ -90,13 +102,11 @@ impl UnparkHandle {
#[inline]
pub fn unpark(self) {
let result = usercalls::send(EV_UNPARK, Some(self.0));
if cfg!(debug_assertions) {
if let Err(error) = result {
// `InvalidInput` may be returned if the thread we send to has
// already been unparked and exited.
if error.kind() != io::ErrorKind::InvalidInput {
panic!("send returned an unexpected error: {:?}", error);
}
if let Err(error) = result {
// `InvalidInput` may be returned if the thread we send to has
// already been unparked and exited.
if error.kind() != io::ErrorKind::InvalidInput {
abort!("send returned an unexpected error: {:?}", error);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions core/src/thread_parker/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::libstd::{
thread,
time::{Duration, Instant},
};
#[cfg(any(target_os = "macos", target_os = "ios"))]
use core::ptr;
use core::{
cell::{Cell, UnsafeCell},
mem,
};
use libc;
use std::{
thread,
time::{Duration, Instant},
};

// x32 Linux uses a non-standard type for tv_nsec in timespec.
// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
Expand Down
3 changes: 2 additions & 1 deletion core/src/thread_parker/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
use core::{
arch::wasm32,
sync::atomic::{AtomicI32, Ordering},
convert::TryFrom,
};
use std::{convert::TryFrom, thread, time::Instant};
use super::libstd::{thread, time::Instant};

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
Expand Down
19 changes: 16 additions & 3 deletions core/src/thread_parker/windows/keyed_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use core::{mem, ptr};
use std::{
use super::super::libstd::time::Instant;
#[cfg(feature = "i-am-libstd")]
use crate::sys::c::{
CloseHandle, GetModuleHandleA, GetProcAddress, ACCESS_MASK, BOOLEAN, GENERIC_READ,
GENERIC_WRITE, HANDLE, LARGE_INTEGER, LPCSTR, LPHANDLE as PHANDLE, LPVOID as PVOID, NTSTATUS,
PLARGE_INTEGER, STATUS_SUCCESS, STATUS_TIMEOUT, TRUE, ULONG,
};
use core::{
mem, ptr,
sync::atomic::{AtomicUsize, Ordering},
time::Instant,
};
#[cfg(not(feature = "i-am-libstd"))]
use winapi::{
shared::{
minwindef::{TRUE, ULONG},
Expand Down Expand Up @@ -139,13 +146,19 @@ impl KeyedEvent {

// NT uses a timeout in units of 100ns. We use a negative value to
// indicate a relative timeout based on a monotonic clock.
#[cfg(feature = "i-am-libstd")]
let mut nt_timeout: LARGE_INTEGER;
#[cfg(not(feature = "i-am-libstd"))]
let mut nt_timeout: LARGE_INTEGER = mem::zeroed();
let diff = timeout - now;
let value = (diff.as_secs() as i64)
.checked_mul(-10000000)
.and_then(|x| x.checked_sub((diff.subsec_nanos() as i64 + 99) / 100));

match value {
#[cfg(feature = "i-am-libstd")]
Some(x) => nt_timeout = x,
#[cfg(not(feature = "i-am-libstd"))]
Some(x) => *nt_timeout.QuadPart_mut() = x,
None => {
// Timeout overflowed, just sleep indefinitely
Expand Down
8 changes: 6 additions & 2 deletions core/src/thread_parker/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::libstd::time::Instant;
use core::{
ptr,
sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
};
use std::time::Instant;

mod keyed_event;
mod waitaddress;
Expand Down Expand Up @@ -164,6 +164,10 @@ impl UnparkHandle {
// Yields the rest of the current timeslice to the OS
#[inline]
pub fn thread_yield() {
#[cfg(feature = "i-am-libstd")]
use crate::sys::c::DWORD;
#[cfg(not(feature = "i-am-libstd"))]
use winapi::shared::minwindef::DWORD;
// Note that this is manually defined here rather than using the definition
// through `winapi`. The `winapi` definition comes from the `synchapi`
// header which enables the "synchronization.lib" library. It turns out,
Expand All @@ -178,7 +182,7 @@ pub fn thread_yield() {
// libraries, but that'll probably take a lot longer than patching this here
// and avoiding the `synchapi` feature entirely.
extern "system" {
fn Sleep(a: winapi::shared::minwindef::DWORD);
fn Sleep(a: DWORD);
}
unsafe {
// We don't use SwitchToThread here because it doesn't consider all
Expand Down
Loading