Skip to content

Commit 8d6edc9

Browse files
author
Jethro Beekman
committed
SGX target: implement synchronization primitives and threading
1 parent 1e44e2d commit 8d6edc9

File tree

14 files changed

+832
-76
lines changed

14 files changed

+832
-76
lines changed

src/libstd/io/lazy.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ }
2626
unsafe impl<T> Sync for Lazy<T> {}
2727

2828
impl<T> Lazy<T> {
29+
#[unstable(feature = "sys_internals", issue = "0")] // FIXME: min_const_fn
2930
pub const fn new() -> Lazy<T> {
3031
Lazy {
3132
lock: Mutex::new(),

src/libstd/sys/sgx/abi/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(super) mod panic;
2020
pub mod thread;
2121
pub mod tls;
2222
#[macro_use]
23-
mod usercalls;
23+
pub mod usercalls;
2424

2525
global_asm!(concat!(usercalls_asm!(), include_str!("entry.S")));
2626

@@ -59,14 +59,13 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
5959
// (main function exists). If this is a library, the crate author should be
6060
// able to specify this
6161
#[no_mangle]
62-
#[allow(unreachable_code)]
6362
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
6463
// FIXME: how to support TLS in library mode?
6564
let tls = Box::new(tls::Tls::new());
6665
let _tls_guard = unsafe { tls.activate() };
6766

6867
if secondary {
69-
unimplemented!("thread entrypoint");
68+
super::thread::Thread::entry();
7069

7170
(0, 0)
7271
} else {

src/libstd/sys/sgx/abi/usercalls/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,22 @@ mod alloc;
1616
#[macro_use]
1717
mod raw;
1818

19+
pub fn launch_thread() -> IoResult<()> {
20+
unsafe { raw::launch_thread().from_sgx_result() }
21+
}
22+
1923
pub fn exit(panic: bool) -> ! {
2024
unsafe { raw::exit(panic) }
2125
}
2226

27+
pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
28+
unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
29+
}
30+
31+
pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
32+
unsafe { raw::send(event_set, tcs).from_sgx_result() }
33+
}
34+
2335
pub fn alloc(size: usize, alignment: usize) -> IoResult<*mut u8> {
2436
unsafe { raw::alloc(size, alignment).from_sgx_result() }
2537
}

src/libstd/sys/sgx/alloc.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,31 @@ extern crate dlmalloc;
1212

1313
use alloc::{GlobalAlloc, Layout, System};
1414

15-
// FIXME: protect this value for concurrent access
16-
static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
15+
use super::waitqueue::SpinMutex;
16+
17+
// Using a SpinMutex because we never want to exit the enclave waiting for the
18+
// allocator.
19+
static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc> = SpinMutex::new(dlmalloc::DLMALLOC_INIT);
1720

1821
#[stable(feature = "alloc_system_type", since = "1.28.0")]
1922
unsafe impl GlobalAlloc for System {
2023
#[inline]
2124
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
22-
DLMALLOC.malloc(layout.size(), layout.align())
25+
DLMALLOC.lock().malloc(layout.size(), layout.align())
2326
}
2427

2528
#[inline]
2629
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
27-
DLMALLOC.calloc(layout.size(), layout.align())
30+
DLMALLOC.lock().calloc(layout.size(), layout.align())
2831
}
2932

3033
#[inline]
3134
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
32-
DLMALLOC.free(ptr, layout.size(), layout.align())
35+
DLMALLOC.lock().free(ptr, layout.size(), layout.align())
3336
}
3437

3538
#[inline]
3639
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
37-
DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
40+
DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size)
3841
}
3942
}

src/libstd/sys/sgx/condvar.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,42 @@
1111
use sys::mutex::Mutex;
1212
use time::Duration;
1313

14-
pub struct Condvar { }
14+
use super::waitqueue::{WaitVariable, WaitQueue, SpinMutex};
15+
16+
pub struct Condvar {
17+
inner: SpinMutex<WaitVariable<()>>,
18+
}
1519

