about summary refs log tree commit diff
diff options
context:
space:
mode:
authorjoboet <jonasboettiger@icloud.com>2024-04-11 19:36:30 +0200
committerjoboet <jonasboettiger@icloud.com>2024-04-11 19:36:30 +0200
commita30a79c5b4c3f470648adbfe3eb11575e72b2f97 (patch)
tree25a1bf55c485106af747b18dfa967a1bc831c24d
parent72fe8a0f0049873f4b1d0ab3c482170921819106 (diff)
downloadrust-a30a79c5b4c3f470648adbfe3eb11575e72b2f97.tar.gz
rust-a30a79c5b4c3f470648adbfe3eb11575e72b2f97.zip
std: use queue-based `RwLock` on SGX
-rw-r--r--library/std/src/sys/pal/sgx/libunwind_integration.rs46
-rw-r--r--library/std/src/sys/pal/sgx/mod.rs1
-rw-r--r--library/std/src/sys/pal/sgx/waitqueue/mod.rs21
-rw-r--r--library/std/src/sys/sync/rwlock/sgx.rs219
-rw-r--r--library/std/src/sys/sync/rwlock/sgx/tests.rs21
5 files changed, 47 insertions, 261 deletions
diff --git a/library/std/src/sys/pal/sgx/libunwind_integration.rs b/library/std/src/sys/pal/sgx/libunwind_integration.rs
new file mode 100644
index 00000000000..debfd324c86
--- /dev/null
+++ b/library/std/src/sys/pal/sgx/libunwind_integration.rs
@@ -0,0 +1,46 @@
+//! The functions in this module are needed by libunwind. These symbols are named
+//! in pre-link args for the target specification, so keep that in sync.
+
+#![cfg(not(test))]
+
+use crate::sys::sync::RwLock;
+
+// Verify that the byte pattern libunwind uses to initialize an RwLock is
+// equivalent to the value of RwLock::new(). If the value changes,
+// `src/UnwindRustSgx.h` in libunwind needs to be changed too.
+const _: () = unsafe {
+    let bits_rust: usize = crate::mem::transmute(RwLock::new());
+    assert!(bits_rust == 0);
+};
+
+const EINVAL: i32 = 22;
+
+#[no_mangle]
+pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RwLock) -> i32 {
+    if p.is_null() {
+        return EINVAL;
+    }
+
+    // We cannot differentiate between reads an writes in unlock and therefore
+    // always use a write-lock. Unwinding isn't really in the hot path anyway.
+    unsafe { (*p).write() };
+    return 0;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RwLock) -> i32 {
+    if p.is_null() {
+        return EINVAL;
+    }
+    unsafe { (*p).write() };
+    return 0;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 {
+    if p.is_null() {
+        return EINVAL;
+    }
+    unsafe { (*p).write_unlock() };
+    return 0;
+}
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 76f930b86f2..d30976ec151 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -17,6 +17,7 @@ pub mod fd;
 pub mod fs;
 #[path = "../unsupported/io.rs"]
 pub mod io;
+mod libunwind_integration;
 pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/pal/sgx/waitqueue/mod.rs b/library/std/src/sys/pal/sgx/waitqueue/mod.rs
index 2d952b7ebbc..ea49bb28034 100644
--- a/library/std/src/sys/pal/sgx/waitqueue/mod.rs
+++ b/library/std/src/sys/pal/sgx/waitqueue/mod.rs
@@ -52,10 +52,6 @@ impl<T> WaitVariable<T> {
         WaitVariable { queue: WaitQueue::new(), lock: var }
     }
 
-    pub fn queue_empty(&self) -> bool {
-        self.queue.is_empty()
-    }
-
     pub fn lock_var(&self) -> &T {
         &self.lock
     }
@@ -98,19 +94,6 @@ impl Default for WaitQueue {
     }
 }
 
