From 43a97878ce14b72f0981164f87f2e35e14151312 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:22:09 +0200 Subject: Adding upstream version 110.0.1. Signed-off-by: Daniel Baumann --- third_party/rust/futures-channel/src/lock.rs | 102 +++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 third_party/rust/futures-channel/src/lock.rs (limited to 'third_party/rust/futures-channel/src/lock.rs') diff --git a/third_party/rust/futures-channel/src/lock.rs b/third_party/rust/futures-channel/src/lock.rs new file mode 100644 index 0000000000..b328d0f7dd --- /dev/null +++ b/third_party/rust/futures-channel/src/lock.rs @@ -0,0 +1,102 @@ +//! A "mutex" which only supports `try_lock` +//! +//! As a futures library the eventual call to an event loop should be the only +//! thing that ever blocks, so this is assisted with a fast user-space +//! implementation of a lock that can only have a `try_lock` operation. + +use core::cell::UnsafeCell; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::AtomicBool; +use core::sync::atomic::Ordering::SeqCst; + +/// A "mutex" around a value, similar to `std::sync::Mutex`. +/// +/// This lock only supports the `try_lock` operation, however, and does not +/// implement poisoning. +#[derive(Debug)] +pub(crate) struct Lock { + locked: AtomicBool, + data: UnsafeCell, +} + +/// Sentinel representing an acquired lock through which the data can be +/// accessed. +pub(crate) struct TryLock<'a, T> { + __ptr: &'a Lock, +} + +// The `Lock` structure is basically just a `Mutex`, and these two impls are +// intended to mirror the standard library's corresponding impls for `Mutex`. +// +// If a `T` is sendable across threads, so is the lock, and `T` must be sendable +// across threads to be `Sync` because it allows mutable access from multiple +// threads. +unsafe impl Send for Lock {} +unsafe impl Sync for Lock {} + +impl Lock { + /// Creates a new lock around the given value. + pub(crate) fn new(t: T) -> Self { + Self { locked: AtomicBool::new(false), data: UnsafeCell::new(t) } + } + + /// Attempts to acquire this lock, returning whether the lock was acquired or + /// not. + /// + /// If `Some` is returned then the data this lock protects can be accessed + /// through the sentinel. This sentinel allows both mutable and immutable + /// access. + /// + /// If `None` is returned then the lock is already locked, either elsewhere + /// on this thread or on another thread. + pub(crate) fn try_lock(&self) -> Option> { + if !self.locked.swap(true, SeqCst) { + Some(TryLock { __ptr: self }) + } else { + None + } + } +} + +impl Deref for TryLock<'_, T> { + type Target = T; + fn deref(&self) -> &T { + // The existence of `TryLock` represents that we own the lock, so we + // can safely access the data here. + unsafe { &*self.__ptr.data.get() } + } +} + +impl DerefMut for TryLock<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // The existence of `TryLock` represents that we own the lock, so we + // can safely access the data here. + // + // Additionally, we're the *only* `TryLock` in existence so mutable + // access should be ok. + unsafe { &mut *self.__ptr.data.get() } + } +} + +impl Drop for TryLock<'_, T> { + fn drop(&mut self) { + self.__ptr.locked.store(false, SeqCst); + } +} + +#[cfg(test)] +mod tests { + use super::Lock; + + #[test] + fn smoke() { + let a = Lock::new(1); + let mut a1 = a.try_lock().unwrap(); + assert!(a.try_lock().is_none()); + assert_eq!(*a1, 1); + *a1 = 2; + drop(a1); + assert_eq!(*a.try_lock().unwrap(), 2); + assert_eq!(*a.try_lock().unwrap(), 2); + } +} -- cgit v1.2.3