1620
impl Condvar {
21+
#[unstable(feature = "sgx_internals", issue = "0")] // FIXME: min_const_fn
1722
pub const fn new() -> Condvar {
18-
Condvar { }
23+
Condvar { inner: SpinMutex::new(WaitVariable::new(())) }
1924
}
2025

2126
#[inline]
2227
pub unsafe fn init(&mut self) {}
2328

2429
#[inline]
2530
pub unsafe fn notify_one(&self) {
31+
let _ = WaitQueue::notify_one(self.inner.lock());
2632
}
2733

2834
#[inline]
2935
pub unsafe fn notify_all(&self) {
36+
let _ = WaitQueue::notify_all(self.inner.lock());
3037
}
3138

32-
pub unsafe fn wait(&self, _mutex: &Mutex) {
33-
panic!("can't block with web assembly")
39+
pub unsafe fn wait(&self, mutex: &Mutex) {
40+
let guard = self.inner.lock();
41+
mutex.unlock();
42+
WaitQueue::wait(guard);
43+
mutex.lock()
3444
}
3545

3646
pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
37-
panic!("can't block with web assembly");
47+
panic!("timeout not supported in SGX");
3848
}
3949

4050
#[inline]
41-
pub unsafe fn destroy(&self) {
42-
}
51+
pub unsafe fn destroy(&self) {}
4352
}

src/libstd/sys/sgx/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use os::raw::c_char;
1818
use sync::atomic::{AtomicBool, Ordering};
1919

2020
pub mod abi;
21+
mod waitqueue;
2122

2223
pub mod alloc;
2324
pub mod args;

src/libstd/sys/sgx/mutex.rs

+98-24
Original file line numberDiff line numberDiff line change
@@ -8,71 +8,145 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use cell::UnsafeCell;
11+
use fortanix_sgx_abi::Tcs;
12+
13+
use super::abi::thread;
14+
15+
use super::waitqueue::{WaitVariable, WaitQueue, SpinMutex, NotifiedTcs, try_lock_or_false};
1216

1317
pub struct Mutex {
14-
locked: UnsafeCell<bool>,
18+
inner: SpinMutex<WaitVariable<bool>>,
1519
}
1620

