about summary refs log tree commit diff
diff options
context:
space:
mode:
authorjoboet <jonasboettiger@icloud.com>2022-12-31 11:00:54 +0100
committerjoboet <jonasboettiger@icloud.com>2022-12-31 11:00:54 +0100
commit78245286dcde9f2cf99a370ec0cd4383fa684404 (patch)
tree595c18d4e82ed2c74443128948582e20253a08d2
parent247e44e61d934e1927db0ff557fe17f131a2379c (diff)
downloadrust-78245286dcde9f2cf99a370ec0cd4383fa684404.tar.gz
rust-78245286dcde9f2cf99a370ec0cd4383fa684404.zip
std: use id-based thread parking on SOLID
-rw-r--r--library/std/src/sys/itron/thread_parking.rs37
-rw-r--r--library/std/src/sys/itron/wait_flag.rs72
-rw-r--r--library/std/src/sys/solid/mod.rs4
-rw-r--r--library/std/src/sys_common/thread_parking/mod.rs4
-rw-r--r--library/std/src/sys_common/thread_parking/wait_flag.rs102
5 files changed, 40 insertions, 179 deletions
diff --git a/library/std/src/sys/itron/thread_parking.rs b/library/std/src/sys/itron/thread_parking.rs
new file mode 100644
index 00000000000..fe9934439d1
--- /dev/null
+++ b/library/std/src/sys/itron/thread_parking.rs
@@ -0,0 +1,37 @@
+use super::abi;
+use super::error::expect_success_aborting;
+use super::time::with_tmos;
+use crate::time::Duration;
+
+pub type ThreadId = abi::ID;
+
+pub use super::task::current_task_id_aborting as current;
+
+pub fn park(_hint: usize) {
+    match unsafe { abi::slp_tsk() } {
+        abi::E_OK | abi::E_RLWAI => {}
+        err => {
+            expect_success_aborting(err, &"slp_tsk");
+        }
+    }
+}
+
+pub fn park_timeout(dur: Duration, _hint: usize) {
+    match with_tmos(dur, |tmo| unsafe { abi::tslp_tsk(tmo) }) {
+        abi::E_OK | abi::E_RLWAI | abi::E_TMOUT => {}
+        err => {
+            expect_success_aborting(err, &"tslp_tsk");
+        }
+    }
+}
+
+pub fn unpark(id: ThreadId, _hint: usize) {
+    match unsafe { abi::wup_tsk(id) } {
+        // It is allowed to try to wake up a destroyed or unrelated task, so we ignore all
+        // errors that could result from that situation.
+        abi::E_OK | abi::E_NOEXS | abi::E_OBJ | abi::E_QOVR => {}
+        err => {
+            expect_success_aborting(err, &"wup_tsk");
+        }
+    }
+}
diff --git a/library/std/src/sys/itron/wait_flag.rs b/library/std/src/sys/itron/wait_flag.rs
deleted file mode 100644
index e432edd2077..00000000000
--- a/library/std/src/sys/itron/wait_flag.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use crate::mem::MaybeUninit;
-use crate::time::Duration;
-
-use super::{
-    abi,
-    error::{expect_success, fail},
-    time::with_tmos,
-};
-
-const CLEAR: abi::FLGPTN = 0;
-const RAISED: abi::FLGPTN = 1;
-
-/// A thread parking primitive that is not susceptible to race conditions,
-/// but provides no atomic ordering guarantees and allows only one `raise` per wait.
-pub struct WaitFlag {
-    flag: abi::ID,
-}
-
-impl WaitFlag {
-    /// Creates a new wait flag.
-    pub fn new() -> WaitFlag {
-        let flag = expect_success(
-            unsafe {
-                abi::acre_flg(&abi::T_CFLG {
-                    flgatr: abi::TA_FIFO | abi::TA_WSGL | abi::TA_CLR,
-                    iflgptn: CLEAR,
-                })
-            },
-            &"acre_flg",
-        );
-
-        WaitFlag { flag }
-    }
-
-    /// Wait for the wait flag to be raised.
-    pub fn wait(&self) {
-        let mut token = MaybeUninit::uninit();
-        expect_success(
-            unsafe { abi::wai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr()) },
-            &"wai_flg",
-        );
-    }
-
-    /// Wait for the wait flag to be raised or the timeout to occur.
-    ///
-    /// Returns whether the flag was raised (`true`) or the operation timed out (`false`).
-    pub fn wait_timeout(&self, dur: Duration) -> bool {
-        let mut token = MaybeUninit::uninit();
-        let res = with_tmos(dur, |tmout| unsafe {
-            abi::twai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr(), tmout)
-        });
-
-        match res {
-            abi::E_OK => true,
-            abi::E_TMOUT => false,
-            error => fail(error, &"twai_flg"),
-        }
-    }
-
-    /// Raise the wait flag.
-    ///
-    /// Calls to this function should be balanced with the number of successful waits.
-    pub fn raise(&self) {
-        expect_success(unsafe { abi::set_flg(self.flag, RAISED) }, &"set_flg");
-    }
-}
-
-impl Drop for WaitFlag {
-    fn drop(&mut self) {
-        expect_success(unsafe { abi::del_flg(self.flag) }, &"del_flg");
-    }
-}
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 5867979a2a7..923d27fd936 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -13,9 +13,9 @@ mod itron {
     pub(super) mod spin;
     pub(super) mod task;
     pub mod thread;
+    pub mod thread_parking;
     pub(super) mod time;
     use super::unsupported;
-    pub mod wait_flag;
 }
 
 pub mod alloc;
