Merge remote-tracking branch 'origin/upstream' am: 6eee6a40b4 am: 3795546d6b Original change: undetermined Change-Id: Ia04c4883272458a0b7d7a51285b6ad4152ab2970 Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..994cd47 --- /dev/null +++ b/Android.bp
@@ -0,0 +1,46 @@ +// This file is generated by cargo_embargo. +// Do not modify this file after the first "rust_*" or "genrule" module +// because the changes will be overridden on upgrade. +// Content before the first "rust_*" or "genrule" module is preserved. + +package { + default_applicable_licenses: ["external_rust_crates_libtry_lock_license"], +} + +license { + name: "external_rust_crates_libtry_lock_license", + visibility: [":__subpackages__"], + license_kinds: ["SPDX-license-identifier-MIT"], + license_text: ["LICENSE"], +} + +rust_library { + name: "libtry_lock", + host_supported: true, + crate_name: "try_lock", + cargo_env_compat: true, + cargo_pkg_version: "0.2.5", + crate_root: "src/lib.rs", + edition: "2015", + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + product_available: true, + vendor_available: true, +} + +rust_test { + name: "try-lock_test_src_lib", + host_supported: true, + crate_name: "try_lock", + cargo_env_compat: true, + cargo_pkg_version: "0.2.5", + crate_root: "src/lib.rs", + test_suites: ["general-tests"], + auto_gen_config: true, + test_options: { + unit_test: true, + }, + edition: "2015", +}
diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ef2f8dd --- /dev/null +++ b/Cargo.toml
@@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +name = "try-lock" +version = "0.2.5" +authors = ["Sean McArthur <[email protected]>"] +description = "A lightweight atomic lock." +homepage = "https://github.com/seanmonstar/try-lock" +documentation = "https://docs.rs/try-lock" +readme = "README.md" +keywords = [ + "lock", + "atomic", +] +categories = [ + "concurrency", + "no-std", +] +license = "MIT" +repository = "https://github.com/seanmonstar/try-lock" + +[dependencies]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig new file mode 100644 index 0000000..9fe3c62 --- /dev/null +++ b/Cargo.toml.orig
@@ -0,0 +1,14 @@ +[package] +name = "try-lock" +version = "0.2.5" # remember to update html_root_url +description = "A lightweight atomic lock." +keywords = ["lock", "atomic"] +categories = ["concurrency", "no-std"] +authors = ["Sean McArthur <[email protected]>"] +license = "MIT" +repository = "https://github.com/seanmonstar/try-lock" +homepage = "https://github.com/seanmonstar/try-lock" +documentation = "https://docs.rs/try-lock" +readme = "README.md" + +[dependencies]
diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ef65989 --- /dev/null +++ b/LICENSE
@@ -0,0 +1,21 @@ +Copyright (c) 2018-2023 Sean McArthur +Copyright (c) 2016 Alex Crichton + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +
diff --git a/METADATA b/METADATA new file mode 100644 index 0000000..e0c7b76 --- /dev/null +++ b/METADATA
@@ -0,0 +1,20 @@ +name: "try-lock" +description: "A lightweight atomic lock." +third_party { + identifier { + type: "crates.io" + value: "try-lock" + } + identifier { + type: "Archive" + value: "https://static.crates.io/crates/try-lock/try-lock-0.2.5.crate" + primary_source: true + } + version: "0.2.5" + license_type: NOTICE + last_upgrade_date { + year: 2024 + month: 5 + day: 27 + } +}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..48bea6e --- /dev/null +++ b/OWNERS
@@ -0,0 +1,2 @@ +# Bug component: 688011 +include platform/prebuilts/rust:main:/OWNERS
diff --git a/README.md b/README.md new file mode 100644 index 0000000..abbb0ea --- /dev/null +++ b/README.md
@@ -0,0 +1,44 @@ +# TryLock + +- [Crates.io](https://crates.io/crates/try-lock) +- [Docs](https://docs.rs/try-lock) + +A light-weight lock guarded by an atomic boolean. + +Most efficient when contention is low, acquiring the lock is a single atomic swap, and releasing it just 1 more atomic swap. + +## Example + +```rust +use std::sync::Arc; +use try_lock::TryLock; + +// a thing we want to share +struct Widget { + name: String, +} + +// lock it up! +let widget1 = Arc::new(TryLock::new(Widget { + name: "Spanner".into(), +})); + +let widget2 = widget1.clone(); + + +// mutate the widget +let mut locked = widget1.try_lock().expect("example isn't locked yet"); +locked.name.push_str(" Bundle"); + +// hands off, buddy +let not_locked = widget2.try_lock(); +assert!(not_locked.is_none(), "widget1 has the lock"); + +// ok, you can have it +drop(locked); + +let locked2 = widget2.try_lock().expect("widget1 lock is released"); + +assert_eq!(locked2.name, "Spanner Bundle"); +``` +
diff --git a/cargo_embargo.json b/cargo_embargo.json new file mode 100644 index 0000000..c8842d1 --- /dev/null +++ b/cargo_embargo.json
@@ -0,0 +1,4 @@ +{ + "run_cargo": false, + "tests": true +}
diff --git a/patches/std.diff b/patches/std.diff new file mode 100644 index 0000000..ed76c3e --- /dev/null +++ b/patches/std.diff
@@ -0,0 +1,24 @@ +diff --git a/src/lib.rs b/src/lib.rs +index 2811996..4faa975 100644 +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -1,7 +1,8 @@ + #![deny(missing_docs)] + #![deny(missing_debug_implementations)] + #![deny(warnings)] +-#![cfg_attr(not(test), no_std)] ++// ANDROID: Use std to allow building as a dylib. ++#![cfg_attr(not(any(test, android_dylib)), no_std)] + + //! A light-weight lock guarded by an atomic boolean. + //! +@@ -43,7 +44,8 @@ + //! assert_eq!(locked2.name, "Spanner Bundle"); + //! ``` + +-#[cfg(test)] ++// ANDROID: Use std to allow building as a dylib. ++#[cfg(any(test, android_dylib))] + extern crate core; + + use core::cell::UnsafeCell;
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4faa975 --- /dev/null +++ b/src/lib.rs
@@ -0,0 +1,268 @@ +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![deny(warnings)] +// ANDROID: Use std to allow building as a dylib. +#![cfg_attr(not(any(test, android_dylib)), no_std)] + +//! A light-weight lock guarded by an atomic boolean. +//! +//! Most efficient when contention is low, acquiring the lock is a single +//! atomic swap, and releasing it just 1 more atomic swap. +//! +//! # Example +//! +//! ``` +//! use std::sync::Arc; +//! use try_lock::TryLock; +//! +//! // a thing we want to share +//! struct Widget { +//! name: String, +//! } +//! +//! // lock it up! +//! let widget1 = Arc::new(TryLock::new(Widget { +//! name: "Spanner".into(), +//! })); +//! +//! let widget2 = widget1.clone(); +//! +//! +//! // mutate the widget +//! let mut locked = widget1.try_lock().expect("example isn't locked yet"); +//! locked.name.push_str(" Bundle"); +//! +//! // hands off, buddy +//! let not_locked = widget2.try_lock(); +//! assert!(not_locked.is_none(), "widget1 has the lock"); +//! +//! // ok, you can have it +//! drop(locked); +//! +//! let locked2 = widget2.try_lock().expect("widget1 lock is released"); +//! +//! assert_eq!(locked2.name, "Spanner Bundle"); +//! ``` + +// ANDROID: Use std to allow building as a dylib. +#[cfg(any(test, android_dylib))] +extern crate core; + +use core::cell::UnsafeCell; +use core::fmt; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::{AtomicBool, Ordering}; +use core::marker::PhantomData; + +/// A light-weight lock guarded by an atomic boolean. +/// +/// Most efficient when contention is low, acquiring the lock is a single +/// atomic swap, and releasing it just 1 more atomic swap. +/// +/// It is only possible to try to acquire the lock, it is not possible to +/// wait for the lock to become ready, like with a `Mutex`. +#[derive(Default)] +pub struct TryLock<T> { + is_locked: AtomicBool, + value: UnsafeCell<T>, +} + +impl<T> TryLock<T> { + /// Create a `TryLock` around the value. + #[inline] + pub const fn new(val: T) -> TryLock<T> { + TryLock { + is_locked: AtomicBool::new(false), + value: UnsafeCell::new(val), + } + } + + /// Try to acquire the lock of this value. + /// + /// If the lock is already acquired by someone else, this returns + /// `None`. You can try to acquire again whenever you want, perhaps + /// by spinning a few times, or by using some other means of + /// notification. + /// + /// # Note + /// + /// The default memory ordering is to use `Acquire` to lock, and `Release` + /// to unlock. If different ordering is required, use + /// [`try_lock_explicit`](TryLock::try_lock_explicit) or + /// [`try_lock_explicit_unchecked`](TryLock::try_lock_explicit_unchecked). + #[inline] + pub fn try_lock(&self) -> Option<Locked<T>> { + unsafe { + self.try_lock_explicit_unchecked(Ordering::Acquire, Ordering::Release) + } + } + + /// Try to acquire the lock of this value using the lock and unlock orderings. + /// + /// If the lock is already acquired by someone else, this returns + /// `None`. You can try to acquire again whenever you want, perhaps + /// by spinning a few times, or by using some other means of + /// notification. + #[inline] + #[deprecated( + since = "0.2.3", + note = "This method is actually unsafe because it unsafely allows \ + the use of weaker memory ordering. Please use try_lock_explicit instead" + )] + pub fn try_lock_order(&self, lock_order: Ordering, unlock_order: Ordering) -> Option<Locked<T>> { + unsafe { + self.try_lock_explicit_unchecked(lock_order, unlock_order) + } + } + + /// Try to acquire the lock of this value using the specified lock and + /// unlock orderings. + /// + /// If the lock is already acquired by someone else, this returns + /// `None`. You can try to acquire again whenever you want, perhaps + /// by spinning a few times, or by using some other means of + /// notification. + /// + /// # Panic + /// + /// This method panics if `lock_order` is not any of `Acquire`, `AcqRel`, + /// and `SeqCst`, or `unlock_order` is not any of `Release` and `SeqCst`. + #[inline] + pub fn try_lock_explicit(&self, lock_order: Ordering, unlock_order: Ordering) -> Option<Locked<T>> { + match lock_order { + Ordering::Acquire | + Ordering::AcqRel | + Ordering::SeqCst => {} + _ => panic!("lock ordering must be `Acquire`, `AcqRel`, or `SeqCst`"), + } + + match unlock_order { + Ordering::Release | + Ordering::SeqCst => {} + _ => panic!("unlock ordering must be `Release` or `SeqCst`"), + } + + unsafe { + self.try_lock_explicit_unchecked(lock_order, unlock_order) + } + } + + /// Try to acquire the lock of this value using the specified lock and + /// unlock orderings without checking that the specified orderings are + /// strong enough to be safe. + /// + /// If the lock is already acquired by someone else, this returns + /// `None`. You can try to acquire again whenever you want, perhaps + /// by spinning a few times, or by using some other means of + /// notification. + /// + /// # Safety + /// + /// Unlike [`try_lock_explicit`], this method is unsafe because it does not + /// check that the given memory orderings are strong enough to prevent data + /// race. + /// + /// [`try_lock_explicit`]: Self::try_lock_explicit + #[inline] + pub unsafe fn try_lock_explicit_unchecked(&self, lock_order: Ordering, unlock_order: Ordering) -> Option<Locked<T>> { + if !self.is_locked.swap(true, lock_order) { + Some(Locked { + lock: self, + order: unlock_order, + _p: PhantomData, + }) + } else { + None + } + } + + /// Take the value back out of the lock when this is the sole owner. + #[inline] + pub fn into_inner(self) -> T { + debug_assert!(!self.is_locked.load(Ordering::Relaxed), "TryLock was mem::forgotten"); + self.value.into_inner() + } +} + +unsafe impl<T: Send> Send for TryLock<T> {} +unsafe impl<T: Send> Sync for TryLock<T> {} + +impl<T: fmt::Debug> fmt::Debug for TryLock<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + + // Used if the TryLock cannot acquire the lock. + struct LockedPlaceholder; + + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("<locked>") + } + } + + let mut builder = f.debug_struct("TryLock"); + if let Some(locked) = self.try_lock() { + builder.field("value", &*locked); + } else { + builder.field("value", &LockedPlaceholder); + } + builder.finish() + } +} + +/// A locked value acquired from a `TryLock`. +/// +/// The type represents an exclusive view at the underlying value. The lock is +/// released when this type is dropped. +/// +/// This type derefs to the underlying value. +#[must_use = "TryLock will immediately unlock if not used"] +pub struct Locked<'a, T: 'a> { + lock: &'a TryLock<T>, + order: Ordering, + /// Suppresses Send and Sync autotraits for `struct Locked`. + _p: PhantomData<*mut T>, +} + +impl<'a, T> Deref for Locked<'a, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + unsafe { &*self.lock.value.get() } + } +} + +impl<'a, T> DerefMut for Locked<'a, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.lock.value.get() } + } +} + +impl<'a, T> Drop for Locked<'a, T> { + #[inline] + fn drop(&mut self) { + self.lock.is_locked.store(false, self.order); + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for Locked<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(test)] +mod tests { + use super::TryLock; + + #[test] + fn fmt_debug() { + let lock = TryLock::new(5); + assert_eq!(format!("{:?}", lock), "TryLock { value: 5 }"); + + let locked = lock.try_lock().unwrap(); + assert_eq!(format!("{:?}", locked), "5"); + + assert_eq!(format!("{:?}", lock), "TryLock { value: <locked> }"); + } +}