17-
unsafe impl Send for Mutex {}
18-
unsafe impl Sync for Mutex {} // FIXME
19-
21+
// Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
2022
impl Mutex {
23+
#[unstable(feature = "sgx_internals", issue = "0")] // FIXME: min_const_fn
2124
pub const fn new() -> Mutex {
22-
Mutex { locked: UnsafeCell::new(false) }
25+
Mutex { inner: SpinMutex::new(WaitVariable::new(false)) }
2326
}
2427

2528
#[inline]
26-
pub unsafe fn init(&mut self) {
27-
}
29+
pub unsafe fn init(&mut self) {}
2830

2931
#[inline]
3032
pub unsafe fn lock(&self) {
31-
let locked = self.locked.get();
32-
assert!(!*locked, "cannot recursively acquire mutex");
33-
*locked = true;
33+
let mut guard = self.inner.lock();
34+
if *guard.lock_var() {
35+
// Another thread has the lock, wait
36+
WaitQueue::wait(guard)
37+
// Another thread has passed the lock to us
38+
} else {
39+
// We are just now obtaining the lock
40+
*guard.lock_var_mut() = true;
41+
}
3442
}
3543

3644
#[inline]
3745
pub unsafe fn unlock(&self) {
38-
*self.locked.get() = false;
46+
let guard = self.inner.lock();
47+
if let Err(mut guard) = WaitQueue::notify_one(guard) {
48+
// No other waiters, unlock
49+
*guard.lock_var_mut() = false;
50+
} else {
51+
// There was a thread waiting, just pass the lock
52+
}
3953
}
4054

4155
#[inline]
4256
pub unsafe fn try_lock(&self) -> bool {
43-
let locked = self.locked.get();
44-
if *locked {
57+
let mut guard = try_lock_or_false!(self.inner);
58+
if *guard.lock_var() {
59+
// Another thread has the lock
4560
false
4661
} else {
47-
*locked = true;
62+
// We are just now obtaining the lock
63+
*guard.lock_var_mut() = true;
4864
true
4965
}
5066
}
5167

5268
#[inline]
53-
pub unsafe fn destroy(&self) {
54-
}
69+
pub unsafe fn destroy(&self) {}
70+
}
71+
72+
struct ReentrantLock {
73+
owner: Option<Tcs>,
74+
count: usize
5575
}
5676

57-
// FIXME
5877
pub struct ReentrantMutex {
78+
inner: SpinMutex<WaitVariable<ReentrantLock>>,
5979
}
6080

6181
impl ReentrantMutex {
62-
pub unsafe fn uninitialized() -> ReentrantMutex {
63-
ReentrantMutex { }
82+
#[unstable(feature = "sgx_internals", issue = "0")] // FIXME: min_const_fn
83+
pub const fn uninitialized() -> ReentrantMutex {
84+
ReentrantMutex {
85+
inner: SpinMutex::new(WaitVariable::new(ReentrantLock { owner: None, count: 0 }))
86+
}
6487
}
6588

89+
#[inline]
6690
pub unsafe fn init(&mut self) {}
6791

68-
pub unsafe fn lock(&self) {}
92+
#[inline]
93+
pub unsafe fn lock(&self) {
94+
let mut guard = self.inner.lock();
95+
match guard.lock_var().owner {
96+
Some(tcs) if tcs != thread::current() => {
97+
// Another thread has the lock, wait
98+
WaitQueue::wait(guard);
99+
// Another thread has passed the lock to us
100+
},
101+
_ => {
102+
// We are just now obtaining the lock
103+
guard.lock_var_mut().owner = Some(thread::current());
104+
guard.lock_var_mut().count += 1;
105+
},
106+
}
107+
}
69108

70109
#[inline]
71-
pub unsafe fn try_lock(&self) -> bool {
72-
true
110+
pub unsafe fn unlock(&self) {
111+
let mut guard = self.inner.lock();
112+
if guard.lock_var().count > 1 {
113+
guard.lock_var_mut().count -= 1;
114+
} else {
115+
match WaitQueue::notify_one(guard) {
116+
Err(mut guard) => {
117+
// No other waiters, unlock
118+
guard.lock_var_mut().count = 0;
119+
guard.lock_var_mut().owner = None;
120+
},
121+
Ok(mut guard) => {
122+
// There was a thread waiting, just pass the lock
123+
if let NotifiedTcs::Single(tcs) = guard.notified_tcs() {
124+
guard.lock_var_mut().owner = Some(tcs)
125+
} else {
126+
unreachable!() // called notify_one
127+
}
128+
}
129+
}
130+
}
73131
}
74132

75-
pub unsafe fn unlock(&self) {}
133+
#[inline]
134+
pub unsafe fn try_lock(&self) -> bool {
135+
let mut guard = try_lock_or_false!(self.inner);
136+
match guard.lock_var().owner {
137+
Some(tcs) if tcs != thread::current() => {
138+
// Another thread has the lock
139+
false
140+
},
141+
_ => {
142+
// We are just now obtaining the lock
143+
guard.lock_var_mut().owner = Some(thread::current());
144+
guard.lock_var_mut().count += 1;
145+
true
146+
},
147+
}
148+
}
76149

150+
#[inline]
77151
pub unsafe fn destroy(&self) {}
78152
}

src/libstd/sys/sgx/os.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pub fn env() -> Env {
9292
}
9393

9494
pub fn getenv(_k: &OsStr) -> io::Result<Option<OsString>> {
95-
unsupported()
95+
Ok(None)
9696
}
9797

9898
pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {

0 commit comments

Comments
 (0)