@@ -43,8 +43,8 @@ pub use self::itron::thread;
 pub mod memchr;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
+pub use self::itron::thread_parking;
 pub mod time;
-pub use self::itron::wait_flag;
 
 mod rwlock;
 
diff --git a/library/std/src/sys_common/thread_parking/mod.rs b/library/std/src/sys_common/thread_parking/mod.rs
index 0ead6633c35..e8e028bb330 100644
--- a/library/std/src/sys_common/thread_parking/mod.rs
+++ b/library/std/src/sys_common/thread_parking/mod.rs
@@ -14,12 +14,10 @@ cfg_if::cfg_if! {
     } else if #[cfg(any(
         target_os = "netbsd",
         all(target_vendor = "fortanix", target_env = "sgx"),
+        target_os = "solid_asp3",
     ))] {
         mod id;
         pub use id::Parker;
-    } else if #[cfg(target_os = "solid_asp3")] {
-        mod wait_flag;
-        pub use wait_flag::Parker;
     } else if #[cfg(any(windows, target_family = "unix"))] {
         pub use crate::sys::thread_parking::Parker;
     } else {
diff --git a/library/std/src/sys_common/thread_parking/wait_flag.rs b/library/std/src/sys_common/thread_parking/wait_flag.rs
deleted file mode 100644
index d0f8899a94e..00000000000
--- a/library/std/src/sys_common/thread_parking/wait_flag.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-//! A wait-flag-based thread parker.
-//!
-//! Some operating systems provide low-level parking primitives like wait counts,
-//! event flags or semaphores which are not susceptible to race conditions (meaning
-//! the wakeup can occur before the wait operation). To implement the `std` thread
-//! parker on top of these primitives, we only have to ensure that parking is fast
-//! when the thread token is available, the atomic ordering guarantees are maintained
-//! and spurious wakeups are minimized.
-//!
-//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`,
-//! `PARKED` and `NOTIFIED`:
-//! * `EMPTY` means the token has not been made available, but the thread is not
-//!    currently waiting on it.
-//! * `PARKED` means the token is not available and the thread is parked.
-//! * `NOTIFIED` means the token is available.
-//!
-//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from
-//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and
-//! execution can continue without calling into the OS. If the state was `EMPTY`,
-//! the token is not available and the thread waits on the primitive (here called
-//! "wait flag").
-//!
-//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread
-//! is or will be sleeping on the wait flag, so we raise it.
-
-use crate::pin::Pin;
-use crate::sync::atomic::AtomicI8;
-use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::sys::wait_flag::WaitFlag;
-use crate::time::Duration;
-
-const EMPTY: i8 = 0;
-const PARKED: i8 = -1;
-const NOTIFIED: i8 = 1;
-
-pub struct Parker {
-    state: AtomicI8,
-    wait_flag: WaitFlag,
-}
-
-impl Parker {
-    /// Construct a parker for the current thread. The UNIX parker
-    /// implementation requires this to happen in-place.
-    pub unsafe fn new_in_place(parker: *mut Parker) {
-        parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park(self: Pin<&Self>) {
-        match self.state.fetch_sub(1, Acquire) {
-            // NOTIFIED => EMPTY
-            NOTIFIED => return,
-            // EMPTY => PARKED
-            EMPTY => (),
-            _ => panic!("inconsistent park state"),
-        }
-
-        // Avoid waking up from spurious wakeups (these are quite likely, see below).
-        loop {
-            self.wait_flag.wait();
-
-            match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
-                Ok(_) => return,
-                Err(PARKED) => (),
-                Err(_) => panic!("inconsistent park state"),
-            }
-        }
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        match self.state.fetch_sub(1, Acquire) {
-            NOTIFIED => return,
-            EMPTY => (),
-            _ => panic!("inconsistent park state"),
-        }
-
-        self.wait_flag.wait_timeout(dur);
-
-        // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be
-        // a race condition when `unpark` is performed between receiving the timeout and
-        // resetting the state, resulting in the eventflag being set unnecessarily. `park`
-        // is protected against this by looping until the token is actually given, but
-        // here we cannot easily tell.
-
-        // Use `swap` to provide acquire ordering.
-        match self.state.swap(EMPTY, Acquire) {
-            NOTIFIED => (),
-            PARKED => (),
-            _ => panic!("inconsistent park state"),
-        }
-    }
-
-    // This implementation doesn't require `Pin`, but other implementations do.
-    pub fn unpark(self: Pin<&Self>) {
-        let state = self.state.swap(NOTIFIED, Release);
-
-        if state == PARKED {
-            self.wait_flag.raise();
-        }
-    }
-}