зеркало из https://github.com/mozilla/gecko-dev.git
No bug - Revendor rust dependencies
This commit is contained in:
Родитель
3fffb92cb4
Коммит
833dcb7e06
|
@ -694,7 +694,7 @@ dependencies = [
|
|||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
"nsstring 0.1.0",
|
||||
"parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.19.0",
|
||||
"servo_arc 0.1.1",
|
||||
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1255,12 +1255,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.4.4"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread-id 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1650,7 +1649,7 @@ dependencies = [
|
|||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1780,15 +1779,6 @@ dependencies = [
|
|||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.4"
|
||||
|
@ -2304,7 +2294,7 @@ dependencies = [
|
|||
"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
|
||||
"checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
|
||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||
"checksum parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "37f364e2ce5efa24c7d0b6646d5bb61145551a0112f107ffd7499f1a3e322fbd"
|
||||
"checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd"
|
||||
"checksum parking_lot_core 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6c677d78851950b3aec390e681a411f78cc250cba277d4f578758a377f727970"
|
||||
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
|
||||
|
@ -2353,7 +2343,6 @@ dependencies = [
|
|||
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
|
||||
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
|
||||
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
|
||||
"checksum thread-id 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8df7875b676fddfadffd96deea3b1124e5ede707d4884248931077518cf1f773"
|
||||
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
||||
"checksum thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf947d192a9be60ef5131cc7a4648886ba89d712f16700ebbf80c8a69d05d48f"
|
||||
"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{".travis.yml":"8e424960f1e47843f45cae205873e9590e4317b5b2316090f9f94cf2f5d704e8","Cargo.toml":"a31940ea072ae30f6df4c28f4fcbae206929a9e7e8adf19956dd9ed75fa7e75d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"0c248175303f7dc19ce2cb30882c950a55a49da6b8c765c5ba49feb3e6eb7553","appveyor.yml":"cc608360622923f6f693cd68b4d7c1f64daa55f6b38f0df90f270825c6c276bc","src/condvar.rs":"962a3838e95cb664b261a44f536b003a284fe7bfdcb94a80c9a07c7679cae3dd","src/elision.rs":"0fef04d2991afeabafb041e81afeec74e89095d0eca49e5516bdcd5bc90c086f","src/lib.rs":"50951210148941266ce3a7d4017c339f8ad4419a9a8db6f915023890ed27d638","src/mutex.rs":"59cd61dd8deeaacceabd05e15b7fd6d2942e3f6c3c592221898d84a2ca804a6e","src/once.rs":"eada2e82bd8dcb9ed68d4fb2d9f8c336878eeb122f0bf8dde3feb2d77adfb598","src/raw_mutex.rs":"225cbf0ef951be062866da674e5eea8245fcc43ecd8a26da7097dea03b770bf5","src/raw_remutex.rs":"6c6d2aa83abe8f45db04de0efc04c70564cd0c55b6655da8ef4afe841c0add95","src/raw_rwlock.rs":"a7aebf70b8f7a43f96136388be1a54e5ca5b565c9da623f23434c99fb4c0b147","src/remutex.rs":"7f1640fa5a6eb43b592db47d9afa63904895030d246708ec8eac413dc8093514","src/rwlock.rs":"87d648c5fcccda784da165801b888a3592b6a85ddb605c1df3ae0e881dd22417","src/stable.rs":"cc18c58404dc6017924d88fb9f4ed94e5320b8cb0a36985162b23130b8cd7480","src/util.rs":"2d07c0c010a857790ae2ed6a1215eeed8af76859e076797ea1ba8dec82169e84"},"package":"37f364e2ce5efa24c7d0b6646d5bb61145551a0112f107ffd7499f1a3e322fbd"}
|
||||
{"files":{".travis.yml":"04d3d7425ce24e59d25df35da9c54f3ccd429c62ed8c9cf37b5ed2757afe96f1","Cargo.toml":"9e6a70c63617696e07a9130c27a80203180c1f240eb4ebdddde4429570da0c63","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"9d1e4237f1063e54aca1f65fc00a87ad53f75fcc73d054f8dd139f62f4a0b15e","appveyor.yml":"cfa9c3ae2476c879fe4240c306d45de6c2c04025212d8217fa76690888117594","src/condvar.rs":"1a3de60460e832d7ff76a82d5dac3f387fe2255e6a8ad4a686fe37f134c088c7","src/deadlock.rs":"82de990ef5966c852f8019b511e3c60471b562e56fd7ed0ca340399968b44a2d","src/elision.rs":"89072fe0aca87d53abc0f56490ae77bcf9d77e28e291bd13e861b1924bbb079f","src/lib.rs":"02d5716f4f43c2598afa57234e53d1a4c5db4f91ede937a226ee34eabbdc4da5","src/mutex.rs":"d8f557d40c3aab3e36f81961db9eb32831580a3a6a4b2a59674cafe6621e4772","src/once.rs":"1f408083854f918e896fdba8a9ecf25ae79ee06613d8daec75b800fb78dfd3a8","src/raw_mutex.rs":"f98ddd76e1491bc239b7c24e94f3f6a94ae0f5828873e78e1245ef19621a257b","src/raw_remutex.rs":"86e1e339567c12f91e3274ca3126c4af004fd30dff88a6cd261fc67680e33798","src/raw_rwlock.rs":"d3c71098df5e8b22cdfd7f8d7c3f287951d0bac1ac9ede83a94f809576ed9d41","src/remutex.rs":"d73f4a0f22f4a5e8c6126b784c03157f34456b0c1b90570b98db9f1c6b1f4046","src/rwlock.rs":"28e6c3a3d1aea9add4950fa5c67ba79f4aeb2e72830ff4d4a66adc2a9afa12dc","src/util.rs":"2d07c0c010a857790ae2ed6a1215eeed8af76859e076797ea1ba8dec82169e84"},"package":"9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd"}
|
|
@ -2,7 +2,7 @@ language: rust
|
|||
sudo: false
|
||||
|
||||
rust:
|
||||
- 1.13.0
|
||||
- 1.18.0
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
@ -18,7 +18,8 @@ script:
|
|||
- cd ..;
|
||||
- travis-cargo build
|
||||
- travis-cargo test
|
||||
- travis-cargo doc -- --no-deps -p parking_lot -p parking_lot_core
|
||||
- travis-cargo test -- --features=deadlock_detection
|
||||
- travis-cargo --only nightly doc -- --all-features --no-deps -p parking_lot -p parking_lot_core
|
||||
- if [ "$TRAVIS_RUST_VERSION" != "1.8.0" ]; then
|
||||
cd benchmark;
|
||||
travis-cargo build;
|
||||
|
@ -33,6 +34,7 @@ after_success:
|
|||
env:
|
||||
global:
|
||||
- TRAVIS_CARGO_NIGHTLY_FEATURE=nightly
|
||||
- RUST_TEST_THREADS=1
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "parking_lot"
|
||||
version = "0.4.4"
|
||||
version = "0.5.4"
|
||||
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
|
||||
description = "More compact and efficient implementations of the standard synchronization primitives."
|
||||
documentation = "https://amanieu.github.io/parking_lot/parking_lot/index.html"
|
||||
|
@ -27,10 +27,9 @@ optional = true
|
|||
[dependencies.parking_lot_core]
|
||||
version = "0.2"
|
||||
[dev-dependencies.rand]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
|
||||
[features]
|
||||
deadlock_detection = ["parking_lot_core/deadlock_detection"]
|
||||
default = ["owning_ref"]
|
||||
nightly = ["parking_lot_core/nightly"]
|
||||
[target."cfg(not(target_os = \"emscripten\"))".dependencies.thread-id]
|
||||
version = "3.0"
|
||||
|
|
|
@ -47,22 +47,25 @@ 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.
|
||||
8. `MutexGuard` (and the `RwLock` equivalents) is `Send`, which means it can
|
||||
be unlocked by a different thread than the one that locked it.
|
||||
9. `RwLock` uses a task-fair locking policy, which avoids reader and writer
|
||||
8. `RwLock` uses a task-fair locking policy, which avoids reader and writer
|
||||
starvation, whereas the standard library version makes no guarantees.
|
||||
10. `Condvar` is guaranteed not to produce spurious wakeups. A thread will
|
||||
9. `Condvar` is guaranteed not to produce spurious wakeups. A thread will
|
||||
only be woken up if it timed out or it was woken up by a notification.
|
||||
11. `Condvar::notify_all` will only wake up a single thread and requeue the
|
||||
10. `Condvar::notify_all` will only wake up a single thread and requeue the
|
||||
rest to wait on the associated `Mutex`. This avoids a thundering herd
|
||||
problem where all threads try to acquire the lock at the same time.
|
||||
12. `RwLock` supports atomically downgrading a write lock into a read lock.
|
||||
13. `Mutex` and `RwLock` allow raw unlocking without a RAII guard object.
|
||||
14. `Mutex<()>` and `RwLock<()>` allow raw locking without a RAII guard
|
||||
11. `RwLock` supports atomically downgrading a write lock into a read lock.
|
||||
12. `Mutex` and `RwLock` allow raw unlocking without a RAII guard object.
|
||||
13. `Mutex<()>` and `RwLock<()>` allow raw locking without a RAII guard
|
||||
object.
|
||||
15. `Mutex` and `RwLock` support [eventual fairness](https://trac.webkit.org/changeset/203350)
|
||||
14. `Mutex` and `RwLock` support [eventual fairness](https://trac.webkit.org/changeset/203350)
|
||||
which allows them to be fair on average without sacrificing performance.
|
||||
16. A `ReentrantMutex` type which supports recursive locking.
|
||||
15. A `ReentrantMutex` type which supports recursive locking.
|
||||
16. An *experimental* deadlock detector that works for `Mutex`,
|
||||
`RwLock` and `ReentrantMutex`. This feature is disabled by default and
|
||||
can be enabled via the `deadlock_detection` feature.
|
||||
17. `RwLock` supports atomically upgrading an "upgradable" read lock into a
|
||||
write lock.
|
||||
|
||||
## The parking lot
|
||||
|
||||
|
@ -87,13 +90,16 @@ There are a few restrictions when using this library on stable Rust:
|
|||
- Slightly less efficient code may be generated for `compare_exchange`
|
||||
operations. This should not affect architectures like x86 though.
|
||||
|
||||
To enable nightly-only functionality, you need to enable the `nightly` feature
|
||||
in Cargo (see below).
|
||||
|
||||
## Usage
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
parking_lot = "0.4"
|
||||
parking_lot = "0.5"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
@ -106,9 +112,12 @@ To enable nightly-only features, add this to your `Cargo.toml` instead:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
parking_lot = {version = "0.4", features = ["nightly"]}
|
||||
parking_lot = {version = "0.5", features = ["nightly"]}
|
||||
```
|
||||
|
||||
The experimental deadlock detector can be enabled with the
|
||||
`deadlock_detection` Cargo feature.
|
||||
|
||||
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`.
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
environment:
|
||||
TRAVIS_CARGO_NIGHTLY_FEATURE: nightly
|
||||
RUST_TEST_THREADS: 1
|
||||
matrix:
|
||||
- TARGET: nightly-x86_64-pc-windows-msvc
|
||||
- TARGET: nightly-i686-pc-windows-msvc
|
||||
- TARGET: nightly-x86_64-pc-windows-gnu
|
||||
- TARGET: nightly-i686-pc-windows-gnu
|
||||
- TARGET: 1.13.0-x86_64-pc-windows-msvc
|
||||
- TARGET: 1.13.0-i686-pc-windows-msvc
|
||||
- TARGET: 1.13.0-x86_64-pc-windows-gnu
|
||||
- TARGET: 1.13.0-i686-pc-windows-gnu
|
||||
- TARGET: 1.18.0-x86_64-pc-windows-msvc
|
||||
- TARGET: 1.18.0-i686-pc-windows-msvc
|
||||
- TARGET: 1.18.0-x86_64-pc-windows-gnu
|
||||
- TARGET: 1.18.0-i686-pc-windows-gnu
|
||||
|
||||
install:
|
||||
- SET PATH=C:\Python27;C:\Python27\Scripts;%PATH%;%APPDATA%\Python\Scripts
|
||||
|
@ -24,4 +25,5 @@ build_script:
|
|||
|
||||
test_script:
|
||||
- travis-cargo test
|
||||
- travis-cargo test -- --features=deadlock_detection
|
||||
- travis-cargo doc
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::ptr;
|
||||
use parking_lot_core::{self, ParkResult, UnparkResult, RequeueOp, DEFAULT_PARK_TOKEN};
|
||||
use mutex::{MutexGuard, guard_lock};
|
||||
use raw_mutex::{RawMutex, TOKEN_NORMAL, TOKEN_HANDOFF};
|
||||
use parking_lot_core::{self, ParkResult, RequeueOp, UnparkResult, DEFAULT_PARK_TOKEN};
|
||||
use mutex::{guard_lock, MutexGuard};
|
||||
use raw_mutex::{RawMutex, TOKEN_HANDOFF, TOKEN_NORMAL};
|
||||
use deadlock;
|
||||
|
||||
/// A type indicating whether a timed wait on a condition variable returned
|
||||
/// due to a time out or not.
|
||||
|
@ -88,7 +89,9 @@ impl Condvar {
|
|||
#[cfg(feature = "nightly")]
|
||||
#[inline]
|
||||
pub const fn new() -> Condvar {
|
||||
Condvar { state: AtomicPtr::new(ptr::null_mut()) }
|
||||
Condvar {
|
||||
state: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new condition variable which is ready to be waited on and
|
||||
|
@ -96,7 +99,9 @@ impl Condvar {
|
|||
#[cfg(not(feature = "nightly"))]
|
||||
#[inline]
|
||||
pub fn new() -> Condvar {
|
||||
Condvar { state: AtomicPtr::new(ptr::null_mut()) }
|
||||
Condvar {
|
||||
state: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Wakes up one blocked thread on this condvar.
|
||||
|
@ -238,10 +243,11 @@ impl Condvar {
|
|||
/// This function will panic if another thread is waiting on the `Condvar`
|
||||
/// with a different `Mutex` object.
|
||||
#[inline]
|
||||
pub fn wait_until<T: ?Sized>(&self,
|
||||
mutex_guard: &mut MutexGuard<T>,
|
||||
timeout: Instant)
|
||||
-> WaitTimeoutResult {
|
||||
pub fn wait_until<T: ?Sized>(
|
||||
&self,
|
||||
mutex_guard: &mut MutexGuard<T>,
|
||||
timeout: Instant,
|
||||
) -> WaitTimeoutResult {
|
||||
self.wait_until_internal(guard_lock(mutex_guard), Some(timeout))
|
||||
}
|
||||
|
||||
|
@ -285,12 +291,14 @@ impl Condvar {
|
|||
self.state.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
}
|
||||
};
|
||||
result = parking_lot_core::park(addr,
|
||||
validate,
|
||||
before_sleep,
|
||||
timed_out,
|
||||
DEFAULT_PARK_TOKEN,
|
||||
timeout);
|
||||
result = 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
|
||||
|
@ -301,7 +309,9 @@ impl Condvar {
|
|||
}
|
||||
|
||||
// ... and re-lock it once we are done sleeping
|
||||
if result != ParkResult::Unparked(TOKEN_HANDOFF) {
|
||||
if result == ParkResult::Unparked(TOKEN_HANDOFF) {
|
||||
deadlock::acquire_resource(mutex as *const _ as usize);
|
||||
} else {
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
|
@ -328,10 +338,11 @@ impl Condvar {
|
|||
/// 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_for<T: ?Sized>(&self,
|
||||
guard: &mut MutexGuard<T>,
|
||||
timeout: Duration)
|
||||
-> WaitTimeoutResult {
|
||||
pub fn wait_for<T: ?Sized>(
|
||||
&self,
|
||||
guard: &mut MutexGuard<T>,
|
||||
timeout: Duration,
|
||||
) -> WaitTimeoutResult {
|
||||
self.wait_until(guard, Instant::now() + timeout)
|
||||
}
|
||||
}
|
||||
|
@ -442,9 +453,10 @@ mod tests {
|
|||
let _g = m2.lock();
|
||||
c2.notify_one();
|
||||
});
|
||||
let timeout_res = c.wait_until(&mut g,
|
||||
Instant::now() +
|
||||
Duration::from_millis(u32::max_value() as u64));
|
||||
let timeout_res = c.wait_until(
|
||||
&mut g,
|
||||
Instant::now() + Duration::from_millis(u32::max_value() as u64),
|
||||
);
|
||||
assert!(!timeout_res.timed_out());
|
||||
drop(g);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
//! [Experimental] Deadlock detection
|
||||
//!
|
||||
//! This feature is optional and can be enabled via the `deadlock_detection` feature flag.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! #[cfg(feature = "deadlock_detection")]
|
||||
//! { // only for #[cfg]
|
||||
//! use std::thread;
|
||||
//! use std::time::Duration;
|
||||
//! use parking_lot::deadlock;
|
||||
//!
|
||||
//! // Create a background thread which checks for deadlocks every 10s
|
||||
//! thread::spawn(move || {
|
||||
//! loop {
|
||||
//! thread::sleep(Duration::from_secs(10));
|
||||
//! let deadlocks = deadlock::check_deadlock();
|
||||
//! if deadlocks.is_empty() {
|
||||
//! continue;
|
||||
//! }
|
||||
//!
|
||||
//! println!("{} deadlocks detected", deadlocks.len());
|
||||
//! for (i, threads) in deadlocks.iter().enumerate() {
|
||||
//! println!("Deadlock #{}", i);
|
||||
//! for t in threads {
|
||||
//! println!("Thread Id {:#?}", t.thread_id());
|
||||
//! println!("{:#?}", t.backtrace());
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! });
|
||||
//! } // only for #[cfg]
|
||||
//! ```
|
||||
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
pub use parking_lot_core::deadlock::check_deadlock;
|
||||
pub(crate) use parking_lot_core::deadlock::{acquire_resource, release_resource};
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
mod tests {
|
||||
use std::thread::{self, sleep};
|
||||
use std::sync::{Arc, Barrier};
|
||||
use std::time::Duration;
|
||||
use {Mutex, ReentrantMutex, RwLock};
|
||||
|
||||
fn check_deadlock() -> bool {
|
||||
use parking_lot_core::deadlock::check_deadlock;
|
||||
!check_deadlock().is_empty()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutex_deadlock() {
|
||||
let m1: Arc<Mutex<()>> = Default::default();
|
||||
let m2: Arc<Mutex<()>> = Default::default();
|
||||
let m3: Arc<Mutex<()>> = Default::default();
|
||||
let b = Arc::new(Barrier::new(4));
|
||||
|
||||
let m1_ = m1.clone();
|
||||
let m2_ = m2.clone();
|
||||
let m3_ = m3.clone();
|
||||
let b1 = b.clone();
|
||||
let b2 = b.clone();
|
||||
let b3 = b.clone();
|
||||
|
||||
assert!(!check_deadlock());
|
||||
|
||||
let _t1 = thread::spawn(move || {
|
||||
let _g = m1.lock();
|
||||
b1.wait();
|
||||
let _ = m2_.lock();
|
||||
});
|
||||
|
||||
let _t2 = thread::spawn(move || {
|
||||
let _g = m2.lock();
|
||||
b2.wait();
|
||||
let _ = m3_.lock();
|
||||
});
|
||||
|
||||
let _t3 = thread::spawn(move || {
|
||||
let _g = m3.lock();
|
||||
b3.wait();
|
||||
let _ = m1_.lock();
|
||||
});
|
||||
|
||||
assert!(!check_deadlock());
|
||||
|
||||
b.wait();
|
||||
sleep(Duration::from_millis(50));
|
||||
assert!(check_deadlock());
|
||||
|
||||
assert!(!check_deadlock());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutex_deadlock_reentrant() {
|
||||
let m1: Arc<Mutex<()>> = Default::default();
|
||||
|
||||
assert!(!check_deadlock());
|
||||
|
||||
let _t1 = thread::spawn(move || {
|
||||
let _g = m1.lock();
|
||||
let _ = m1.lock();
|
||||
});
|
||||
|
||||
sleep(Duration::from_millis(50));
|
||||
assert!(check_deadlock());
|
||||
|
||||
assert!(!check_deadlock());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remutex_deadlock() {
|
||||
let m1: Arc<ReentrantMutex<()>> = Default::default();
|
||||
let m2: Arc<ReentrantMutex<()>> = Default::default();
|
||||
let m3: Arc<ReentrantMutex<()>> = Default::default();
|
||||
let b = Arc::new(Barrier::new(4));
|
||||
|
||||
let m1_ = m1.clone();
|
||||
let m2_ = m2.clone();
|
||||
let m3_ = m3.clone();
|
||||
let b1 = b.clone();
|
||||
let b2 = b.clone();
|
||||
let b3 = b.clone();
|
||||
|
||||
assert!(!check_deadlock());
|
||||
|
||||
let _t1 = thread::spawn(move || {
|
||||
let _g = m1.lock();
|
||||
let _g = m1.lock();
|
||||
b1.wait();
|
||||
let _ = m2_.lock();
|
||||
});
|
||||
|
||||
let _t2 = thread::spawn(move || {
|
||||
let _g = m2.lock();
|
||||
let _g = m2.lock();
|
||||
b2.wait();
|
||||
let _ = m3_.lock();
|
||||
});
|
||||
|
||||
let _t3 = thread::spawn(move || {
|
||||
let _g = m3.lock();
|
||||
let _g = m3.lock();
|
||||
b3.wait();
|
||||
let _ = m1_.lock();
|
||||
});
|
||||
|
||||
assert!(!check_deadlock());
|
||||
|
||||
b.wait();
|
||||
sleep(Duration::from_millis(50));
|
||||
assert!(check_deadlock());
|
||||
|
||||
assert!(!check_deadlock());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rwlock_deadlock() {
|
||||
let m1: Arc<RwLock<()>> = Default::default();
|
||||
let m2: Arc<RwLock<()>> = Default::default();
|
||||
let m3: Arc<RwLock<()>> = Default::default();
|
||||
let b = Arc::new(Barrier::new(4));
|
||||
|
||||
let m1_ = m1.clone();
|
||||
let m2_ = m2.clone();
|
||||
let m3_ = m3.clone();
|
||||
let b1 = b.clone();
|
||||
let b2 = b.clone();
|
||||
let b3 = b.clone();
|
||||
|
||||
assert!(!check_deadlock());
|
||||
|
||||
let _t1 = thread::spawn(move || {
|
||||
let _g = m1.read();
|
||||
b1.wait();
|
||||
let _g = m2_.write();
|
||||
});
|
||||
|
||||
let _t2 = thread::spawn(move || {
|
||||
let _g = m2.read();
|
||||
b2.wait();
|
||||
let _g = m3_.write();
|
||||
});
|
||||
|
||||
let _t3 = thread::spawn(move || {
|
||||
let _g = m3.read();
|
||||
b3.wait();
|
||||
let _ = m1_.write();
|
||||
});
|
||||
|
||||
assert!(!check_deadlock());
|
||||
|
||||
b.wait();
|
||||
sleep(Duration::from_millis(50));
|
||||
assert!(check_deadlock());
|
||||
|
||||
assert!(!check_deadlock());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rwlock_deadlock_reentrant() {
|
||||
let m1: Arc<RwLock<()>> = Default::default();
|
||||
|
||||
assert!(!check_deadlock());
|
||||
|
||||
let _t1 = thread::spawn(move || {
|
||||
let _g = m1.read();
|
||||
let _ = m1.write();
|
||||
});
|
||||
|
||||
sleep(Duration::from_millis(50));
|
||||
assert!(check_deadlock());
|
||||
|
||||
assert!(!check_deadlock());
|
||||
}
|
||||
}
|
|
@ -5,32 +5,33 @@
|
|||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use stable::AtomicUsize;
|
||||
|
||||
// Extension trait to add lock elision primitives to atomic types
|
||||
pub trait AtomicElisionExt {
|
||||
type IntType;
|
||||
|
||||
// Perform a compare_exchange and start a transaction
|
||||
fn elision_acquire(&self,
|
||||
current: Self::IntType,
|
||||
new: Self::IntType)
|
||||
-> Result<Self::IntType, Self::IntType>;
|
||||
fn elision_acquire(
|
||||
&self,
|
||||
current: Self::IntType,
|
||||
new: Self::IntType,
|
||||
) -> Result<Self::IntType, Self::IntType>;
|
||||
// Perform a compare_exchange and end a transaction
|
||||
fn elision_release(&self,
|
||||
current: Self::IntType,
|
||||
new: Self::IntType)
|
||||
-> Result<Self::IntType, Self::IntType>;
|
||||
fn elision_release(
|
||||
&self,
|
||||
current: Self::IntType,
|
||||
new: Self::IntType,
|
||||
) -> Result<Self::IntType, Self::IntType>;
|
||||
}
|
||||
|
||||
// Indicates whether the target architecture supports lock elision
|
||||
#[inline]
|
||||
pub fn have_elision() -> bool {
|
||||
cfg!(all(feature = "nightly",
|
||||
any(target_arch = "x86", target_arch = "x86_64")))
|
||||
cfg!(all(
|
||||
feature = "nightly",
|
||||
any(target_arch = "x86", target_arch = "x86_64"),
|
||||
))
|
||||
}
|
||||
|
||||
// This implementation is never actually called because it is guarded by
|
||||
|
@ -63,7 +64,11 @@ impl AtomicElisionExt for AtomicUsize {
|
|||
: "r" (new), "{eax}" (current)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
if prev == current { Ok(prev) } else { Err(prev) }
|
||||
if prev == current {
|
||||
Ok(prev)
|
||||
} else {
|
||||
Err(prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,12 +81,55 @@ impl AtomicElisionExt for AtomicUsize {
|
|||
: "r" (new), "{eax}" (current)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
if prev == current { Ok(prev) } else { Err(prev) }
|
||||
if prev == current {
|
||||
Ok(prev)
|
||||
} else {
|
||||
Err(prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "nightly", target_arch = "x86_64"))]
|
||||
#[cfg(all(feature = "nightly", target_arch = "x86_64", target_pointer_width = "32"))]
|
||||
impl AtomicElisionExt for AtomicUsize {
|
||||
type IntType = usize;
|
||||
|
||||
#[inline]
|
||||
fn elision_acquire(&self, current: usize, new: usize) -> Result<usize, usize> {
|
||||
unsafe {
|
||||
let prev: usize;
|
||||
asm!("xacquire; lock; cmpxchgl $2, $1"
|
||||
: "={rax}" (prev), "+*m" (self)
|
||||
: "r" (new), "{rax}" (current)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
if prev == current {
|
||||
Ok(prev)
|
||||
} else {
|
||||
Err(prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn elision_release(&self, current: usize, new: usize) -> Result<usize, usize> {
|
||||
unsafe {
|
||||
let prev: usize;
|
||||
asm!("xrelease; lock; cmpxchgl $2, $1"
|
||||
: "={rax}" (prev), "+*m" (self)
|
||||
: "r" (new), "{rax}" (current)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
if prev == current {
|
||||
Ok(prev)
|
||||
} else {
|
||||
Err(prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "nightly", target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
impl AtomicElisionExt for AtomicUsize {
|
||||
type IntType = usize;
|
||||
|
||||
|
@ -94,7 +142,11 @@ impl AtomicElisionExt for AtomicUsize {
|
|||
: "r" (new), "{rax}" (current)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
if prev == current { Ok(prev) } else { Err(prev) }
|
||||
if prev == current {
|
||||
Ok(prev)
|
||||
} else {
|
||||
Err(prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +159,11 @@ impl AtomicElisionExt for AtomicUsize {
|
|||
: "r" (new), "{rax}" (current)
|
||||
: "memory"
|
||||
: "volatile");
|
||||
if prev == current { Ok(prev) } else { Err(prev) }
|
||||
if prev == current {
|
||||
Ok(prev)
|
||||
} else {
|
||||
Err(prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,8 @@
|
|||
#[cfg(feature = "owning_ref")]
|
||||
extern crate owning_ref;
|
||||
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
extern crate thread_id;
|
||||
|
||||
extern crate parking_lot_core;
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
mod stable;
|
||||
|
||||
mod util;
|
||||
mod elision;
|
||||
mod raw_mutex;
|
||||
|
@ -36,11 +30,16 @@ mod remutex;
|
|||
mod rwlock;
|
||||
mod once;
|
||||
|
||||
pub use once::{Once, ONCE_INIT, OnceState};
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
pub mod deadlock;
|
||||
#[cfg(not(feature = "deadlock_detection"))]
|
||||
mod deadlock;
|
||||
|
||||
pub use once::{Once, OnceState, ONCE_INIT};
|
||||
pub use mutex::{Mutex, MutexGuard};
|
||||
pub use remutex::{ReentrantMutex, ReentrantMutexGuard};
|
||||
pub use condvar::{Condvar, WaitTimeoutResult};
|
||||
pub use rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
pub use rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableReadGuard, RwLockWriteGuard};
|
||||
|
||||
#[cfg(feature = "owning_ref")]
|
||||
use owning_ref::OwningRef;
|
||||
|
@ -60,3 +59,8 @@ pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef<RwLockReadGuard<'a, T>, U>
|
|||
/// Typedef of an owning reference that uses a `RwLockWriteGuard` as the owner.
|
||||
#[cfg(feature = "owning_ref")]
|
||||
pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef<RwLockWriteGuard<'a, T>, U>;
|
||||
|
||||
/// Typedef of an owning reference that uses a `RwLockUpgradableReadGuard` as the owner.
|
||||
#[cfg(feature = "owning_ref")]
|
||||
pub type RwLockUpgradableReadGuardRef<'a, T, U = T> =
|
||||
OwningRef<RwLockUpgradableReadGuard<'a, T>, U>;
|
||||
|
|
|
@ -50,7 +50,6 @@ use owning_ref::StableAddress;
|
|||
/// - 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.
|
||||
/// - A `MutexGuard` can be sent to another thread and unlocked there.
|
||||
/// - Can be statically constructed (requires the `const_fn` nightly feature).
|
||||
/// - Does not require any drop glue when dropped.
|
||||
/// - Inline fast path for the uncontended case.
|
||||
|
@ -99,8 +98,8 @@ pub struct Mutex<T: ?Sized> {
|
|||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for Mutex<T> {}
|
||||
unsafe impl<T: Send> Sync for Mutex<T> {}
|
||||
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
|
||||
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
|
||||
|
||||
/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
|
||||
/// dropped (falls out of scope), the lock will be unlocked.
|
||||
|
@ -109,10 +108,13 @@ unsafe impl<T: Send> Sync for Mutex<T> {}
|
|||
/// `Deref` and `DerefMut` implementations.
|
||||
#[must_use]
|
||||
pub struct MutexGuard<'a, T: ?Sized + 'a> {
|
||||
mutex: &'a Mutex<T>,
|
||||
raw: &'a RawMutex,
|
||||
data: *mut T,
|
||||
marker: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: ?Sized + Sync + 'a> Sync for MutexGuard<'a, T> {}
|
||||
|
||||
impl<T> Mutex<T> {
|
||||
/// Creates a new mutex in an unlocked state ready for use.
|
||||
#[cfg(feature = "nightly")]
|
||||
|
@ -142,6 +144,15 @@ impl<T> Mutex<T> {
|
|||
}
|
||||
|
||||
impl<T: ?Sized> Mutex<T> {
|
||||
#[inline]
|
||||
fn guard(&self) -> MutexGuard<T> {
|
||||
MutexGuard {
|
||||
raw: &self.raw,
|
||||
data: self.data.get(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires a mutex, blocking the current thread until it is able to do so.
|
||||
///
|
||||
/// This function will block the local thread until it is available to acquire
|
||||
|
@ -154,10 +165,7 @@ impl<T: ?Sized> Mutex<T> {
|
|||
#[inline]
|
||||
pub fn lock(&self) -> MutexGuard<T> {
|
||||
self.raw.lock();
|
||||
MutexGuard {
|
||||
mutex: self,
|
||||
marker: PhantomData,
|
||||
}
|
||||
self.guard()
|
||||
}
|
||||
|
||||
/// Attempts to acquire this lock.
|
||||
|
@ -170,10 +178,7 @@ impl<T: ?Sized> Mutex<T> {
|
|||
#[inline]
|
||||
pub fn try_lock(&self) -> Option<MutexGuard<T>> {
|
||||
if self.raw.try_lock() {
|
||||
Some(MutexGuard {
|
||||
mutex: self,
|
||||
marker: PhantomData,
|
||||
})
|
||||
Some(self.guard())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -187,10 +192,7 @@ impl<T: ?Sized> Mutex<T> {
|
|||
#[inline]
|
||||
pub fn try_lock_for(&self, timeout: Duration) -> Option<MutexGuard<T>> {
|
||||
if self.raw.try_lock_for(timeout) {
|
||||
Some(MutexGuard {
|
||||
mutex: self,
|
||||
marker: PhantomData,
|
||||
})
|
||||
Some(self.guard())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -204,10 +206,7 @@ impl<T: ?Sized> Mutex<T> {
|
|||
#[inline]
|
||||
pub fn try_lock_until(&self, timeout: Instant) -> Option<MutexGuard<T>> {
|
||||
if self.raw.try_lock_until(timeout) {
|
||||
Some(MutexGuard {
|
||||
mutex: self,
|
||||
marker: PhantomData,
|
||||
})
|
||||
Some(self.guard())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -300,30 +299,53 @@ impl<'a, T: ?Sized + 'a> MutexGuard<'a, T> {
|
|||
/// using this method instead of dropping the `MutexGuard` normally.
|
||||
#[inline]
|
||||
pub fn unlock_fair(self) {
|
||||
self.mutex.raw.unlock(true);
|
||||
self.raw.unlock(true);
|
||||
mem::forget(self);
|
||||
}
|
||||
|
||||
/// Make a new `MutexGuard` for a component of the locked data.
|
||||
///
|
||||
/// This operation cannot fail as the `MutexGuard` passed
|
||||
/// in already locked the mutex.
|
||||
///
|
||||
/// This is an associated function that needs to be
|
||||
/// used as `MutexGuard::map(...)`. A method would interfere with methods of
|
||||
/// the same name on the contents of the locked data.
|
||||
#[inline]
|
||||
pub fn map<U: ?Sized, F>(orig: Self, f: F) -> MutexGuard<'a, U>
|
||||
where
|
||||
F: FnOnce(&mut T) -> &mut U,
|
||||
{
|
||||
let raw = orig.raw;
|
||||
let data = f(unsafe { &mut *orig.data });
|
||||
mem::forget(orig);
|
||||
MutexGuard {
|
||||
raw,
|
||||
data,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a> Deref for MutexGuard<'a, T> {
|
||||
type Target = T;
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.mutex.data.get() }
|
||||
unsafe { &*self.data }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a> DerefMut for MutexGuard<'a, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.mutex.data.get() }
|
||||
unsafe { &mut *self.data }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a> Drop for MutexGuard<'a, T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
self.mutex.raw.unlock(false);
|
||||
self.raw.unlock(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,8 +354,8 @@ unsafe impl<'a, T: ?Sized> StableAddress for MutexGuard<'a, T> {}
|
|||
|
||||
// Helper function used by Condvar, not publicly exported
|
||||
#[inline]
|
||||
pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a RawMutex {
|
||||
&guard.mutex.raw
|
||||
pub(crate) fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a RawMutex {
|
||||
&guard.raw
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -342,7 +364,7 @@ mod tests {
|
|||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::thread;
|
||||
use {Mutex, Condvar};
|
||||
use {Condvar, Mutex};
|
||||
|
||||
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
|
||||
|
||||
|
@ -476,18 +498,17 @@ mod tests {
|
|||
let arc = Arc::new(Mutex::new(1));
|
||||
let arc2 = arc.clone();
|
||||
let _ = thread::spawn(move || -> () {
|
||||
struct Unwinder {
|
||||
i: Arc<Mutex<i32>>,
|
||||
struct Unwinder {
|
||||
i: Arc<Mutex<i32>>,
|
||||
}
|
||||
impl Drop for Unwinder {
|
||||
fn drop(&mut self) {
|
||||
*self.i.lock() += 1;
|
||||
}
|
||||
impl Drop for Unwinder {
|
||||
fn drop(&mut self) {
|
||||
*self.i.lock() += 1;
|
||||
}
|
||||
}
|
||||
let _u = Unwinder { i: arc2 };
|
||||
panic!();
|
||||
})
|
||||
.join();
|
||||
}
|
||||
let _u = Unwinder { i: arc2 };
|
||||
panic!();
|
||||
}).join();
|
||||
let lock = arc.lock();
|
||||
assert_eq!(*lock, 2);
|
||||
}
|
||||
|
@ -505,10 +526,10 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutexguard_send() {
|
||||
fn send<T: Send>(_: T) {}
|
||||
fn test_mutexguard_sync() {
|
||||
fn sync<T: Sync>(_: T) {}
|
||||
|
||||
let mutex = Mutex::new(());
|
||||
send(mutex.lock());
|
||||
sync(mutex.lock());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,15 +5,19 @@
|
|||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
use std::sync::atomic::{fence, Ordering};
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::sync::atomic::{AtomicU8, ATOMIC_U8_INIT, Ordering, fence};
|
||||
use std::sync::atomic::{ATOMIC_U8_INIT, AtomicU8};
|
||||
#[cfg(feature = "nightly")]
|
||||
type U8 = u8;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use stable::{AtomicU8, ATOMIC_U8_INIT, Ordering, fence};
|
||||
use std::sync::atomic::AtomicUsize as AtomicU8;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use std::sync::atomic::ATOMIC_USIZE_INIT as ATOMIC_U8_INIT;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
type U8 = usize;
|
||||
use std::mem;
|
||||
use std::fmt;
|
||||
use parking_lot_core::{self, SpinWait, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN};
|
||||
use util::UncheckedOptionExt;
|
||||
|
||||
|
@ -95,14 +99,14 @@ impl Once {
|
|||
#[cfg(feature = "nightly")]
|
||||
#[inline]
|
||||
pub const fn new() -> Once {
|
||||
Once(AtomicU8::new(0))
|
||||
Once(ATOMIC_U8_INIT)
|
||||
}
|
||||
|
||||
/// Creates a new `Once` value.
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[inline]
|
||||
pub fn new() -> Once {
|
||||
Once(AtomicU8::new(0))
|
||||
Once(ATOMIC_U8_INIT)
|
||||
}
|
||||
|
||||
/// Returns the current state of this `Once`.
|
||||
|
@ -171,7 +175,8 @@ impl Once {
|
|||
/// `call_once` to also panic.
|
||||
#[inline]
|
||||
pub fn call_once<F>(&self, f: F)
|
||||
where F: FnOnce()
|
||||
where
|
||||
F: FnOnce(),
|
||||
{
|
||||
if self.0.load(Ordering::Acquire) == DONE_BIT {
|
||||
return;
|
||||
|
@ -192,15 +197,17 @@ impl Once {
|
|||
/// not).
|
||||
#[inline]
|
||||
pub fn call_once_force<F>(&self, f: F)
|
||||
where F: FnOnce(OnceState)
|
||||
where
|
||||
F: FnOnce(OnceState),
|
||||
{
|
||||
if self.0.load(Ordering::Acquire) == DONE_BIT {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut f = Some(f);
|
||||
self.call_once_slow(true,
|
||||
&mut |state| unsafe { f.take().unchecked_unwrap()(state) });
|
||||
self.call_once_slow(true, &mut |state| unsafe {
|
||||
f.take().unchecked_unwrap()(state)
|
||||
});
|
||||
}
|
||||
|
||||
// This is a non-generic function to reduce the monomorphization cost of
|
||||
|
@ -239,11 +246,12 @@ impl Once {
|
|||
// We also clear the poison bit since we are going to try running
|
||||
// the closure again.
|
||||
if state & LOCKED_BIT == 0 {
|
||||
match self.0
|
||||
.compare_exchange_weak(state,
|
||||
(state | LOCKED_BIT) & !POISON_BIT,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed) {
|
||||
match self.0.compare_exchange_weak(
|
||||
state,
|
||||
(state | LOCKED_BIT) & !POISON_BIT,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => break,
|
||||
Err(x) => state = x,
|
||||
}
|
||||
|
@ -258,10 +266,12 @@ impl Once {
|
|||
|
||||
// Set the parked bit
|
||||
if state & PARKED_BIT == 0 {
|
||||
if let Err(x) = self.0.compare_exchange_weak(state,
|
||||
state | PARKED_BIT,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Relaxed) {
|
||||
if let Err(x) = self.0.compare_exchange_weak(
|
||||
state,
|
||||
state | PARKED_BIT,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
state = x;
|
||||
continue;
|
||||
}
|
||||
|
@ -274,12 +284,14 @@ impl Once {
|
|||
let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
|
||||
let before_sleep = || {};
|
||||
let timed_out = |_, _| unreachable!();
|
||||
parking_lot_core::park(addr,
|
||||
validate,
|
||||
before_sleep,
|
||||
timed_out,
|
||||
DEFAULT_PARK_TOKEN,
|
||||
None);
|
||||
parking_lot_core::park(
|
||||
addr,
|
||||
validate,
|
||||
before_sleep,
|
||||
timed_out,
|
||||
DEFAULT_PARK_TOKEN,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
// Loop back and check if the done bit was set
|
||||
|
@ -331,6 +343,12 @@ impl Default for Once {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Once {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Once {{ state: {:?} }}", &self.state())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(feature = "nightly")]
|
||||
|
@ -391,11 +409,15 @@ mod tests {
|
|||
static O: Once = ONCE_INIT;
|
||||
|
||||
// poison the once
|
||||
let t = panic::catch_unwind(|| { O.call_once(|| panic!()); });
|
||||
let t = panic::catch_unwind(|| {
|
||||
O.call_once(|| panic!());
|
||||
});
|
||||
assert!(t.is_err());
|
||||
|
||||
// poisoning propagates
|
||||
let t = panic::catch_unwind(|| { O.call_once(|| {}); });
|
||||
let t = panic::catch_unwind(|| {
|
||||
O.call_once(|| {});
|
||||
});
|
||||
assert!(t.is_err());
|
||||
|
||||
// we can subvert poisoning, however
|
||||
|
@ -416,7 +438,9 @@ mod tests {
|
|||
static O: Once = ONCE_INIT;
|
||||
|
||||
// poison the once
|
||||
let t = panic::catch_unwind(|| { O.call_once(|| panic!()); });
|
||||
let t = panic::catch_unwind(|| {
|
||||
O.call_once(|| panic!());
|
||||
});
|
||||
assert!(t.is_err());
|
||||
|
||||
// make sure someone's waiting inside the once via a force
|
||||
|
@ -435,7 +459,9 @@ mod tests {
|
|||
// put another waiter on the once
|
||||
let t2 = thread::spawn(|| {
|
||||
let mut called = false;
|
||||
O.call_once(|| { called = true; });
|
||||
O.call_once(|| {
|
||||
called = true;
|
||||
});
|
||||
assert!(!called);
|
||||
});
|
||||
|
||||
|
@ -443,6 +469,5 @@ mod tests {
|
|||
|
||||
assert!(t1.join().is_ok());
|
||||
assert!(t2.join().is_ok());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,20 @@
|
|||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
use std::sync::atomic::Ordering;
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::sync::atomic::{AtomicU8, Ordering};
|
||||
use std::sync::atomic::{ATOMIC_U8_INIT, AtomicU8};
|
||||
#[cfg(feature = "nightly")]
|
||||
type U8 = u8;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use stable::{AtomicU8, Ordering};
|
||||
use std::sync::atomic::AtomicUsize as AtomicU8;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use std::sync::atomic::ATOMIC_USIZE_INIT as ATOMIC_U8_INIT;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
type U8 = usize;
|
||||
use std::time::{Duration, Instant};
|
||||
use parking_lot_core::{self, ParkResult, UnparkResult, SpinWait, UnparkToken, DEFAULT_PARK_TOKEN};
|
||||
use parking_lot_core::{self, ParkResult, SpinWait, UnparkResult, UnparkToken, DEFAULT_PARK_TOKEN};
|
||||
use deadlock;
|
||||
|
||||
// UnparkToken used to indicate that that the target thread should attempt to
|
||||
// lock the mutex again as soon as it is unparked.
|
||||
|
@ -35,42 +39,59 @@ impl RawMutex {
|
|||
#[cfg(feature = "nightly")]
|
||||
#[inline]
|
||||
pub const fn new() -> RawMutex {
|
||||
RawMutex { state: AtomicU8::new(0) }
|
||||
RawMutex {
|
||||
state: ATOMIC_U8_INIT,
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
#[inline]
|
||||
pub fn new() -> RawMutex {
|
||||
RawMutex { state: AtomicU8::new(0) }
|
||||
RawMutex {
|
||||
state: ATOMIC_U8_INIT,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn lock(&self) {
|
||||
if self.state
|
||||
.compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
|
||||
.is_ok() {
|
||||
return;
|
||||
.is_err()
|
||||
{
|
||||
self.lock_slow(None);
|
||||
}
|
||||
self.lock_slow(None);
|
||||
unsafe { deadlock::acquire_resource(self as *const _ as usize) };
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_lock_until(&self, timeout: Instant) -> bool {
|
||||
if self.state
|
||||
let result = if self.state
|
||||
.compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
|
||||
.is_ok() {
|
||||
return true;
|
||||
.is_ok()
|
||||
{
|
||||
true
|
||||
} else {
|
||||
self.lock_slow(Some(timeout))
|
||||
};
|
||||
if result {
|
||||
unsafe { deadlock::acquire_resource(self as *const _ as usize) };
|
||||
}
|
||||
self.lock_slow(Some(timeout))
|
||||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_lock_for(&self, timeout: Duration) -> bool {
|
||||
if self.state
|
||||
let result = if self.state
|
||||
.compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
|
||||
.is_ok() {
|
||||
return true;
|
||||
.is_ok()
|
||||
{
|
||||
true
|
||||
} else {
|
||||
self.lock_slow(Some(Instant::now() + timeout))
|
||||
};
|
||||
if result {
|
||||
unsafe { deadlock::acquire_resource(self as *const _ as usize) };
|
||||
}
|
||||
self.lock_slow(Some(Instant::now() + timeout))
|
||||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -80,11 +101,16 @@ impl RawMutex {
|
|||
if state & LOCKED_BIT != 0 {
|
||||
return false;
|
||||
}
|
||||
match self.state.compare_exchange_weak(state,
|
||||
state | LOCKED_BIT,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed) {
|
||||
Ok(_) => return true,
|
||||
match self.state.compare_exchange_weak(
|
||||
state,
|
||||
state | LOCKED_BIT,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => {
|
||||
unsafe { deadlock::acquire_resource(self as *const _ as usize) };
|
||||
return true;
|
||||
}
|
||||
Err(x) => state = x,
|
||||
}
|
||||
}
|
||||
|
@ -92,9 +118,11 @@ impl RawMutex {
|
|||
|
||||
#[inline]
|
||||
pub fn unlock(&self, force_fair: bool) {
|
||||
unsafe { deadlock::release_resource(self as *const _ as usize) };
|
||||
if self.state
|
||||
.compare_exchange_weak(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
|
||||
.is_ok() {
|
||||
.is_ok()
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.unlock_slow(force_fair);
|
||||
|
@ -103,16 +131,18 @@ impl RawMutex {
|
|||
// Used by Condvar when requeuing threads to us, must be called while
|
||||
// holding the queue lock.
|
||||
#[inline]
|
||||
pub fn mark_parked_if_locked(&self) -> bool {
|
||||
pub(crate) fn mark_parked_if_locked(&self) -> bool {
|
||||
let mut state = self.state.load(Ordering::Relaxed);
|
||||
loop {
|
||||
if state & LOCKED_BIT == 0 {
|
||||
return false;
|
||||
}
|
||||
match self.state.compare_exchange_weak(state,
|
||||
state | PARKED_BIT,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Relaxed) {
|
||||
match self.state.compare_exchange_weak(
|
||||
state,
|
||||
state | PARKED_BIT,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => return true,
|
||||
Err(x) => state = x,
|
||||
}
|
||||
|
@ -122,7 +152,7 @@ impl RawMutex {
|
|||
// Used by Condvar when requeuing threads to us, must be called while
|
||||
// holding the queue lock.
|
||||
#[inline]
|
||||
pub fn mark_parked(&self) {
|
||||
pub(crate) fn mark_parked(&self) {
|
||||
self.state.fetch_or(PARKED_BIT, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
|
@ -134,11 +164,12 @@ impl RawMutex {
|
|||
loop {
|
||||
// Grab the lock if it isn't locked, even if there is a queue on it
|
||||
if state & LOCKED_BIT == 0 {
|
||||
match self.state
|
||||
.compare_exchange_weak(state,
|
||||
state | LOCKED_BIT,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed) {
|
||||
match self.state.compare_exchange_weak(
|
||||
state,
|
||||
state | LOCKED_BIT,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => return true,
|
||||
Err(x) => state = x,
|
||||
}
|
||||
|
@ -153,10 +184,12 @@ impl RawMutex {
|
|||
|
||||
// Set the parked bit
|
||||
if state & PARKED_BIT == 0 {
|
||||
if let Err(x) = self.state.compare_exchange_weak(state,
|
||||
state | PARKED_BIT,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Relaxed) {
|
||||
if let Err(x) = self.state.compare_exchange_weak(
|
||||
state,
|
||||
state | PARKED_BIT,
|
||||
Ordering::Relaxed,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
state = x;
|
||||
continue;
|
||||
}
|
||||
|
@ -173,12 +206,14 @@ impl RawMutex {
|
|||
self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed);
|
||||
}
|
||||
};
|
||||
match parking_lot_core::park(addr,
|
||||
validate,
|
||||
before_sleep,
|
||||
timed_out,
|
||||
DEFAULT_PARK_TOKEN,
|
||||
timeout) {
|
||||
match parking_lot_core::park(
|
||||
addr,
|
||||
validate,
|
||||
before_sleep,
|
||||
timed_out,
|
||||
DEFAULT_PARK_TOKEN,
|
||||
timeout,
|
||||
) {
|
||||
// The thread that unparked us passed the lock on to us
|
||||
// directly without unlocking it.
|
||||
ParkResult::Unparked(TOKEN_HANDOFF) => return true,
|
||||
|
@ -206,7 +241,8 @@ impl RawMutex {
|
|||
// Unlock directly if there are no parked threads
|
||||
if self.state
|
||||
.compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
|
||||
.is_ok() {
|
||||
.is_ok()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,20 +9,11 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||
use std::time::{Duration, Instant};
|
||||
use std::cell::Cell;
|
||||
use raw_mutex::RawMutex;
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
use thread_id;
|
||||
|
||||
// Helper function to get a thread id
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
fn get_thread_id() -> usize {
|
||||
thread_id::get()
|
||||
}
|
||||
#[cfg(target_os = "emscripten")]
|
||||
fn get_thread_id() -> usize {
|
||||
// pthread_self returns 0 on enscripten, but we use that as a
|
||||
// reserved value to indicate an empty slot. We instead fall
|
||||
// back to using the address of a thread-local variable, which
|
||||
// is slightly slower but guaranteed to produce a non-zero value.
|
||||
// The address of a thread-local variable is guaranteed to be unique to the
|
||||
// current thread, and is also guaranteed to be non-zero.
|
||||
thread_local!(static KEY: u8 = unsafe { ::std::mem::uninitialized() });
|
||||
KEY.with(|x| x as *const _ as usize)
|
||||
}
|
||||
|
@ -59,10 +50,12 @@ impl RawReentrantMutex {
|
|||
fn lock_internal<F: FnOnce() -> bool>(&self, try_lock: F) -> bool {
|
||||
let id = get_thread_id();
|
||||
if self.owner.load(Ordering::Relaxed) == id {
|
||||
self.lock_count.set(self.lock_count
|
||||
.get()
|
||||
.checked_add(1)
|
||||
.expect("ReentrantMutex lock count overflow"));
|
||||
self.lock_count.set(
|
||||
self.lock_count
|
||||
.get()
|
||||
.checked_add(1)
|
||||
.expect("ReentrantMutex lock count overflow"),
|
||||
);
|
||||
} else {
|
||||
if !try_lock() {
|
||||
return false;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -33,8 +33,8 @@ pub struct ReentrantMutex<T: ?Sized> {
|
|||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for ReentrantMutex<T> {}
|
||||
unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
|
||||
unsafe impl<T: ?Sized + Send> Send for ReentrantMutex<T> {}
|
||||
unsafe impl<T: ?Sized + Send> Sync for ReentrantMutex<T> {}
|
||||
|
||||
/// An RAII implementation of a "scoped lock" of a reentrant mutex. When this structure
|
||||
/// is dropped (falls out of scope), the lock will be unlocked.
|
||||
|
@ -43,13 +43,12 @@ unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
|
|||
/// `Deref` implementation.
|
||||
#[must_use]
|
||||
pub struct ReentrantMutexGuard<'a, T: ?Sized + 'a> {
|
||||
mutex: &'a ReentrantMutex<T>,
|
||||
|
||||
// The raw pointer here ensures that ReentrantMutexGuard is !Send
|
||||
marker: PhantomData<(&'a T, *mut ())>,
|
||||
raw: &'a RawReentrantMutex,
|
||||
data: *const T,
|
||||
marker: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: ?Sized + 'a + Sync> Sync for ReentrantMutexGuard<'a, T> {}
|
||||
unsafe impl<'a, T: ?Sized + Sync + 'a> Sync for ReentrantMutexGuard<'a, T> {}
|
||||
|
||||
impl<T> ReentrantMutex<T> {
|
||||
/// Creates a new reentrant mutex in an unlocked state ready for use.
|
||||
|
@ -80,6 +79,15 @@ impl<T> ReentrantMutex<T> {
|
|||
}
|
||||
|
||||
impl<T: ?Sized> ReentrantMutex<T> {
|
||||
#[inline]
|
||||
fn guard(&self) -> ReentrantMutexGuard<T> {
|
||||
ReentrantMutexGuard {
|
||||
raw: &self.raw,
|
||||
data: self.data.get(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires a reentrant mutex, blocking the current thread until it is able
|
||||
/// to do so.
|
||||
///
|
||||
|
@ -93,10 +101,7 @@ impl<T: ?Sized> ReentrantMutex<T> {
|
|||
#[inline]
|
||||
pub fn lock(&self) -> ReentrantMutexGuard<T> {
|
||||
self.raw.lock();
|
||||
ReentrantMutexGuard {
|
||||
mutex: self,
|
||||
marker: PhantomData,
|
||||
}
|
||||
self.guard()
|
||||
}
|
||||
|
||||
/// Attempts to acquire this lock.
|
||||
|
@ -109,10 +114,7 @@ impl<T: ?Sized> ReentrantMutex<T> {
|
|||
#[inline]
|
||||
pub fn try_lock(&self) -> Option<ReentrantMutexGuard<T>> {
|
||||
if self.raw.try_lock() {
|
||||
Some(ReentrantMutexGuard {
|
||||
mutex: self,
|
||||
marker: PhantomData,
|
||||
})
|
||||
Some(self.guard())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -126,10 +128,7 @@ impl<T: ?Sized> ReentrantMutex<T> {
|
|||
#[inline]
|
||||
pub fn try_lock_for(&self, timeout: Duration) -> Option<ReentrantMutexGuard<T>> {
|
||||
if self.raw.try_lock_for(timeout) {
|
||||
Some(ReentrantMutexGuard {
|
||||
mutex: self,
|
||||
marker: PhantomData,
|
||||
})
|
||||
Some(self.guard())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -143,10 +142,7 @@ impl<T: ?Sized> ReentrantMutex<T> {
|
|||
#[inline]
|
||||
pub fn try_lock_until(&self, timeout: Instant) -> Option<ReentrantMutexGuard<T>> {
|
||||
if self.raw.try_lock_until(timeout) {
|
||||
Some(ReentrantMutexGuard {
|
||||
mutex: self,
|
||||
marker: PhantomData,
|
||||
})
|
||||
Some(self.guard())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -239,23 +235,46 @@ impl<'a, T: ?Sized + 'a> ReentrantMutexGuard<'a, T> {
|
|||
/// using this method instead of dropping the `ReentrantMutexGuard` normally.
|
||||
#[inline]
|
||||
pub fn unlock_fair(self) {
|
||||
self.mutex.raw.unlock(true);
|
||||
self.raw.unlock(true);
|
||||
mem::forget(self);
|
||||
}
|
||||
|
||||
/// Make a new `ReentrantMutexGuard` for a component of the locked data.
|
||||
///
|
||||
/// This operation cannot fail as the `ReentrantMutexGuard` passed
|
||||
/// in already locked the mutex.
|
||||
///
|
||||
/// This is an associated function that needs to be
|
||||
/// used as `ReentrantMutexGuard::map(...)`. A method would interfere with
|
||||
/// methods of the same name on the contents of the locked data.
|
||||
#[inline]
|
||||
pub fn map<U: ?Sized, F>(orig: Self, f: F) -> ReentrantMutexGuard<'a, U>
|
||||
where
|
||||
F: FnOnce(&T) -> &U,
|
||||
{
|
||||
let raw = orig.raw;
|
||||
let data = f(unsafe { &*orig.data });
|
||||
mem::forget(orig);
|
||||
ReentrantMutexGuard {
|
||||
raw,
|
||||
data,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a> Deref for ReentrantMutexGuard<'a, T> {
|
||||
type Target = T;
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.mutex.data.get() }
|
||||
unsafe { &*self.data }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + 'a> Drop for ReentrantMutexGuard<'a, T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
self.mutex.raw.unlock(false);
|
||||
self.raw.unlock(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,10 +329,9 @@ mod tests {
|
|||
let _lock = m.try_lock();
|
||||
let _lock2 = m.try_lock();
|
||||
thread::spawn(move || {
|
||||
let lock = m2.try_lock();
|
||||
assert!(lock.is_none());
|
||||
})
|
||||
.join()
|
||||
let lock = m2.try_lock();
|
||||
assert!(lock.is_none());
|
||||
}).join()
|
||||
.unwrap();
|
||||
let _lock3 = m.try_lock();
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,77 +0,0 @@
|
|||
// Copyright 2016 Amanieu d'Antras
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::sync::atomic;
|
||||
|
||||
// Re-export this for convenience
|
||||
pub use std::sync::atomic::{Ordering, fence};
|
||||
|
||||
// Wrapper around AtomicUsize for non-nightly which has usable compare_exchange
|
||||
// and compare_exchange_weak methods.
|
||||
pub struct AtomicUsize(atomic::AtomicUsize);
|
||||
pub use self::AtomicUsize as AtomicU8;
|
||||
|
||||
// Constants for static initialization
|
||||
pub const ATOMIC_USIZE_INIT: AtomicUsize = AtomicUsize(atomic::ATOMIC_USIZE_INIT);
|
||||
pub use self::ATOMIC_USIZE_INIT as ATOMIC_U8_INIT;
|
||||
|
||||
impl AtomicUsize {
|
||||
#[inline]
|
||||
pub fn new(val: usize) -> AtomicUsize {
|
||||
AtomicUsize(atomic::AtomicUsize::new(val))
|
||||
}
|
||||
#[inline]
|
||||
pub fn load(&self, order: Ordering) -> usize {
|
||||
self.0.load(order)
|
||||
}
|
||||
#[inline]
|
||||
pub fn store(&self, val: usize, order: Ordering) {
|
||||
self.0.store(val, order);
|
||||
}
|
||||
#[inline]
|
||||
pub fn swap(&self, val: usize, order: Ordering) -> usize {
|
||||
self.0.swap(val, order)
|
||||
}
|
||||
#[inline]
|
||||
pub fn fetch_add(&self, val: usize, order: Ordering) -> usize {
|
||||
self.0.fetch_add(val, order)
|
||||
}
|
||||
#[inline]
|
||||
pub fn fetch_sub(&self, val: usize, order: Ordering) -> usize {
|
||||
self.0.fetch_sub(val, order)
|
||||
}
|
||||
#[inline]
|
||||
pub fn fetch_and(&self, val: usize, order: Ordering) -> usize {
|
||||
self.0.fetch_and(val, order)
|
||||
}
|
||||
#[inline]
|
||||
pub fn fetch_or(&self, val: usize, order: Ordering) -> usize {
|
||||
self.0.fetch_or(val, order)
|
||||
}
|
||||
#[inline]
|
||||
pub fn compare_exchange(&self,
|
||||
old: usize,
|
||||
new: usize,
|
||||
order: Ordering,
|
||||
_: Ordering)
|
||||
-> Result<usize, usize> {
|
||||
let res = self.0.compare_and_swap(old, new, order);
|
||||
if res == old { Ok(res) } else { Err(res) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn compare_exchange_weak(&self,
|
||||
old: usize,
|
||||
new: usize,
|
||||
order: Ordering,
|
||||
_: Ordering)
|
||||
-> Result<usize, usize> {
|
||||
let res = self.0.compare_and_swap(old, new, order);
|
||||
if res == old { Ok(res) } else { Err(res) }
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
environment:
|
||||
matrix:
|
||||
- target: 1.8.0-x86_64-pc-windows-msvc
|
||||
- target: 1.8.0-i686-pc-windows-msvc
|
||||
- target: 1.9.0-x86_64-pc-windows-msvc
|
||||
- target: 1.9.0-i686-pc-windows-msvc
|
||||
- target: 1.10.0-x86_64-pc-windows-msvc
|
||||
- target: 1.10.0-i686-pc-windows-msvc
|
||||
- target: 1.11.0-x86_64-pc-windows-msvc
|
||||
- target: 1.11.0-i686-pc-windows-msvc
|
||||
- target: 1.12.0-x86_64-pc-windows-msvc
|
||||
- target: 1.12.0-i686-pc-windows-msvc
|
||||
- target: 1.13.0-x86_64-pc-windows-msvc
|
||||
- target: 1.13.0-i686-pc-windows-msvc
|
||||
- target: 1.14.0-x86_64-pc-windows-msvc
|
||||
- target: 1.14.0-i686-pc-windows-msvc
|
||||
- target: 1.15.1-x86_64-pc-windows-msvc
|
||||
- target: 1.15.1-i686-pc-windows-msvc
|
||||
- target: 1.16.0-x86_64-pc-windows-msvc
|
||||
- target: 1.16.0-i686-pc-windows-msvc
|
||||
- target: 1.17.0-x86_64-pc-windows-msvc
|
||||
- target: 1.17.0-i686-pc-windows-msvc
|
||||
- target: beta-x86_64-pc-windows-msvc
|
||||
- target: beta-i686-pc-windows-msvc
|
||||
- target: beta-x86_64-pc-windows-gnu
|
||||
- target: beta-i686-pc-windows-gnu
|
||||
- target: nightly-x86_64-pc-windows-msvc
|
||||
- target: nightly-i686-pc-windows-msvc
|
||||
- target: nightly-x86_64-pc-windows-gnu
|
||||
- target: nightly-i686-pc-windows-gnu
|
||||
|
||||
install:
|
||||
# Download the Rust and Cargo installer.
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:target}.msi"
|
||||
|
||||
# Install Rust and Cargo and wait for installation to finish by using Write-Output.
|
||||
- ps: msiexec /package "rust-${env:target}.msi" /quiet /norestart | Write-Output
|
||||
|
||||
# Pick up the new Path variable after the installer modified it.
|
||||
- ps: $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine")
|
||||
|
||||
# Print versions for future reference.
|
||||
- rustc --version
|
||||
- cargo --version
|
||||
|
||||
build_script:
|
||||
- cargo build
|
||||
|
||||
test_script:
|
||||
- cargo test
|
|
@ -1 +0,0 @@
|
|||
{"files":{".appveyor.yml":"86b8a7bf3ff316a2d8c58ba1fc365c5773c926ee3e4abccf889a95e5ec4f393a",".travis.yml":"731fd15b3f516c8da8241d2c5e7a56e638f0295f637d448fb009131092792264","Cargo.toml":"fbe4f546589b570dff000201397c059cc16a5807211a436c17f03aade65690ff","changelog.md":"71ecf0389739517ce6e84fc230f1b42f7532c545c0690fbcff270c83012f0d30","license-apache":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","license-mit":"69a1ca9eaf8e5276eade8931f42808d7c39c6a26011e34450c4ebb10f11c653f","readme.md":"2dc47b0ce86bb82f007639782c12ba9376be7d31635ba5cdf7cc828e27a9ba54","src/lib.rs":"214ad7a56dd4715387bbdbe91e53cd93f49fedc88f4c818b4e52378b71d98232"},"package":"8df7875b676fddfadffd96deea3b1124e5ede707d4884248931077518cf1f773"}
|
|
@ -1,15 +0,0 @@
|
|||
language: rust
|
||||
|
||||
rust:
|
||||
- 1.8.0
|
||||
- 1.9.0
|
||||
- 1.10.0
|
||||
- 1.11.0
|
||||
- 1.12.0
|
||||
- 1.13.0
|
||||
- 1.14.0
|
||||
- 1.15.1
|
||||
- 1.16.0
|
||||
- 1.17.0
|
||||
- beta
|
||||
- nightly
|
|
@ -1,16 +0,0 @@
|
|||
[package]
|
||||
name = "thread-id"
|
||||
version = "3.1.0"
|
||||
authors = ["Ruud van Asseldonk <dev@veniogames.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
readme = "readme.md"
|
||||
keywords = ["thread", "pthread", "getcurrentthreadid"]
|
||||
description = "Get a unique thread ID"
|
||||
repository = "https://github.com/ruuda/thread-id"
|
||||
documentation = "https://docs.rs/thread-id"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2.6"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
kernel32-sys = "0.2.1"
|
|
@ -1,30 +0,0 @@
|
|||
# v3.1.0
|
||||
|
||||
Released 2017-05-13.
|
||||
|
||||
* Add the MIT license as an alternative to the Apache 2.0 license. This license
|
||||
change applies retroactively to all versions, this is only a metadata change.
|
||||
|
||||
# v3.0.0
|
||||
|
||||
Released 2016-10-29.
|
||||
|
||||
* Depend on libc only on Unix-like environments, and on kernel32-sys only
|
||||
on Windows. This requires Rust 1.8 or later, hence the major version
|
||||
bump.
|
||||
|
||||
# v2.0.0
|
||||
|
||||
Released 2016-04-09.
|
||||
|
||||
* Change ID type to `usize` to better reflect the underlying platform IDs.
|
||||
This is a breaking change.
|
||||
* Allow functions to be inlined to avoid call overhead.
|
||||
|
||||
Many thanks to Amanieu d'Antras for contributing to this release.
|
||||
|
||||
# v1.0.0
|
||||
|
||||
Released 2016-03-13.
|
||||
|
||||
Initial release with Windows and Linux support.
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,19 +0,0 @@
|
|||
Copyright 2017 Ruud van Asseldonk
|
||||
|
||||
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.
|
|
@ -1,53 +0,0 @@
|
|||
Thread-ID
|
||||
=========
|
||||
Get a unique ID for the current thread in Rust.
|
||||
|
||||
[![Build Status][tr-img]][tr]
|
||||
[![Build Status][av-img]][av]
|
||||
[![Crates.io version][crate-img]][crate]
|
||||
[![Documentation][docs-img]][docs]
|
||||
|
||||
For diagnostics and debugging it can often be useful to get an ID that is
|
||||
different for every thread. [Until Rust 1.14][stdlib-pr], the standard library
|
||||
did not expose a way to do that, hence this crate.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
use thread_id;
|
||||
|
||||
thread::spawn(move || {
|
||||
println!("spawned thread has id {}", thread_id::get());
|
||||
});
|
||||
|
||||
println!("main thread has id {}", thread_id::get());
|
||||
```
|
||||
|
||||
This will print two different numbers.
|
||||
|
||||
License
|
||||
-------
|
||||
Thread-ID is licensed under either the [Apache 2.0 license][apache2], or the
|
||||
[MIT license][mit], at your option. It may be used in free software as well as
|
||||
closed-source applications, both for commercial and non-commercial use under the
|
||||
conditions given in the license.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache 2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
|
||||
[tr-img]: https://travis-ci.org/ruuda/thread-id.svg?branch=master
|
||||
[tr]: https://travis-ci.org/ruuda/thread-id
|
||||
[av-img]: https://ci.appveyor.com/api/projects/status/a6ccbm3x4fgi6wku?svg=true
|
||||
[av]: https://ci.appveyor.com/project/ruuda/thread-id
|
||||
[crate-img]: https://img.shields.io/crates/v/thread-id.svg
|
||||
[crate]: https://crates.io/crates/thread-id
|
||||
[docs-img]: https://img.shields.io/badge/docs-online-blue.svg
|
||||
[docs]: https://docs.rs/thread-id
|
||||
[stdlib-pr]: https://github.com/rust-lang/rust/pull/36341
|
||||
[apache2]: https://www.apache.org/licenses/LICENSE-2.0
|
||||
[mit]: https://opensource.org/licenses/MIT
|
|
@ -1,67 +0,0 @@
|
|||
// Thread-ID -- Get a unique thread ID
|
||||
// Copyright 2016 Ruud van Asseldonk
|
||||
//
|
||||
// Licensed under either the Apache License, Version 2.0, or the MIT license, at
|
||||
// your option. A copy of both licenses has been included in the root of the
|
||||
// repository.
|
||||
|
||||
//! Thread-ID: get a unique ID for the current thread.
|
||||
//!
|
||||
//! For diagnostics and debugging it can often be useful to get an ID that is
|
||||
//! different for every thread. This crate provides that functionality.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use std::thread;
|
||||
//! use thread_id;
|
||||
//!
|
||||
//! thread::spawn(move || {
|
||||
//! println!("spawned thread has id {}", thread_id::get());
|
||||
//! });
|
||||
//!
|
||||
//! println!("main thread has id {}", thread_id::get());
|
||||
//! ```
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#[cfg(unix)]
|
||||
extern crate libc;
|
||||
|
||||
#[cfg(windows)]
|
||||
extern crate kernel32;
|
||||
|
||||
/// Returns a number that is unique to the calling thread.
|
||||
///
|
||||
/// Calling this function twice from the same thread will return the same
|
||||
/// number. Calling this function from a different thread will return a
|
||||
/// different number.
|
||||
#[inline]
|
||||
pub fn get() -> usize {
|
||||
get_internal()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[inline]
|
||||
fn get_internal() -> usize {
|
||||
unsafe { libc::pthread_self() as usize }
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[inline]
|
||||
fn get_internal() -> usize {
|
||||
unsafe { kernel32::GetCurrentThreadId() as usize }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn distinct_threads_have_distinct_ids() {
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
thread::spawn(move || tx.send(::get()).unwrap()).join().unwrap();
|
||||
|
||||
let main_tid = ::get();
|
||||
let other_tid = rx.recv().unwrap();
|
||||
assert!(main_tid != other_tid);
|
||||
}
|
Загрузка…
Ссылка в новой задаче