1 #![cfg_attr(test, allow(dead_code))] // why is this necessary?
2 use super::unsupported;
5 use crate::num::NonZeroUsize;
6 use crate::time::Duration;
8 use super::abi::usercalls;
10 pub struct Thread(task_queue::JoinHandle);
12 pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
14 pub use self::task_queue::JoinNotifier;
17 use super::wait_notify;
18 use crate::sync::{Mutex, MutexGuard, Once};
20 pub type JoinHandle = wait_notify::Waiter;
22 pub struct JoinNotifier(Option<wait_notify::Notifier>);
24 impl Drop for JoinNotifier {
26 self.0.take().unwrap().notify();
30 pub(super) struct Task {
36 pub(super) fn new(p: Box<dyn FnOnce()>) -> (Task, JoinHandle) {
37 let (done, recv) = wait_notify::new();
38 let done = JoinNotifier(Some(done));
39 (Task { p, done }, recv)
42 pub(super) fn run(self) -> JoinNotifier {
48 #[cfg_attr(test, linkage = "available_externally")]
49 #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread15TASK_QUEUE_INITE"]
50 static TASK_QUEUE_INIT: Once = Once::new();
51 #[cfg_attr(test, linkage = "available_externally")]
52 #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE"]
53 static mut TASK_QUEUE: Option<Mutex<Vec<Task>>> = None;
55 pub(super) fn lock() -> MutexGuard<'static, Vec<Task>> {
57 TASK_QUEUE_INIT.call_once(|| TASK_QUEUE = Some(Default::default()));
58 TASK_QUEUE.as_ref().unwrap().lock().unwrap()
63 /// This module provides a synchronization primitive that does not use thread
64 /// local variables. This is needed for signaling that a thread has finished
65 /// execution. The signal is sent once all TLS destructors have finished at
66 /// which point no new thread locals should be created.
68 use super::super::thread_parker::Parker;
72 pub struct Notifier(Arc<Parker>);
75 /// Notify the waiter. The waiter is either notified right away (if
76 /// currently blocked in `Waiter::wait()`) or later when it calls the
77 /// `Waiter::wait()` method.
79 Pin::new(&*self.0).unpark()
83 pub struct Waiter(Arc<Parker>);
86 /// Wait for a notification. If `Notifier::notify()` has already been
87 /// called, this will return immediately, otherwise the current thread
88 /// is blocked until notified.
90 // This is not actually `unsafe`, but it uses the `Parker` API,
91 // which needs `unsafe` on some platforms.
92 unsafe { Pin::new(&*self.0).park() }
96 pub fn new() -> (Notifier, Waiter) {
97 let inner = Arc::new(Parker::new_internal());
98 (Notifier(inner.clone()), Waiter(inner))
103 // unsafe: see thread::Builder::spawn_unchecked for safety requirements
104 pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
105 let mut queue_lock = task_queue::lock();
106 unsafe { usercalls::launch_thread()? };
107 let (task, handle) = task_queue::Task::new(p);
108 queue_lock.push(task);
112 pub(super) fn entry() -> JoinNotifier {
113 let mut pending_tasks = task_queue::lock();
114 let task = rtunwrap!(Some, pending_tasks.pop());
115 drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
120 let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
121 rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
124 pub fn set_name(_name: &CStr) {
125 // FIXME: could store this pointer in TLS somewhere
128 pub fn sleep(dur: Duration) {
129 usercalls::wait_timeout(0, dur, || true);
137 pub fn available_parallelism() -> io::Result<NonZeroUsize> {
143 pub unsafe fn current() -> Option<Guard> {
146 pub unsafe fn init() -> Option<Guard> {