Skip to content

Commit

Permalink
Merge pull request #123 from faern/add-sgx-thread-parker
Browse files Browse the repository at this point in the history
Add SGX thread parker
  • Loading branch information
Amanieu authored Mar 22, 2019
2 parents 66d67bb + 8844366 commit ba43375
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ before_script:
- |
pip install 'travis-cargo<0.2' --user &&
export PATH=$HOME/.local/bin:$PATH
- if [ "${TRAVIS_RUST_VERSION}" = "nightly" ]; then
rustup target add x86_64-fortanix-unknown-sgx;
fi

script:
- cd core;
Expand All @@ -22,6 +25,7 @@ script:
- travis-cargo test
- travis-cargo --only stable test -- --features=deadlock_detection
- travis-cargo --only beta test -- --features=deadlock_detection
- travis-cargo --only nightly test -- --all --no-run --target x86_64-fortanix-unknown-sgx
- travis-cargo --only nightly doc -- --all-features --no-deps -p parking_lot -p parking_lot_core -p lock_api
- cd benchmark
- travis-cargo build
Expand Down
13 changes: 12 additions & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,28 @@

#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![cfg_attr(
all(target_env = "sgx", target_vendor = "fortanix"),
feature(sgx_platform)
)]

#[cfg(all(feature = "nightly", target_os = "linux"))]
#[path = "thread_parker/linux.rs"]
mod thread_parker;

#[cfg(all(unix, not(all(feature = "nightly", target_os = "linux"))))]
#[path = "thread_parker/unix.rs"]
mod thread_parker;

#[cfg(windows)]
#[path = "thread_parker/windows/mod.rs"]
mod thread_parker;
#[cfg(not(any(windows, unix)))]

#[cfg(all(target_env = "sgx", target_vendor = "fortanix"))]
#[path = "thread_parker/sgx.rs"]
mod thread_parker;

#[cfg(not(any(windows, unix, all(target_env = "sgx", target_vendor = "fortanix"))))]
#[path = "thread_parker/generic.rs"]
mod thread_parker;

Expand Down
108 changes: 108 additions & 0 deletions core/src/thread_parker/sgx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// 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::{
io,
os::fortanix_sgx::{
thread::current as current_tcs,
usercalls::{
self,
raw::{Tcs, EV_UNPARK, WAIT_INDEFINITE},
},
},
thread,
time::Instant,
};

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
parked: AtomicBool,
tcs: Tcs,
}

impl ThreadParker {
pub const IS_CHEAP_TO_CONSTRUCT: bool = true;

#[inline]
pub fn new() -> ThreadParker {
ThreadParker {
parked: AtomicBool::new(false),
tcs: current_tcs(),
}
}

// Prepares the parker. This should be called before adding it to the queue.
#[inline]
pub fn prepare_park(&self) {
self.parked.store(true, Ordering::Relaxed);
}

// Checks if the park timed out. This should be called while holding the
// queue lock after park_until has returned false.
#[inline]
pub fn timed_out(&self) -> bool {
self.parked.load(Ordering::Relaxed)
}

// Parks the thread until it is unparked. This should be called after it has
// been added to the queue, after unlocking the queue.
#[inline]
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);
}
}

// Parks the thread until it is unparked or the timeout is reached. This
// should be called after it has been added to the queue, after unlocking
// the queue. Returns true if we were unparked and false if we timed out.
#[inline]
pub fn park_until(&self, _timeout: Instant) -> bool {
// FIXME: https://github.com/fortanix/rust-sgx/issues/31
panic!("timeout not supported in SGX");
}

// Locks the parker to prevent the target thread from exiting. This is
// necessary to ensure that thread-local ThreadData objects remain valid.
// This should be called while holding the queue lock.
#[inline]
pub fn unpark_lock(&self) -> UnparkHandle {
// We don't need to lock anything, just clear the state
self.parked.store(false, Ordering::Release);
UnparkHandle(self.tcs)
}
}

// Handle for a thread that is about to be unparked. We need to mark the thread
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle(Tcs);

impl UnparkHandle {
// Wakes up the parked thread. This should be called after the queue lock is
// released to avoid blocking the queue for too long.
#[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);
}
}
}
}
}

#[inline]
pub fn thread_yield() {
thread::yield_now();
}
10 changes: 9 additions & 1 deletion src/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,15 @@ mod tests {
thread::spawn(move || {
let _lock = arc2.write();
});
thread::sleep(Duration::from_millis(100));

if cfg!(not(all(target_env = "sgx", target_vendor = "fortanix"))) {
thread::sleep(Duration::from_millis(100));
} else {
// FIXME: https://github.com/fortanix/rust-sgx/issues/31
for _ in 0..100 {
thread::yield_now();
}
}

// A normal read would block here since there is a pending writer
let _lock2 = arc.read_recursive();
Expand Down

0 comments on commit ba43375

Please sign in to comment.