diff options
-rw-r--r-- | .cargo_vcs_info.json | 7 | ||||
-rw-r--r-- | .github/workflows/rust.yml | 19 | ||||
-rw-r--r-- | Android.bp | 22 | ||||
-rw-r--r-- | CHANGELOG.md | 38 | ||||
-rw-r--r-- | Cargo.toml | 26 | ||||
-rw-r--r-- | Cargo.toml.orig | 15 | ||||
-rw-r--r-- | METADATA | 10 | ||||
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | TEST_MAPPING | 8 | ||||
-rw-r--r-- | cargo2android.json | 10 | ||||
-rw-r--r-- | src/condvar.rs | 20 | ||||
-rw-r--r-- | src/elision.rs | 86 | ||||
-rw-r--r-- | src/fair_mutex.rs | 19 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/mutex.rs | 2 | ||||
-rw-r--r-- | src/raw_mutex.rs | 2 | ||||
-rw-r--r-- | src/raw_rwlock.rs | 13 | ||||
-rw-r--r-- | src/rwlock.rs | 24 | ||||
-rw-r--r-- | src/util.rs | 3 |
19 files changed, 198 insertions, 136 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index e1a0b04..38c6551 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "86969fd7baf94312520e0b5a5f3b0861a0fd411b" - } -} + "sha1": "a75875b0bf904287a9749e8eabea919b5e9dd8a9" + }, + "path_in_vcs": "" +}
\ No newline at end of file diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d613089..4d33593 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,11 +2,11 @@ name: Rust on: push: - branches-ignore: - - trying.tmp - - staging.tmp + branches: + - trying + - staging pull_request: - + env: RUST_TEST_THREADS: 1 @@ -16,15 +16,18 @@ jobs: strategy: matrix: os: [ubuntu, macos, windows] - channel: [1.36.0, stable, beta, nightly] - feature: [serde, deadlock_detection] + channel: [1.49.0, stable, beta, nightly] + feature: [arc_lock, serde, deadlock_detection] exclude: - feature: deadlock_detection - channel: '1.36.0' + channel: '1.49.0' include: - channel: nightly feature: nightly os: ubuntu + - channel: nightly + feature: hardware-lock-elision + os: ubuntu steps: - uses: actions/checkout@v2 @@ -53,7 +56,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: rustup default nightly - - run: cargo doc --workspace --features serde,deadlock_detection --no-deps -p parking_lot -p parking_lot_core -p lock_api + - run: cargo doc --workspace --features arc_lock,serde,deadlock_detection --no-deps -p parking_lot -p parking_lot_core -p lock_api benchmark: runs-on: ubuntu-latest steps: @@ -1,4 +1,5 @@ -// This file is generated by cargo2android.py --run --device --dependencies. +// This file is generated by cargo2android.py --config cargo2android.json. +// Do not modify this file as changes will be overridden on upgrade. package { default_applicable_licenses: ["external_rust_crates_parking_lot_license"], @@ -40,22 +41,19 @@ rust_library { name: "libparking_lot", host_supported: true, crate_name: "parking_lot", + cargo_env_compat: true, + cargo_pkg_version: "0.12.0", srcs: ["src/lib.rs"], edition: "2018", features: ["default"], rustlibs: [ - "libinstant", "liblock_api", "libparking_lot_core", ], + apex_available: [ + "//apex_available:platform", + "com.android.bluetooth", + "com.android.virt", + ], + min_sdk_version: "29", } - -// dependent_library ["feature_list"] -// cfg-if-0.1.10 -// cfg-if-1.0.0 -// instant-0.1.8 -// libc-0.2.80 "default,std" -// lock_api-0.4.2 -// parking_lot_core-0.8.0 -// scopeguard-1.1.0 -// smallvec-1.5.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index a473463..d1951e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,41 @@ +## 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. +- Disabled eventual fairness on wasm32-unknown-unknown. (#302) +- Added a rwlock method to report if lock is held exclusively. (#303) +- Use new `asm!` macro. (#304) +- Use windows-rs instead of winapi for faster builds. (#311) +- Moved hardware lock elision support to a separate Cargo feature. (#313) +- Removed used of deprecated `spin_loop_hint`. (#314) + +## parking_lot 0.11.2, parking_lot_core 0.8.4, lock_api 0.4.5 (2021-08-28) + +- Fixed incorrect memory orderings on `RwLock` and `WordLock`. (#294, #292) +- Added `Arc`-based lock guards. (#291) +- Added workaround for TSan's lack of support for `fence`. (#292) + +## lock_api 0.4.4 (2021-05-01) + +- Update for latest nightly. (#281) + +## lock_api 0.4.3 (2021-04-03) + +- Added `[Raw]ReentrantMutex::is_owned`. (#280) + +## parking_lot_core 0.8.3 (2021-02-12) + +- Updated smallvec to 1.6. (#276) + +## parking_lot_core 0.8.2 (2020-12-21) + +- Fixed assertion failure on OpenBSD. (#270) + +## parking_lot_core 0.8.1 (2020-12-04) + +- Removed deprecated CloudABI support. (#263) +- Fixed build on wasm32-unknown-unknown. (#265) +- Relaxed dependency on `smallvec`. (#266) + ## parking_lot 0.11.1, lock_api 0.4.2 (2020-11-18) - Fix bounds on Send and Sync impls for lock guards. (#262) @@ -3,17 +3,16 @@ # 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 +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# 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] edition = "2018" name = "parking_lot" -version = "0.11.1" +version = "0.12.0" authors = ["Amanieu d'Antras <amanieu@gmail.com>"] description = "More compact and efficient implementations of the standard synchronization primitives." readme = "README.md" @@ -21,26 +20,23 @@ keywords = ["mutex", "condvar", "rwlock", "once", "thread"] categories = ["concurrency"] license = "Apache-2.0/MIT" repository = "https://github.com/Amanieu/parking_lot" -[dependencies.instant] -version = "0.1.4" - [dependencies.lock_api] -version = "0.4.0" +version = "0.4.6" [dependencies.parking_lot_core] -version = "0.8.0" +version = "0.9.0" [dev-dependencies.bincode] -version = "1.3.0" +version = "1.3.3" [dev-dependencies.rand] -version = "0.7.3" +version = "0.8.3" [features] +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"] owning_ref = ["lock_api/owning_ref"] send_guard = [] serde = ["lock_api/serde"] -stdweb = ["instant/stdweb"] -wasm-bindgen = ["instant/wasm-bindgen"] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 67a2555..bb501be 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "parking_lot" -version = "0.11.1" +version = "0.12.0" authors = ["Amanieu d'Antras <amanieu@gmail.com>"] description = "More compact and efficient implementations of the standard synchronization primitives." license = "Apache-2.0/MIT" @@ -11,25 +11,24 @@ categories = ["concurrency"] edition = "2018" [dependencies] -parking_lot_core = { path = "core", version = "0.8.0" } -lock_api = { path = "lock_api", version = "0.4.0" } -instant = "0.1.4" +parking_lot_core = { path = "core", version = "0.9.0" } +lock_api = { path = "lock_api", version = "0.4.6" } [dev-dependencies] -rand = "0.7.3" +rand = "0.8.3" # Used when testing out serde support. -bincode = "1.3.0" +bincode = "1.3.3" [features] default = [] +arc_lock = ["lock_api/arc_lock"] owning_ref = ["lock_api/owning_ref"] nightly = ["parking_lot_core/nightly", "lock_api/nightly"] deadlock_detection = ["parking_lot_core/deadlock_detection"] serde = ["lock_api/serde"] -stdweb = ["instant/stdweb"] -wasm-bindgen = ["instant/wasm-bindgen"] send_guard = [] +hardware-lock-elision = [] [workspace] exclude = ["benchmark"] @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/parking_lot/parking_lot-0.11.1.crate" + value: "https://static.crates.io/crates/parking_lot/parking_lot-0.12.0.crate" } - version: "0.11.1" + version: "0.12.0" license_type: NOTICE last_upgrade_date { - year: 2020 - month: 11 - day: 17 + year: 2022 + month: 3 + day: 1 } } @@ -50,6 +50,7 @@ in the Rust standard library: library versions of those types. 7. `RwLock` takes advantage of hardware lock elision on processors that support it, which can lead to huge performance wins with many readers. + This must be enabled with the `hardware-lock-elision` feature. 8. `RwLock` uses a task-fair locking policy, which avoids reader and writer starvation, whereas the standard library version makes no guarantees. 9. `Condvar` is guaranteed not to produce spurious wakeups. A thread will @@ -93,8 +94,6 @@ 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. -- `RwLock` will not be able to take advantage of hardware lock elision for - readers, which improves performance when there are multiple readers. - The `wasm32-unknown-unknown` target is only supported on nightly and requires `-C target-feature=+atomics` in `RUSTFLAGS`. @@ -126,13 +125,17 @@ To allow sending `MutexGuard`s and `RwLock*Guard`s to other threads, enable the Note that the `deadlock_detection` and `send_guard` features are incompatible and cannot be used together. +Hardware lock elision support for x86 can be enabled with the +`hardware-lock-elision` feature. This requires Rust 1.59 due to the use of +inline assembly. + The core parking lot API is provided by the `parking_lot_core` crate. It is separate from the synchronization primitives in the `parking_lot` crate so that changes to the core API do not cause breaking changes for users of `parking_lot`. ## Minimum Rust version -The current minimum required Rust version is 1.36. Any change to this is +The current minimum required Rust version is 1.49. Any change to this is considered a breaking change and will require a major version bump. ## License diff --git a/TEST_MAPPING b/TEST_MAPPING new file mode 100644 index 0000000..f439cf8 --- /dev/null +++ b/TEST_MAPPING @@ -0,0 +1,8 @@ +// Generated by update_crate_tests.py for tests that depend on this crate. +{ + "imports": [ + { + "path": "external/rust/crates/vulkano" + } + ] +} diff --git a/cargo2android.json b/cargo2android.json new file mode 100644 index 0000000..e48e3b8 --- /dev/null +++ b/cargo2android.json @@ -0,0 +1,10 @@ +{ + "apex-available": [ + "//apex_available:platform", + "com.android.bluetooth", + "com.android.virt" + ], + "device": true, + "min-sdk-version": "29", + "run": true +} diff --git a/src/condvar.rs b/src/condvar.rs index 534b8af..9eaf300 100644 --- a/src/condvar.rs +++ b/src/condvar.rs @@ -12,10 +12,9 @@ use core::{ fmt, ptr, sync::atomic::{AtomicPtr, Ordering}, }; -use instant::Instant; use lock_api::RawMutex as RawMutex_; use parking_lot_core::{self, ParkResult, RequeueOp, UnparkResult, DEFAULT_PARK_TOKEN}; -use std::time::Duration; +use std::time::{Duration, Instant}; /// A type indicating whether a timed wait on a condition variable returned /// due to a time out or not. @@ -381,12 +380,6 @@ impl Condvar { /// /// Like `wait`, the lock specified will be re-acquired when this function /// returns, regardless of whether the timeout elapsed or not. - /// - /// # Panics - /// - /// Panics if the given `timeout` is so large that it can't be added to the current time. - /// This panic is not possible if the crate is built with the `nightly` feature, then a too - /// large `timeout` becomes equivalent to just calling `wait`. #[inline] pub fn wait_for<T: ?Sized>( &self, @@ -414,11 +407,11 @@ impl fmt::Debug for Condvar { #[cfg(test)] mod tests { use crate::{Condvar, Mutex, MutexGuard}; - use instant::Instant; use std::sync::mpsc::channel; use std::sync::Arc; use std::thread; use std::time::Duration; + use std::time::Instant; #[test] fn smoke() { @@ -557,14 +550,7 @@ mod tests { let _g = m2.lock(); c2.notify_one(); }); - // Non-nightly panics on too large timeouts. Nightly treats it as indefinite wait. - let very_long_timeout = if cfg!(feature = "nightly") { - Duration::from_secs(u64::max_value()) - } else { - Duration::from_millis(u32::max_value() as u64) - }; - - let timeout_res = c.wait_for(&mut g, very_long_timeout); + let timeout_res = c.wait_for(&mut g, Duration::from_secs(u64::max_value())); assert!(!timeout_res.timed_out()); drop(g); diff --git a/src/elision.rs b/src/elision.rs index 68cfa63..8fa229e 100644 --- a/src/elision.rs +++ b/src/elision.rs @@ -5,6 +5,8 @@ // http://opensource.org/licenses/MIT>, at your option. This file may not be // copied, modified, or distributed except according to those terms. +#[cfg(all(feature = "hardware-lock-elision", any(target_arch = "x86", target_arch = "x86_64")))] +use std::arch::asm; use std::sync::atomic::AtomicUsize; // Extension trait to add lock elision primitives to atomic types @@ -26,14 +28,14 @@ pub trait AtomicElisionExt { #[inline] pub fn have_elision() -> bool { cfg!(all( - feature = "nightly", + feature = "hardware-lock-elision", any(target_arch = "x86", target_arch = "x86_64"), )) } // This implementation is never actually called because it is guarded by // have_elision(). -#[cfg(not(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64"))))] +#[cfg(not(all(feature = "hardware-lock-elision", any(target_arch = "x86", target_arch = "x86_64"))))] impl AtomicElisionExt for AtomicUsize { type IntType = usize; @@ -48,37 +50,33 @@ impl AtomicElisionExt for AtomicUsize { } } -#[cfg(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64")))] +#[cfg(all(feature = "hardware-lock-elision", any(target_arch = "x86", target_arch = "x86_64")))] impl AtomicElisionExt for AtomicUsize { type IntType = usize; - #[cfg(target_pointer_width = "32")] #[inline] fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result<usize, usize> { unsafe { + use core::arch::asm; let prev: usize; - llvm_asm!("xacquire; lock; cmpxchgl $2, $1" - : "={eax}" (prev), "+*m" (self) - : "r" (new), "{eax}" (current) - : "memory" - : "volatile"); - if prev == current { - Ok(prev) - } else { - Err(prev) - } - } - } - #[cfg(target_pointer_width = "64")] - #[inline] - fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result<usize, usize> { - unsafe { - let prev: usize; - llvm_asm!("xacquire; lock; cmpxchgq $2, $1" - : "={rax}" (prev), "+*m" (self) - : "r" (new), "{rax}" (current) - : "memory" - : "volatile"); + #[cfg(target_pointer_width = "32")] + asm!( + "xacquire", + "lock", + "cmpxchg [{:e}], {:e}", + in(reg) self, + in(reg) new, + inout("eax") current => prev, + ); + #[cfg(target_pointer_width = "64")] + asm!( + "xacquire", + "lock", + "cmpxchg [{}], {}", + in(reg) self, + in(reg) new, + inout("rax") current => prev, + ); if prev == current { Ok(prev) } else { @@ -87,29 +85,27 @@ impl AtomicElisionExt for AtomicUsize { } } - #[cfg(target_pointer_width = "32")] - #[inline] - fn elision_fetch_sub_release(&self, val: usize) -> usize { - unsafe { - let prev: usize; - llvm_asm!("xrelease; lock; xaddl $2, $1" - : "=r" (prev), "+*m" (self) - : "0" (val.wrapping_neg()) - : "memory" - : "volatile"); - prev - } - } - #[cfg(target_pointer_width = "64")] #[inline] fn elision_fetch_sub_release(&self, val: usize) -> usize { unsafe { + use core::arch::asm; let prev: usize; - llvm_asm!("xrelease; lock; xaddq $2, $1" - : "=r" (prev), "+*m" (self) - : "0" (val.wrapping_neg()) - : "memory" - : "volatile"); + #[cfg(target_pointer_width = "32")] + asm!( + "xrelease", + "lock", + "xadd [{:e}], {:e}", + in(reg) self, + inout(reg) val.wrapping_neg() => prev, + ); + #[cfg(target_pointer_width = "64")] + asm!( + "xrelease", + "lock", + "xadd [{}], {}", + in(reg) self, + inout(reg) val.wrapping_neg() => prev, + ); prev } } diff --git a/src/fair_mutex.rs b/src/fair_mutex.rs index 449c53b..3e4c163 100644 --- a/src/fair_mutex.rs +++ b/src/fair_mutex.rs @@ -11,24 +11,21 @@ use lock_api; /// A mutual exclusive primitive that is always fair, useful for protecting shared data /// /// This mutex will block threads waiting for the lock to become available. The -/// mutex can also be statically initialized or created via a `new` +/// mutex can be statically initialized or created by the `new` /// constructor. Each mutex has a type parameter which represents the data that /// it is protecting. The data can only be accessed through the RAII guards /// returned from `lock` and `try_lock`, which guarantees that the data is only /// ever accessed when the mutex is locked. /// -/// The regular mutex provided by `parking_lot` uses eventual locking fairness +/// The regular mutex provided by `parking_lot` uses eventual fairness /// (after some time it will default to the fair algorithm), but eventual -/// fairness does not provide the same garantees a always fair method would. -/// Fair mutexes are generally slower, but sometimes needed. This wrapper was -/// created to avoid using a unfair protocol when it's forbidden by mistake. +/// fairness does not provide the same guarantees an always fair method would. +/// Fair mutexes are generally slower, but sometimes needed. /// -/// In a fair mutex the lock is provided to whichever thread asked first, -/// they form a queue and always follow the first-in first-out order. This -/// means some thread in the queue won't be able to steal the lock and use it fast -/// to increase throughput, at the cost of latency. Since the response time will grow -/// for some threads that are waiting for the lock and losing to faster but later ones, -/// but it may make sending more responses possible. +/// In a fair mutex the waiters form a queue, and the lock is always granted to +/// the next requester in the queue, in first-in first-out order. This ensures +/// that one thread cannot starve others by quickly re-acquiring the lock after +/// releasing it. /// /// A fair mutex may not be interesting if threads have different priorities (this is known as /// priority inversion). @@ -11,7 +11,6 @@ #![warn(missing_docs)] #![warn(rust_2018_idioms)] -#![cfg_attr(feature = "nightly", feature(llvm_asm))] mod condvar; mod elision; diff --git a/src/mutex.rs b/src/mutex.rs index 9f63cb9..71bc351 100644 --- a/src/mutex.rs +++ b/src/mutex.rs @@ -11,7 +11,7 @@ use lock_api; /// A mutual exclusion primitive useful for protecting shared data /// /// This mutex will block threads waiting for the lock to become available. The -/// mutex can also be statically initialized or created via a `new` +/// mutex can be statically initialized or created by the `new` /// constructor. Each mutex has a type parameter which represents the data that /// it is protecting. The data can only be accessed through the RAII guards /// returned from `lock` and `try_lock`, which guarantees that the data is only diff --git a/src/raw_mutex.rs b/src/raw_mutex.rs index 06667d3..b1ae7ee 100644 --- a/src/raw_mutex.rs +++ b/src/raw_mutex.rs @@ -10,9 +10,9 @@ use core::{ sync::atomic::{AtomicU8, Ordering}, time::Duration, }; -use instant::Instant; use lock_api::RawMutex as RawMutex_; use parking_lot_core::{self, ParkResult, SpinWait, UnparkResult, UnparkToken, DEFAULT_PARK_TOKEN}; +use std::time::Instant; // UnparkToken used to indicate that that the target thread should attempt to // lock the mutex again as soon as it is unparked. diff --git a/src/raw_rwlock.rs b/src/raw_rwlock.rs index 75a9812..21d338b 100644 --- a/src/raw_rwlock.rs +++ b/src/raw_rwlock.rs @@ -12,12 +12,11 @@ use core::{ cell::Cell, sync::atomic::{AtomicUsize, Ordering}, }; -use instant::Instant; use lock_api::{RawRwLock as RawRwLock_, RawRwLockUpgrade}; use parking_lot_core::{ self, deadlock, FilterOp, ParkResult, ParkToken, SpinWait, UnparkResult, UnparkToken, }; -use std::time::Duration; +use std::time::{Duration, Instant}; // This reader-writer lock implementation is based on Boost's upgrade_mutex: // https://github.com/boostorg/thread/blob/fc08c1fe2840baeeee143440fba31ef9e9a813c8/include/boost/thread/v2/shared_mutex.hpp#L432 @@ -144,6 +143,12 @@ unsafe impl lock_api::RawRwLock for RawRwLock { let state = self.state.load(Ordering::Relaxed); state & (WRITER_BIT | READERS_MASK) != 0 } + + #[inline] + fn is_locked_exclusive(&self) -> bool { + let state = self.state.load(Ordering::Relaxed); + state & (WRITER_BIT) != 0 + } } unsafe impl lock_api::RawRwLockFair for RawRwLock { @@ -362,7 +367,7 @@ unsafe impl lock_api::RawRwLockUpgrade for RawRwLock { unsafe fn upgrade(&self) { let state = self.state.fetch_sub( (ONE_READER | UPGRADABLE_BIT) - WRITER_BIT, - Ordering::Relaxed, + Ordering::Acquire, ); if state & READERS_MASK != ONE_READER { let result = self.upgrade_slow(None); @@ -377,7 +382,7 @@ unsafe impl lock_api::RawRwLockUpgrade for RawRwLock { .compare_exchange_weak( ONE_READER | UPGRADABLE_BIT, WRITER_BIT, - Ordering::Relaxed, + Ordering::Acquire, Ordering::Relaxed, ) .is_ok() diff --git a/src/rwlock.rs b/src/rwlock.rs index 70e1b1a..512114c 100644 --- a/src/rwlock.rs +++ b/src/rwlock.rs @@ -408,6 +408,8 @@ mod tests { write_result.is_none(), "try_write should fail while read_guard is in scope" ); + assert!(lock.is_locked()); + assert!(!lock.is_locked_exclusive()); drop(read_guard); } @@ -419,6 +421,8 @@ mod tests { write_result.is_none(), "try_write should fail while upgrade_guard is in scope" ); + assert!(lock.is_locked()); + assert!(!lock.is_locked_exclusive()); drop(upgrade_guard); } @@ -430,6 +434,8 @@ mod tests { write_result.is_none(), "try_write should fail while write_guard is in scope" ); + assert!(lock.is_locked()); + assert!(lock.is_locked_exclusive()); drop(write_guard); } @@ -615,4 +621,22 @@ mod tests { .join() .unwrap(); } + + #[test] + fn test_rw_write_is_locked() { + let lock = RwLock::new(0isize); + { + let _read_guard = lock.read(); + + assert!(lock.is_locked()); + assert!(!lock.is_locked_exclusive()); + } + + { + let _write_guard = lock.write(); + + assert!(lock.is_locked()); + assert!(lock.is_locked_exclusive()); + } + } } diff --git a/src/util.rs b/src/util.rs index 19cc2c2..c5496fc 100644 --- a/src/util.rs +++ b/src/util.rs @@ -5,8 +5,7 @@ // http://opensource.org/licenses/MIT>, at your option. This file may not be // copied, modified, or distributed except according to those terms. -use instant::Instant; -use std::time::Duration; +use std::time::{Duration, Instant}; // Option::unchecked_unwrap pub trait UncheckedOptionExt<T> { |