-impl<'a, T> WaitGuard<'a, T> {
-    /// Returns which TCSes will be notified when this guard drops.
-    pub fn notified_tcs(&self) -> NotifiedTcs {
-        self.notified_tcs
-    }
-
-    /// Drop this `WaitGuard`, after dropping another `guard`.
-    pub fn drop_after<U>(self, guard: U) {
-        drop(guard);
-        drop(self);
-    }
-}
-
 impl<'a, T> Deref for WaitGuard<'a, T> {
     type Target = SpinMutexGuard<'a, WaitVariable<T>>;
 
@@ -141,10 +124,6 @@ impl WaitQueue {
         WaitQueue { inner: UnsafeList::new() }
     }
 
-    pub fn is_empty(&self) -> bool {
-        self.inner.is_empty()
-    }
-
     /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
     /// until a wakeup event.
     ///
diff --git a/library/std/src/sys/sync/rwlock/sgx.rs b/library/std/src/sys/sync/rwlock/sgx.rs
deleted file mode 100644
index 136dea597bb..00000000000
--- a/library/std/src/sys/sync/rwlock/sgx.rs
+++ /dev/null
@@ -1,219 +0,0 @@
-#[cfg(test)]
-mod tests;
-
-use crate::alloc::Layout;
-use crate::num::NonZero;
-use crate::sys::pal::waitqueue::{
-    try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
-};
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-
-struct AllocatedRwLock {
-    readers: SpinMutex<WaitVariable<Option<NonZero<usize>>>>,
-    writer: SpinMutex<WaitVariable<bool>>,
-}
-
-pub struct RwLock {
-    inner: LazyBox<AllocatedRwLock>,
-}
-
-impl LazyInit for AllocatedRwLock {
-    fn init() -> Box<Self> {
-        Box::new(AllocatedRwLock {
-            readers: SpinMutex::new(WaitVariable::new(None)),
-            writer: SpinMutex::new(WaitVariable::new(false)),
-        })
-    }
-}
-
-// Check at compile time that RwLock's size and alignment matches the C definition
-// in libunwind (see also `test_c_rwlock_initializer` in `tests`).
-const _: () = {
-    let rust = Layout::new::<RwLock>();
-    let c = Layout::new::<*mut ()>();
-    assert!(rust.size() == c.size());
-    assert!(rust.align() == c.align());
-};
-
-impl RwLock {
-    pub const fn new() -> RwLock {
-        RwLock { inner: LazyBox::new() }
-    }
-
-    #[inline]
-    pub fn read(&self) {
-        let lock = &*self.inner;
-        let mut rguard = lock.readers.lock();
-        let wguard = lock.writer.lock();
-        if *wguard.lock_var() || !wguard.queue_empty() {
-            // Another thread has or is waiting for the write lock, wait
-            drop(wguard);
-            WaitQueue::wait(rguard, || {});
-        // Another thread has passed the lock to us
-        } else {
-            // No waiting writers, acquire the read lock
-            *rguard.lock_var_mut() = NonZero::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        let lock = &*self.inner;
-        let mut rguard = try_lock_or_false!(lock.readers);
-        let wguard = try_lock_or_false!(lock.writer);
-        if *wguard.lock_var() || !wguard.queue_empty() {
-            // Another thread has or is waiting for the write lock
-            false
-        } else {
-            // No waiting writers, acquire the read lock
-            *rguard.lock_var_mut() = NonZero::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
-            true
-        }
-    }
-
-    #[inline]
-    pub fn write(&self) {
-        let lock = &*self.inner;
-        let rguard = lock.readers.lock();
-        let mut wguard = lock.writer.lock();
-        if *wguard.lock_var() || rguard.lock_var().is_some() {
-            // Another thread has the lock, wait
-            drop(rguard);
-            WaitQueue::wait(wguard, || {});
-        // Another thread has passed the lock to us
-        } else {
-            // We are just now obtaining the lock
-            *wguard.lock_var_mut() = true;
-        }
-    }
-
-    #[inline]
-    pub fn try_write(&self) -> bool {
-        let lock = &*self.inner;
-        let rguard = try_lock_or_false!(lock.readers);
-        let mut wguard = try_lock_or_false!(lock.writer);
-        if *wguard.lock_var() || rguard.lock_var().is_some() {
-            // Another thread has the lock
-            false
-        } else {
-            // We are just now obtaining the lock
-            *wguard.lock_var_mut() = true;
-            true
-        }
-    }
-
-    #[inline]
-    unsafe fn __read_unlock(
-        &self,
-        mut rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZero<usize>>>>,
-        wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
-    ) {
-        *rguard.lock_var_mut() = NonZero::new(rguard.lock_var().unwrap().get() - 1);
-        if rguard.lock_var().is_some() {
-            // There are other active readers
-        } else {
-            if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
-                // A writer was waiting, pass the lock
-                *wguard.lock_var_mut() = true;
-                wguard.drop_after(rguard);
-            } else {
-                // No writers were waiting, the lock is released
-                rtassert!(rguard.queue_empty());
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        let lock = &*self.inner;
-        let rguard = lock.readers.lock();
-        let wguard = lock.writer.lock();
-        unsafe { self.__read_unlock(rguard, wguard) };
-    }
-
-    #[inline]
-    unsafe fn __write_unlock(
-        &self,
-        rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZero<usize>>>>,
-        wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
-    ) {
-        match WaitQueue::notify_one(wguard) {
-            Err(mut wguard) => {
-                // No writers waiting, release the write lock
-                *wguard.lock_var_mut() = false;
-                if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
-                    // One or more readers were waiting, pass the lock to them
-                    if let NotifiedTcs::All { count } = rguard.notified_tcs() {
-                        *rguard.lock_var_mut() = Some(count)
-                    } else {
-                        unreachable!() // called notify_all
-                    }
-                    rguard.drop_after(wguard);
-                } else {
-                    // No readers waiting, the lock is released
-                }
-            }
-            Ok(wguard) => {
-                // There was a thread waiting for write, just pass the lock
-                wguard.drop_after(rguard);
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        let lock = &*self.inner;
-        let rguard = lock.readers.lock();
-        let wguard = lock.writer.lock();
-        unsafe { self.__write_unlock(rguard, wguard) };
-    }
-
-    // only used by __rust_rwlock_unlock below
-    #[inline]
-    #[cfg_attr(test, allow(dead_code))]
-    unsafe fn unlock(&self) {
-        let lock = &*self.inner;
-        let rguard = lock.readers.lock();
-        let wguard = lock.writer.lock();
-        if *wguard.lock_var() == true {
-            unsafe { self.__write_unlock(rguard, wguard) };
-        } else {
-            unsafe { self.__read_unlock(rguard, wguard) };
-        }
-    }
-}
-
-// The following functions are needed by libunwind. These symbols are named
-// in pre-link args for the target specification, so keep that in sync.
-#[cfg(not(test))]
-const EINVAL: i32 = 22;
-
-#[cfg(not(test))]
-#[no_mangle]
-pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RwLock) -> i32 {
-    if p.is_null() {
-        return EINVAL;
-    }
-    unsafe { (*p).read() };
-    return 0;
-}
-
-#[cfg(not(test))]
-#[no_mangle]
-pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RwLock) -> i32 {
-    if p.is_null() {
-        return EINVAL;
-    }
-    unsafe { (*p).write() };
-    return 0;
-}
-
-#[cfg(not(test))]
-#[no_mangle]
-pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 {
-    if p.is_null() {
-        return EINVAL;
-    }
-    unsafe { (*p).unlock() };
-    return 0;
-}
diff --git a/library/std/src/sys/sync/rwlock/sgx/tests.rs b/library/std/src/sys/sync/rwlock/sgx/tests.rs
deleted file mode 100644
index 5fd6670afd4..00000000000
--- a/library/std/src/sys/sync/rwlock/sgx/tests.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use super::*;
-use crate::ptr;
-
-// Verify that the byte pattern libunwind uses to initialize an RwLock is
-// equivalent to the value of RwLock::new(). If the value changes,
-// `src/UnwindRustSgx.h` in libunwind needs to be changed too.
-#[test]
-fn test_c_rwlock_initializer() {
-    const C_RWLOCK_INIT: *mut () = ptr::null_mut();
-
-    // For the test to work, we need the padding/unused bytes in RwLock to be
-    // initialized as 0. In practice, this is the case with statics.
-    static RUST_RWLOCK_INIT: RwLock = RwLock::new();
-
-    unsafe {
-        // If the assertion fails, that not necessarily an issue with the value
-        // of C_RWLOCK_INIT. It might just be an issue with the way padding
-        // bytes are initialized in the test code.
-        assert_eq!(crate::mem::transmute_copy::<_, *mut ()>(&RUST_RWLOCK_INIT), C_RWLOCK_INIT);
-    };
-}