From 824a531036c53205c3b22b4ceac4c88cd021f589 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Tue, 13 Dec 2022 09:36:41 +0100 Subject: Upgrade parking_lot to 0.12.1 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update rust/crates/parking_lot For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md Test: TreeHugger Change-Id: I89fe53441ba6f3bab0686c192f5e80ec3b640709 --- .cargo_vcs_info.json | 2 +- .github/workflows/rust.yml | 5 +- Android.bp | 2 +- CHANGELOG.md | 21 ++++ Cargo.toml | 19 +++- Cargo.toml.orig | 4 +- METADATA | 12 +- README.md | 24 ++-- src/condvar.rs | 266 +++++++++++++++++++++++++++++++++++++++++---- src/fair_mutex.rs | 2 +- src/mutex.rs | 2 +- src/once.rs | 12 +- src/raw_rwlock.rs | 4 +- src/rwlock.rs | 2 +- 14 files changed, 322 insertions(+), 55 deletions(-) diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 38c6551..ca34d9d 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "a75875b0bf904287a9749e8eabea919b5e9dd8a9" + "sha1": "336a9b31ff385728d00eb7ef173e4d054584b787" }, "path_in_vcs": "" } \ No newline at end of file diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4d33593..e5c2395 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -8,6 +8,7 @@ on: pull_request: env: + CARGO_INCREMENTAL: 0 RUST_TEST_THREADS: 1 jobs: @@ -18,7 +19,7 @@ jobs: os: [ubuntu, macos, windows] channel: [1.49.0, stable, beta, nightly] feature: [arc_lock, serde, deadlock_detection] - exclude: + exclude: - feature: deadlock_detection channel: '1.49.0' include: @@ -41,7 +42,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - target: + target: - wasm32-unknown-unknown - x86_64-fortanix-unknown-sgx #- x86_64-unknown-redox diff --git a/Android.bp b/Android.bp index 37f9ad1..2c6d8bf 100644 --- a/Android.bp +++ b/Android.bp @@ -42,7 +42,7 @@ rust_library { host_supported: true, crate_name: "parking_lot", cargo_env_compat: true, - cargo_pkg_version: "0.12.0", + cargo_pkg_version: "0.12.1", srcs: ["src/lib.rs"], edition: "2018", features: ["default"], diff --git a/CHANGELOG.md b/CHANGELOG.md index d1951e9..8421b84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## parking_lot 0.12.1 (2022-05-31) + +- Fixed incorrect memory ordering in `RwLock`. (#344) +- Added `Condvar::wait_while` convenience methods (#343) + +## parking_lot_core 0.9.3 (2022-04-30) + +- Bump windows-sys dependency to 0.36. (#339) + +## parking_lot_core 0.9.2, lock_api 0.4.7 (2022-03-25) + +- Enable const new() on lock types on stable. (#325) +- Added `MutexGuard::leak` function. (#333) +- Bump windows-sys dependency to 0.34. (#331) +- Bump petgraph dependency to 0.6. (#326) +- Don't use pthread attributes on the espidf platform. (#319) + +## parking_lot_core 0.9.1 (2022-02-06) + +- Bump windows-sys dependency to 0.32. (#316) + ## parking_lot 0.12.0, parking_lot_core 0.9.0, lock_api 0.4.6 (2022-01-28) - The MSRV is bumped to 1.49.0. diff --git a/Cargo.toml b/Cargo.toml index 6f58afa..e474f48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,19 +12,27 @@ [package] edition = "2018" name = "parking_lot" -version = "0.12.0" +version = "0.12.1" authors = ["Amanieu d'Antras "] description = "More compact and efficient implementations of the standard synchronization primitives." readme = "README.md" -keywords = ["mutex", "condvar", "rwlock", "once", "thread"] +keywords = [ + "mutex", + "condvar", + "rwlock", + "once", + "thread", +] categories = ["concurrency"] -license = "Apache-2.0/MIT" +license = "MIT OR Apache-2.0" repository = "https://github.com/Amanieu/parking_lot" + [dependencies.lock_api] version = "0.4.6" [dependencies.parking_lot_core] version = "0.9.0" + [dev-dependencies.bincode] version = "1.3.3" @@ -36,7 +44,10 @@ arc_lock = ["lock_api/arc_lock"] deadlock_detection = ["parking_lot_core/deadlock_detection"] default = [] hardware-lock-elision = [] -nightly = ["parking_lot_core/nightly", "lock_api/nightly"] +nightly = [ + "parking_lot_core/nightly", + "lock_api/nightly", +] owning_ref = ["lock_api/owning_ref"] send_guard = [] serde = ["lock_api/serde"] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index bb501be..90b653d 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,9 +1,9 @@ [package] name = "parking_lot" -version = "0.12.0" +version = "0.12.1" authors = ["Amanieu d'Antras "] description = "More compact and efficient implementations of the standard synchronization primitives." -license = "Apache-2.0/MIT" +license = "MIT OR Apache-2.0" repository = "https://github.com/Amanieu/parking_lot" readme = "README.md" keywords = ["mutex", "condvar", "rwlock", "once", "thread"] diff --git a/METADATA b/METADATA index 10f98ed..0cb5945 100644 --- a/METADATA +++ b/METADATA @@ -1,3 +1,7 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/parking_lot +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + name: "parking_lot" description: "More compact and efficient implementations of the standard synchronization primitives." third_party { @@ -7,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/parking_lot/parking_lot-0.12.0.crate" + value: "https://static.crates.io/crates/parking_lot/parking_lot-0.12.1.crate" } - version: "0.12.0" + version: "0.12.1" license_type: NOTICE last_upgrade_date { year: 2022 - month: 3 - day: 1 + month: 12 + day: 13 } } diff --git a/README.md b/README.md index 5bda8d8..70fdca7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ parking_lot ============ -![Rust](https://github.com/Amanieu/parking_lot/workflows/Rust/badge.svg) +[![Rust](https://github.com/Amanieu/parking_lot/workflows/Rust/badge.svg)](https://github.com/Amanieu/parking_lot/actions) [![Crates.io](https://img.shields.io/crates/v/parking_lot.svg)](https://crates.io/crates/parking_lot) [Documentation (synchronization primitives)](https://docs.rs/parking_lot/) @@ -83,7 +83,7 @@ functionality is offloaded to the *parking lot*. The idea behind this is based on the Webkit [`WTF::ParkingLot`](https://webkit.org/blog/6161/locking-in-webkit/) class, which essentially consists of a hash table mapping of lock addresses to queues of parked (sleeping) threads. The Webkit parking lot was itself -inspired by Linux [futexes](http://man7.org/linux/man-pages/man2/futex.2.html), +inspired by Linux [futexes](https://man7.org/linux/man-pages/man2/futex.2.html), but it is more powerful since it allows invoking callbacks while holding a queue lock. @@ -91,11 +91,13 @@ lock. There are a few restrictions when using this library on stable Rust: -- You will have to use the `const_*` functions (e.g. `const_mutex(val)`) to - statically initialize the locking primitives. Using e.g. `Mutex::new(val)` - does not work on stable Rust yet. -- The `wasm32-unknown-unknown` target is only supported on nightly and requires - `-C target-feature=+atomics` in `RUSTFLAGS`. +- The `wasm32-unknown-unknown` target is only fully supported on nightly with + `-C target-feature=+atomics` in `RUSTFLAGS` and `-Z build-std` passed to cargo. + parking_lot will work mostly fine on stable, the only difference is it will + panic instead of block forever if you hit a deadlock. + Just make sure not to enable `-C target-feature=+atomics` on stable as that + will allow wasm to run with multiple threads which will completely break + parking_lot's concurrency guarantees. To enable nightly-only functionality, you need to enable the `nightly` feature in Cargo (see below). @@ -106,14 +108,14 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -parking_lot = "0.11" +parking_lot = "0.12" ``` To enable nightly-only features, add this to your `Cargo.toml` instead: ```toml [dependencies] -parking_lot = { version = "0.11", features = ["nightly"] } +parking_lot = { version = "0.12", features = ["nightly"] } ``` The experimental deadlock detector can be enabled with the @@ -142,8 +144,8 @@ considered a breaking change and will require a major version bump. Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT) at your option. diff --git a/src/condvar.rs b/src/condvar.rs index 9eaf300..15daa69 100644 --- a/src/condvar.rs +++ b/src/condvar.rs @@ -14,6 +14,7 @@ use core::{ }; use lock_api::RawMutex as RawMutex_; use parking_lot_core::{self, ParkResult, RequeueOp, UnparkResult, DEFAULT_PARK_TOKEN}; +use std::ops::DerefMut; use std::time::{Duration, Instant}; /// A type indicating whether a timed wait on a condition variable returned @@ -53,7 +54,7 @@ impl WaitTimeoutResult { /// woken up. /// - Only requires 1 word of space, whereas the standard library boxes the /// `Condvar` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). +/// - Can be statically constructed. /// - Does not require any drop glue when dropped. /// - Inline fast path for the uncontended case. /// @@ -136,10 +137,9 @@ impl Condvar { #[cold] fn notify_one_slow(&self, mutex: *mut RawMutex) -> bool { - unsafe { - // Unpark one thread and requeue the rest onto the mutex - let from = self as *const _ as usize; - let to = mutex as usize; + // Unpark one thread and requeue the rest onto the mutex + let from = self as *const _ as usize; + let to = mutex as usize; let validate = || { // Make sure that our atomic state still points to the same // mutex. If not then it means that all threads on the current @@ -156,7 +156,7 @@ impl Condvar { // locking the queue. There is the possibility of a race if the // mutex gets locked after we check, but that doesn't matter in // this case. - if (*mutex).mark_parked_if_locked() { + if unsafe { (*mutex).mark_parked_if_locked() } { RequeueOp::RequeueOne } else { RequeueOp::UnparkOne @@ -169,10 +169,9 @@ impl Condvar { } TOKEN_NORMAL }; - let res = parking_lot_core::unpark_requeue(from, to, validate, callback); + let res = unsafe { parking_lot_core::unpark_requeue(from, to, validate, callback) }; res.unparked_threads + res.requeued_threads != 0 - } } /// Wakes up all blocked threads on this condvar. @@ -197,7 +196,6 @@ impl Condvar { #[cold] fn notify_all_slow(&self, mutex: *mut RawMutex) -> usize { - unsafe { // Unpark one thread and requeue the rest onto the mutex let from = self as *const _ as usize; let to = mutex as usize; @@ -221,7 +219,7 @@ impl Condvar { // locking the queue. There is the possibility of a race if the // mutex gets locked after we check, but that doesn't matter in // this case. - if (*mutex).mark_parked_if_locked() { + if unsafe { (*mutex).mark_parked_if_locked() } { RequeueOp::RequeueAll } else { RequeueOp::UnparkOneRequeueRest @@ -231,14 +229,13 @@ impl Condvar { // If we requeued threads to the mutex, mark it as having // parked threads. The RequeueAll case is already handled above. if op == RequeueOp::UnparkOneRequeueRest && result.requeued_threads != 0 { - (*mutex).mark_parked(); + unsafe { (*mutex).mark_parked() }; } TOKEN_NORMAL }; - let res = parking_lot_core::unpark_requeue(from, to, validate, callback); + let res = unsafe { parking_lot_core::unpark_requeue(from, to, validate, callback) }; res.unparked_threads + res.requeued_threads - } } /// Blocks the current thread until this condition variable receives a @@ -297,7 +294,6 @@ impl Condvar { // This is a non-generic function to reduce the monomorphization cost of // using `wait_until`. fn wait_until_internal(&self, mutex: &RawMutex, timeout: Option) -> WaitTimeoutResult { - unsafe { let result; let mut bad_mutex = false; let mut requeued = false; @@ -319,7 +315,7 @@ impl Condvar { }; let before_sleep = || { // Unlock the mutex before sleeping... - mutex.unlock(); + unsafe { mutex.unlock() }; }; let timed_out = |k, was_last_thread| { // If we were requeued to a mutex, then we did not time out. @@ -334,14 +330,14 @@ impl Condvar { self.state.store(ptr::null_mut(), Ordering::Relaxed); } }; - result = parking_lot_core::park( + result = unsafe { parking_lot_core::park( addr, validate, before_sleep, timed_out, DEFAULT_PARK_TOKEN, timeout, - ); + ) }; } // Panic if we tried to use multiple mutexes with a Condvar. Note @@ -353,13 +349,12 @@ impl Condvar { // ... and re-lock it once we are done sleeping if result == ParkResult::Unparked(TOKEN_HANDOFF) { - deadlock::acquire_resource(mutex as *const _ as usize); + unsafe { deadlock::acquire_resource(mutex as *const _ as usize) }; } else { mutex.lock(); } WaitTimeoutResult(!(result.is_unparked() || requeued)) - } } /// Waits on this condition variable for a notification, timing out after a @@ -389,6 +384,127 @@ impl Condvar { let deadline = util::to_deadline(timeout); self.wait_until_internal(unsafe { MutexGuard::mutex(mutex_guard).raw() }, deadline) } + + #[inline] + fn wait_while_until_internal( + &self, + mutex_guard: &mut MutexGuard<'_, T>, + mut condition: F, + timeout: Option, + ) -> WaitTimeoutResult + where + T: ?Sized, + F: FnMut(&mut T) -> bool, + { + let mut result = WaitTimeoutResult(false); + + while !result.timed_out() && condition(mutex_guard.deref_mut()) { + result = + self.wait_until_internal(unsafe { MutexGuard::mutex(mutex_guard).raw() }, timeout); + } + + result + } + /// Blocks the current thread until this condition variable receives a + /// notification. If the provided condition evaluates to `false`, then the + /// thread is no longer blocked and the operation is completed. If the + /// condition evaluates to `true`, then the thread is blocked again and + /// waits for another notification before repeating this process. + /// + /// This function will atomically unlock the mutex specified (represented by + /// `mutex_guard`) and block the current thread. This means that any calls + /// to `notify_*()` which happen logically after the mutex is unlocked are + /// candidates to wake this thread up. When this function call returns, the + /// lock specified will have been re-acquired. + /// + /// # Panics + /// + /// This function will panic if another thread is waiting on the `Condvar` + /// with a different `Mutex` object. + #[inline] + pub fn wait_while(&self, mutex_guard: &mut MutexGuard<'_, T>, condition: F) + where + T: ?Sized, + F: FnMut(&mut T) -> bool, + { + self.wait_while_until_internal(mutex_guard, condition, None); + } + + /// Waits on this condition variable for a notification, timing out after + /// the specified time instant. If the provided condition evaluates to + /// `false`, then the thread is no longer blocked and the operation is + /// completed. If the condition evaluates to `true`, then the thread is + /// blocked again and waits for another notification before repeating + /// this process. + /// + /// The semantics of this function are equivalent to `wait()` except that + /// the thread will be blocked roughly until `timeout` is reached. This + /// method should not be used for precise timing due to anomalies such as + /// preemption or platform differences that may not cause the maximum + /// amount of time waited to be precisely `timeout`. + /// + /// Note that the best effort is made to ensure that the time waited is + /// measured with a monotonic clock, and not affected by the changes made to + /// the system time. + /// + /// The returned `WaitTimeoutResult` value indicates if the timeout is + /// known to have elapsed. + /// + /// Like `wait`, the lock specified will be re-acquired when this function + /// returns, regardless of whether the timeout elapsed or not. + /// + /// # Panics + /// + /// This function will panic if another thread is waiting on the `Condvar` + /// with a different `Mutex` object. + #[inline] + pub fn wait_while_until( + &self, + mutex_guard: &mut MutexGuard<'_, T>, + condition: F, + timeout: Instant, + ) -> WaitTimeoutResult + where + T: ?Sized, + F: FnMut(&mut T) -> bool, + { + self.wait_while_until_internal(mutex_guard, condition, Some(timeout)) + } + + /// Waits on this condition variable for a notification, timing out after a + /// specified duration. If the provided condition evaluates to `false`, + /// then the thread is no longer blocked and the operation is completed. + /// If the condition evaluates to `true`, then the thread is blocked again + /// and waits for another notification before repeating this process. + /// + /// The semantics of this function are equivalent to `wait()` except that + /// the thread will be blocked for roughly no longer than `timeout`. This + /// method should not be used for precise timing due to anomalies such as + /// preemption or platform differences that may not cause the maximum + /// amount of time waited to be precisely `timeout`. + /// + /// Note that the best effort is made to ensure that the time waited is + /// measured with a monotonic clock, and not affected by the changes made to + /// the system time. + /// + /// The returned `WaitTimeoutResult` value indicates if the timeout is + /// known to have elapsed. + /// + /// Like `wait`, the lock specified will be re-acquired when this function + /// returns, regardless of whether the timeout elapsed or not. + #[inline] + pub fn wait_while_for( + &self, + mutex_guard: &mut MutexGuard<'_, T>, + condition: F, + timeout: Duration, + ) -> WaitTimeoutResult + where + F: FnMut(&mut T) -> bool, + { + let deadline = util::to_deadline(timeout); + self.wait_while_until_internal(mutex_guard, condition, deadline) + } } impl Default for Condvar { @@ -410,6 +526,8 @@ mod tests { use std::sync::mpsc::channel; use std::sync::Arc; use std::thread; + use std::thread::sleep; + use std::thread::JoinHandle; use std::time::Duration; use std::time::Instant; @@ -578,6 +696,116 @@ mod tests { drop(g); } + fn spawn_wait_while_notifier( + mutex: Arc>, + cv: Arc, + num_iters: u32, + timeout: Option, + ) -> JoinHandle<()> { + thread::spawn(move || { + for epoch in 1..=num_iters { + // spin to wait for main test thread to block + // before notifying it to wake back up and check + // its condition. + let mut sleep_backoff = Duration::from_millis(1); + let _mutex_guard = loop { + let mutex_guard = mutex.lock(); + + if let Some(timeout) = timeout { + if Instant::now() >= timeout { + return; + } + } + + if *mutex_guard == epoch { + break mutex_guard; + } + + drop(mutex_guard); + + // give main test thread a good chance to + // acquire the lock before this thread does. + sleep(sleep_backoff); + sleep_backoff *= 2; + }; + + cv.notify_one(); + } + }) + } + + #[test] + fn wait_while_until_internal_does_not_wait_if_initially_false() { + let mutex = Arc::new(Mutex::new(0)); + let cv = Arc::new(Condvar::new()); + + let condition = |counter: &mut u32| { + *counter += 1; + false + }; + + let mut mutex_guard = mutex.lock(); + let timeout_result = cv + .wait_while_until_internal(&mut mutex_guard, condition, None); + + assert!(!timeout_result.timed_out()); + assert!(*mutex_guard == 1); + } + + #[test] + fn wait_while_until_internal_times_out_before_false() { + let mutex = Arc::new(Mutex::new(0)); + let cv = Arc::new(Condvar::new()); + + let num_iters = 3; + let condition = |counter: &mut u32| { + *counter += 1; + true + }; + + let mut mutex_guard = mutex.lock(); + let timeout = Some(Instant::now() + Duration::from_millis(500)); + let handle = spawn_wait_while_notifier(mutex.clone(), cv.clone(), num_iters, timeout); + + let timeout_result = + cv.wait_while_until_internal(&mut mutex_guard, condition, timeout); + + assert!(timeout_result.timed_out()); + assert!(*mutex_guard == num_iters + 1); + + // prevent deadlock with notifier + drop(mutex_guard); + handle.join().unwrap(); + } + + #[test] + fn wait_while_until_internal() { + let mutex = Arc::new(Mutex::new(0)); + let cv = Arc::new(Condvar::new()); + + let num_iters = 4; + + let condition = |counter: &mut u32| { + *counter += 1; + *counter <= num_iters + }; + + let mut mutex_guard = mutex.lock(); + let handle = spawn_wait_while_notifier(mutex.clone(), cv.clone(), num_iters, None); + + let timeout_result = + cv.wait_while_until_internal(&mut mutex_guard, condition, None); + + assert!(!timeout_result.timed_out()); + assert!(*mutex_guard == num_iters + 1); + + let timeout_result = cv.wait_while_until_internal(&mut mutex_guard, condition, None); + handle.join().unwrap(); + + assert!(!timeout_result.timed_out()); + assert!(*mutex_guard == num_iters + 2); + } + #[test] #[should_panic] fn two_mutexes() { diff --git a/src/fair_mutex.rs b/src/fair_mutex.rs index 3e4c163..d7d7a77 100644 --- a/src/fair_mutex.rs +++ b/src/fair_mutex.rs @@ -35,7 +35,7 @@ use lock_api; /// - No poisoning, the lock is released normally on panic. /// - Only requires 1 byte of space, whereas the standard library boxes the /// `FairMutex` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). +/// - Can be statically constructed. /// - Does not require any drop glue when dropped. /// - Inline fast path for the uncontended case. /// - Efficient handling of micro-contention using adaptive spinning. diff --git a/src/mutex.rs b/src/mutex.rs index 71bc351..f3f8aa9 100644 --- a/src/mutex.rs +++ b/src/mutex.rs @@ -42,7 +42,7 @@ use lock_api; /// - No poisoning, the lock is released normally on panic. /// - Only requires 1 byte of space, whereas the standard library boxes the /// `Mutex` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). +/// - Can be statically constructed. /// - Does not require any drop glue when dropped. /// - Inline fast path for the uncontended case. /// - Efficient handling of micro-contention using adaptive spinning. diff --git a/src/once.rs b/src/once.rs index f458c9c..6b91ac4 100644 --- a/src/once.rs +++ b/src/once.rs @@ -258,11 +258,11 @@ impl Once { // Park our thread until we are woken up by the thread that owns the // lock. + let addr = self as *const _ as usize; + let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT; + let before_sleep = || {}; + let timed_out = |_, _| unreachable!(); unsafe { - let addr = self as *const _ as usize; - let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT; - let before_sleep = || {}; - let timed_out = |_, _| unreachable!(); parking_lot_core::park( addr, validate, @@ -285,8 +285,8 @@ impl Once { let once = self.0; let state = once.0.swap(POISON_BIT, Ordering::Release); if state & PARKED_BIT != 0 { + let addr = once as *const _ as usize; unsafe { - let addr = once as *const _ as usize; parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN); } } @@ -307,8 +307,8 @@ impl Once { // Now unlock the state, set the done bit and unpark all threads let state = self.0.swap(DONE_BIT, Ordering::Release); if state & PARKED_BIT != 0 { + let addr = self as *const _ as usize; unsafe { - let addr = self as *const _ as usize; parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN); } } diff --git a/src/raw_rwlock.rs b/src/raw_rwlock.rs index 21d338b..6d1fef9 100644 --- a/src/raw_rwlock.rs +++ b/src/raw_rwlock.rs @@ -988,8 +988,8 @@ impl RawRwLock { if let Err(x) = self.state.compare_exchange_weak( state, state | WRITER_PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, + Ordering::Acquire, + Ordering::Acquire, ) { state = x; continue; diff --git a/src/rwlock.rs b/src/rwlock.rs index 512114c..4167a85 100644 --- a/src/rwlock.rs +++ b/src/rwlock.rs @@ -55,7 +55,7 @@ use lock_api; /// - No poisoning, the lock is released normally on panic. /// - Only requires 1 word of space, whereas the standard library boxes the /// `RwLock` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). +/// - Can be statically constructed. /// - Does not require any drop glue when dropped. /// - Inline fast path for the uncontended case. /// - Efficient handling of micro-contention using adaptive spinning. -- cgit v1.2.3