mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-11 16:32:59 +00:00
Bug 1424081 - Update parking_lot_core Rust crate to 0.2.7 r=SimonSapin
MozReview-Commit-ID: G8C94Vt2RVx --HG-- extra : rebase_source : e13d4b40761171a16fd99d29fccabe5c5d942d58
This commit is contained in:
parent
53c3b17b09
commit
7f726d3cbb
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"0fbc0225f4a4220fa4e6390f5fd889f1739ae67fd6144baf8698f601f65632e4","src/lib.rs":"76b3e0b8c7c5931e71f2f563ca629b3b1a668a195ea454104537e39c4a43d8da","src/parking_lot.rs":"b451509ab016630edb5d17aafd6b0de1011663e2fe6e1b8c71361fe6f877fc98","src/spinwait.rs":"682e5a3fc71d1d7a7d8da377d1d93415fa64b4f53809bd80bbf2942628e3a23d","src/stable.rs":"cc18c58404dc6017924d88fb9f4ed94e5320b8cb0a36985162b23130b8cd7480","src/thread_parker/generic.rs":"041c56505851c0f2f68f250cb74851a198ea15e86d0b4fc2f8065fd024b9dc7b","src/thread_parker/linux.rs":"0a3c63a8cba192827edb55dd785ccab22229370ad2bc4b52e81cc25c1fb63696","src/thread_parker/unix.rs":"64d18bf39ebe13e08a43d641ec3c9e66048663b4fd0bae1af555375cf735f7fd","src/thread_parker/windows/keyed_event.rs":"ceea3746ae04f59f86a6ccddde651cbbf8a203eb53a9e83349dfb5159eca4d88","src/thread_parker/windows/mod.rs":"d0caa762effeba24a5d866be812d8b1e8e076394142cdde5ef873a1247e867d9","src/thread_parker/windows/waitaddress.rs":"7f280d3c60bc4290b5bf30bc9740322cc0723742cfce58dcfcbfe4058e32d3a0","src/util.rs":"2d07c0c010a857790ae2ed6a1215eeed8af76859e076797ea1ba8dec82169e84","src/word_lock.rs":"c33355107175d58f16fc6814cbd7792d2b9d92deae8311baf4306542c35c9853"},"package":"a25dd36576d01cca115881dc920b1f0dd0037303ed8cfa0c5d0a4966151757f7"}
|
||||
{"files":{"Cargo.toml":"c8a7070b6801c4cc9f410d45819dab3c6efcbe77806a617415289d8de0fbb01b","src/lib.rs":"932b67d85b4176bfb1d7a78b70ec5dd356839158dad22d2e932b88be30925572","src/parking_lot.rs":"aabffbdf465648a1066b24e88c74fbff9cef636354e0bfdd125937f61d771449","src/spinwait.rs":"5aee4a6e8d33eec1b6a81b21ff3b223460d8fa2d37e633b31b8ca27fabe659cb","src/stable.rs":"4562ea9a408bd3917df6d30c8354bf51f46bc69b3360815813730743204adfdc","src/thread_parker/generic.rs":"0c30db3d1c96bd5ef284a4761a829aba8d21fc813b3d1d70b2baf5f00744e006","src/thread_parker/linux.rs":"4e0a142ce3ff59d37e5c452bf57b3481ef00274e8e489ac1a1d11b2f31b473ed","src/thread_parker/unix.rs":"ff5a543f21895c8114bd4f89b5764882beab1f3a37ddbd8fc31c783e1db3f1c1","src/thread_parker/windows/keyed_event.rs":"b54b0855b10ed2c188ce42094c6e4069e92e325f870d0c0f8244bfe2d7811b66","src/thread_parker/windows/mod.rs":"dc5359b10275a4aaee04024c202b115d267e4ea15917546b042c4035c0218136","src/thread_parker/windows/waitaddress.rs":"2da78bfe09e4262a6cd6271d6416a9debdb3fd3abb1993be1c68515952576874","src/util.rs":"2d07c0c010a857790ae2ed6a1215eeed8af76859e076797ea1ba8dec82169e84","src/word_lock.rs":"6ab156a775c46423bbb7dae520f181dde1747140d52ba995850969498559c7b2"},"package":"6c677d78851950b3aec390e681a411f78cc250cba277d4f578758a377f727970"}
|
23
third_party/rust/parking_lot_core/Cargo.toml
vendored
23
third_party/rust/parking_lot_core/Cargo.toml
vendored
@ -12,25 +12,38 @@
|
||||
|
||||
[package]
|
||||
name = "parking_lot_core"
|
||||
version = "0.2.4"
|
||||
version = "0.2.7"
|
||||
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
|
||||
description = "An advanced API for creating custom synchronization primitives."
|
||||
documentation = "https://amanieu.github.io/parking_lot/parking_lot_core/index.html"
|
||||
keywords = ["mutex", "condvar", "rwlock", "once", "thread"]
|
||||
license = "Apache-2.0/MIT"
|
||||
repository = "https://github.com/Amanieu/parking_lot"
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.petgraph]
|
||||
version = "0.4.5"
|
||||
optional = true
|
||||
|
||||
[dependencies.rand]
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.smallvec]
|
||||
version = "0.4"
|
||||
version = "0.6"
|
||||
|
||||
[dependencies.thread-id]
|
||||
version = "3.2.0"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
deadlock_detection = ["petgraph", "thread-id", "backtrace"]
|
||||
nightly = []
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2.15"
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.2"
|
||||
|
||||
[target."cfg(windows)".dependencies.kernel32-sys]
|
||||
version = "0.2"
|
||||
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.2"
|
||||
|
20
third_party/rust/parking_lot_core/src/lib.rs
vendored
20
third_party/rust/parking_lot_core/src/lib.rs
vendored
@ -41,16 +41,23 @@
|
||||
#![cfg_attr(all(feature = "nightly", target_os = "linux"), feature(integer_atomics))]
|
||||
#![cfg_attr(feature = "nightly", feature(asm))]
|
||||
|
||||
extern crate smallvec;
|
||||
extern crate rand;
|
||||
extern crate smallvec;
|
||||
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
extern crate backtrace;
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
extern crate petgraph;
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
extern crate thread_id;
|
||||
|
||||
#[cfg(unix)]
|
||||
extern crate libc;
|
||||
|
||||
#[cfg(windows)]
|
||||
extern crate winapi;
|
||||
#[cfg(windows)]
|
||||
extern crate kernel32;
|
||||
#[cfg(windows)]
|
||||
extern crate winapi;
|
||||
|
||||
#[cfg(all(feature = "nightly", target_os = "linux"))]
|
||||
#[path = "thread_parker/linux.rs"]
|
||||
@ -73,7 +80,8 @@ mod spinwait;
|
||||
mod word_lock;
|
||||
mod parking_lot;
|
||||
|
||||
pub use parking_lot::{ParkResult, UnparkResult, RequeueOp, UnparkToken, ParkToken, FilterOp};
|
||||
pub use parking_lot::{DEFAULT_UNPARK_TOKEN, DEFAULT_PARK_TOKEN};
|
||||
pub use parking_lot::{park, unpark_one, unpark_all, unpark_requeue, unpark_filter};
|
||||
pub use parking_lot::{FilterOp, ParkResult, ParkToken, RequeueOp, UnparkResult, UnparkToken};
|
||||
pub use parking_lot::{DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN};
|
||||
pub use parking_lot::{park, unpark_all, unpark_filter, unpark_one, unpark_requeue};
|
||||
pub use spinwait::SpinWait;
|
||||
pub use parking_lot::deadlock;
|
||||
|
481
third_party/rust/parking_lot_core/src/parking_lot.rs
vendored
481
third_party/rust/parking_lot_core/src/parking_lot.rs
vendored
@ -6,10 +6,10 @@
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use stable::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
use std::time::{Instant, Duration};
|
||||
use stable::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
@ -17,7 +17,7 @@ use std::thread::LocalKey;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use std::panic;
|
||||
use smallvec::SmallVec;
|
||||
use rand::{self, XorShiftRng, Rng};
|
||||
use rand::{self, Rng, XorShiftRng};
|
||||
use thread_parker::ThreadParker;
|
||||
use word_lock::WordLock;
|
||||
use util::UncheckedOptionExt;
|
||||
@ -132,6 +132,13 @@ struct ThreadData {
|
||||
|
||||
// ParkToken value set by the thread when it was parked
|
||||
park_token: Cell<ParkToken>,
|
||||
|
||||
// Is the thread parked with a timeout?
|
||||
parked_with_timeout: Cell<bool>,
|
||||
|
||||
// Extra data for deadlock detection
|
||||
// TODO: once supported in stable replace with #[cfg...] & remove dummy struct/impl
|
||||
#[allow(dead_code)] deadlock_data: deadlock::DeadlockData,
|
||||
}
|
||||
|
||||
impl ThreadData {
|
||||
@ -149,6 +156,8 @@ impl ThreadData {
|
||||
next_in_queue: Cell::new(ptr::null()),
|
||||
unpark_token: Cell::new(DEFAULT_UNPARK_TOKEN),
|
||||
park_token: Cell::new(DEFAULT_PARK_TOKEN),
|
||||
parked_with_timeout: Cell::new(false),
|
||||
deadlock_data: deadlock::DeadlockData::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -194,10 +203,12 @@ unsafe fn get_hashtable() -> *const HashTable {
|
||||
|
||||
// If this fails then it means some other thread created the hash
|
||||
// table first.
|
||||
match HASHTABLE.compare_exchange(0,
|
||||
new_table as usize,
|
||||
Ordering::Release,
|
||||
Ordering::Relaxed) {
|
||||
match HASHTABLE.compare_exchange(
|
||||
0,
|
||||
new_table as usize,
|
||||
Ordering::Release,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => return new_table,
|
||||
Err(x) => table = x,
|
||||
}
|
||||
@ -219,8 +230,10 @@ unsafe fn grow_hashtable(num_threads: usize) {
|
||||
|
||||
// If this fails then it means some other thread created the hash
|
||||
// table first.
|
||||
if HASHTABLE.compare_exchange(0, new_table as usize, Ordering::Release, Ordering::Relaxed)
|
||||
.is_ok() {
|
||||
if HASHTABLE
|
||||
.compare_exchange(0, new_table as usize, Ordering::Release, Ordering::Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@ -267,7 +280,9 @@ unsafe fn grow_hashtable(num_threads: usize) {
|
||||
if new_table.entries[hash].queue_tail.get().is_null() {
|
||||
new_table.entries[hash].queue_head.set(current);
|
||||
} else {
|
||||
(*new_table.entries[hash].queue_tail.get()).next_in_queue.set(current);
|
||||
(*new_table.entries[hash].queue_tail.get())
|
||||
.next_in_queue
|
||||
.set(current);
|
||||
}
|
||||
new_table.entries[hash].queue_tail.set(current);
|
||||
(*current).next_in_queue.set(ptr::null());
|
||||
@ -336,8 +351,9 @@ unsafe fn lock_bucket_checked<'a>(key: &AtomicUsize) -> (usize, &'a Bucket) {
|
||||
// Check that both the hash table and key are correct while the bucket
|
||||
// is locked. Note that the key can't change once we locked the proper
|
||||
// bucket for it, so we just keep trying until we have the correct key.
|
||||
if HASHTABLE.load(Ordering::Relaxed) == hashtable as usize &&
|
||||
key.load(Ordering::Relaxed) == current_key {
|
||||
if HASHTABLE.load(Ordering::Relaxed) == hashtable as usize
|
||||
&& key.load(Ordering::Relaxed) == current_key
|
||||
{
|
||||
return (current_key, bucket);
|
||||
}
|
||||
|
||||
@ -508,36 +524,41 @@ pub const DEFAULT_PARK_TOKEN: ParkToken = ParkToken(0);
|
||||
/// to call `unpark_one`, `unpark_all`, `unpark_requeue` or `unpark_filter`, but
|
||||
/// it is not allowed to call `park` or panic.
|
||||
#[inline]
|
||||
pub unsafe fn park<V, B, T>(key: usize,
|
||||
validate: V,
|
||||
before_sleep: B,
|
||||
timed_out: T,
|
||||
park_token: ParkToken,
|
||||
timeout: Option<Instant>)
|
||||
-> ParkResult
|
||||
where V: FnOnce() -> bool,
|
||||
B: FnOnce(),
|
||||
T: FnOnce(usize, bool)
|
||||
pub unsafe fn park<V, B, T>(
|
||||
key: usize,
|
||||
validate: V,
|
||||
before_sleep: B,
|
||||
timed_out: T,
|
||||
park_token: ParkToken,
|
||||
timeout: Option<Instant>,
|
||||
) -> ParkResult
|
||||
where
|
||||
V: FnOnce() -> bool,
|
||||
B: FnOnce(),
|
||||
T: FnOnce(usize, bool),
|
||||
{
|
||||
let mut v = Some(validate);
|
||||
let mut b = Some(before_sleep);
|
||||
let mut t = Some(timed_out);
|
||||
park_internal(key,
|
||||
&mut || v.take().unchecked_unwrap()(),
|
||||
&mut || b.take().unchecked_unwrap()(),
|
||||
&mut |key, was_last_thread| t.take().unchecked_unwrap()(key, was_last_thread),
|
||||
park_token,
|
||||
timeout)
|
||||
park_internal(
|
||||
key,
|
||||
&mut || v.take().unchecked_unwrap()(),
|
||||
&mut || b.take().unchecked_unwrap()(),
|
||||
&mut |key, was_last_thread| t.take().unchecked_unwrap()(key, was_last_thread),
|
||||
park_token,
|
||||
timeout,
|
||||
)
|
||||
}
|
||||
|
||||
// Non-generic version to reduce monomorphization cost
|
||||
unsafe fn park_internal(key: usize,
|
||||
validate: &mut FnMut() -> bool,
|
||||
before_sleep: &mut FnMut(),
|
||||
timed_out: &mut FnMut(usize, bool),
|
||||
park_token: ParkToken,
|
||||
timeout: Option<Instant>)
|
||||
-> ParkResult {
|
||||
unsafe fn park_internal(
|
||||
key: usize,
|
||||
validate: &mut FnMut() -> bool,
|
||||
before_sleep: &mut FnMut(),
|
||||
timed_out: &mut FnMut(usize, bool),
|
||||
park_token: ParkToken,
|
||||
timeout: Option<Instant>,
|
||||
) -> ParkResult {
|
||||
// Grab our thread data, this also ensures that the hash table exists
|
||||
let mut thread_data = None;
|
||||
let thread_data = get_thread_data(&mut thread_data);
|
||||
@ -552,6 +573,7 @@ unsafe fn park_internal(key: usize,
|
||||
}
|
||||
|
||||
// Append our thread data to the queue and unlock the bucket
|
||||
thread_data.parked_with_timeout.set(timeout.is_some());
|
||||
thread_data.next_in_queue.set(ptr::null());
|
||||
thread_data.key.store(key, Ordering::Relaxed);
|
||||
thread_data.park_token.set(park_token);
|
||||
@ -574,6 +596,8 @@ unsafe fn park_internal(key: usize,
|
||||
Some(timeout) => thread_data.parker.park_until(timeout),
|
||||
None => {
|
||||
thread_data.parker.park();
|
||||
// call deadlock detection on_unpark hook
|
||||
deadlock::on_unpark(thread_data);
|
||||
true
|
||||
}
|
||||
};
|
||||
@ -659,16 +683,18 @@ unsafe fn park_internal(key: usize,
|
||||
/// panic or call into any function in `parking_lot`.
|
||||
#[inline]
|
||||
pub unsafe fn unpark_one<C>(key: usize, callback: C) -> UnparkResult
|
||||
where C: FnOnce(UnparkResult) -> UnparkToken
|
||||
where
|
||||
C: FnOnce(UnparkResult) -> UnparkToken,
|
||||
{
|
||||
let mut c = Some(callback);
|
||||
unpark_one_internal(key, &mut |result| c.take().unchecked_unwrap()(result))
|
||||
}
|
||||
|
||||
// Non-generic version to reduce monomorphization cost
|
||||
unsafe fn unpark_one_internal(key: usize,
|
||||
callback: &mut FnMut(UnparkResult) -> UnparkToken)
|
||||
-> UnparkResult {
|
||||
unsafe fn unpark_one_internal(
|
||||
key: usize,
|
||||
callback: &mut FnMut(UnparkResult) -> UnparkToken,
|
||||
) -> UnparkResult {
|
||||
// Lock the bucket for the given key
|
||||
let bucket = lock_bucket(key);
|
||||
|
||||
@ -818,28 +844,33 @@ pub unsafe fn unpark_all(key: usize, unpark_token: UnparkToken) -> usize {
|
||||
/// The `validate` and `callback` functions are called while the queue is locked
|
||||
/// and must not panic or call into any function in `parking_lot`.
|
||||
#[inline]
|
||||
pub unsafe fn unpark_requeue<V, C>(key_from: usize,
|
||||
key_to: usize,
|
||||
validate: V,
|
||||
callback: C)
|
||||
-> UnparkResult
|
||||
where V: FnOnce() -> RequeueOp,
|
||||
C: FnOnce(RequeueOp, UnparkResult) -> UnparkToken
|
||||
pub unsafe fn unpark_requeue<V, C>(
|
||||
key_from: usize,
|
||||
key_to: usize,
|
||||
validate: V,
|
||||
callback: C,
|
||||
) -> UnparkResult
|
||||
where
|
||||
V: FnOnce() -> RequeueOp,
|
||||
C: FnOnce(RequeueOp, UnparkResult) -> UnparkToken,
|
||||
{
|
||||
let mut v = Some(validate);
|
||||
let mut c = Some(callback);
|
||||
unpark_requeue_internal(key_from,
|
||||
key_to,
|
||||
&mut || v.take().unchecked_unwrap()(),
|
||||
&mut |op, r| c.take().unchecked_unwrap()(op, r))
|
||||
unpark_requeue_internal(
|
||||
key_from,
|
||||
key_to,
|
||||
&mut || v.take().unchecked_unwrap()(),
|
||||
&mut |op, r| c.take().unchecked_unwrap()(op, r),
|
||||
)
|
||||
}
|
||||
|
||||
// Non-generic version to reduce monomorphization cost
|
||||
unsafe fn unpark_requeue_internal(key_from: usize,
|
||||
key_to: usize,
|
||||
validate: &mut FnMut() -> RequeueOp,
|
||||
callback: &mut FnMut(RequeueOp, UnparkResult) -> UnparkToken)
|
||||
-> UnparkResult {
|
||||
unsafe fn unpark_requeue_internal(
|
||||
key_from: usize,
|
||||
key_to: usize,
|
||||
validate: &mut FnMut() -> RequeueOp,
|
||||
callback: &mut FnMut(RequeueOp, UnparkResult) -> UnparkToken,
|
||||
) -> UnparkResult {
|
||||
// Lock the two buckets for the given key
|
||||
let (bucket_from, bucket_to) = lock_bucket_pair(key_from, key_to);
|
||||
|
||||
@ -897,7 +928,9 @@ unsafe fn unpark_requeue_internal(key_from: usize,
|
||||
if !requeue_threads.is_null() {
|
||||
(*requeue_threads_tail).next_in_queue.set(ptr::null());
|
||||
if !bucket_to.queue_head.get().is_null() {
|
||||
(*bucket_to.queue_tail.get()).next_in_queue.set(requeue_threads);
|
||||
(*bucket_to.queue_tail.get())
|
||||
.next_in_queue
|
||||
.set(requeue_threads);
|
||||
} else {
|
||||
bucket_to.queue_head.set(requeue_threads);
|
||||
}
|
||||
@ -951,18 +984,20 @@ unsafe fn unpark_requeue_internal(key_from: usize,
|
||||
/// and must not panic or call into any function in `parking_lot`.
|
||||
#[inline]
|
||||
pub unsafe fn unpark_filter<F, C>(key: usize, mut filter: F, callback: C) -> UnparkResult
|
||||
where F: FnMut(ParkToken) -> FilterOp,
|
||||
C: FnOnce(UnparkResult) -> UnparkToken
|
||||
where
|
||||
F: FnMut(ParkToken) -> FilterOp,
|
||||
C: FnOnce(UnparkResult) -> UnparkToken,
|
||||
{
|
||||
let mut c = Some(callback);
|
||||
unpark_filter_internal(key, &mut filter, &mut |r| c.take().unchecked_unwrap()(r))
|
||||
}
|
||||
|
||||
// Non-generic version to reduce monomorphization cost
|
||||
unsafe fn unpark_filter_internal(key: usize,
|
||||
filter: &mut FnMut(ParkToken) -> FilterOp,
|
||||
callback: &mut FnMut(UnparkResult) -> UnparkToken)
|
||||
-> UnparkResult {
|
||||
unsafe fn unpark_filter_internal(
|
||||
key: usize,
|
||||
filter: &mut FnMut(ParkToken) -> FilterOp,
|
||||
callback: &mut FnMut(UnparkResult) -> UnparkToken,
|
||||
) -> UnparkResult {
|
||||
// Lock the bucket for the given key
|
||||
let bucket = lock_bucket(key);
|
||||
|
||||
@ -1035,3 +1070,323 @@ unsafe fn unpark_filter_internal(key: usize,
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// [Experimental] Deadlock detection
|
||||
///
|
||||
/// Enabled via the `deadlock_detection` feature flag.
|
||||
pub mod deadlock {
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
use super::deadlock_impl;
|
||||
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
pub(super) use super::deadlock_impl::DeadlockData;
|
||||
|
||||
#[cfg(not(feature = "deadlock_detection"))]
|
||||
pub(super) struct DeadlockData {}
|
||||
|
||||
#[cfg(not(feature = "deadlock_detection"))]
|
||||
impl DeadlockData {
|
||||
pub(super) fn new() -> Self {
|
||||
DeadlockData {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquire a resource identified by key in the deadlock detector
|
||||
/// Noop if deadlock_detection feature isn't enabled.
|
||||
/// Note: Call after the resource is acquired
|
||||
#[inline]
|
||||
pub unsafe fn acquire_resource(_key: usize) {
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
deadlock_impl::acquire_resource(_key);
|
||||
}
|
||||
|
||||
/// Release a resource identified by key in the deadlock detector.
|
||||
/// Noop if deadlock_detection feature isn't enabled.
|
||||
/// Note: Call before the resource is released
|
||||
/// # Panics
|
||||
/// Panics if the resource was already released or wasn't acquired in this thread.
|
||||
#[inline]
|
||||
pub unsafe fn release_resource(_key: usize) {
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
deadlock_impl::release_resource(_key);
|
||||
}
|
||||
|
||||
/// Returns all deadlocks detected *since* the last call.
|
||||
/// Each cycle consist of a vector of `DeadlockedThread`.
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
#[inline]
|
||||
pub fn check_deadlock() -> Vec<Vec<deadlock_impl::DeadlockedThread>> {
|
||||
deadlock_impl::check_deadlock()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) unsafe fn on_unpark(_td: &super::ThreadData) {
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
deadlock_impl::on_unpark(_td);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
mod deadlock_impl {
|
||||
use super::{get_hashtable, get_thread_data, lock_bucket, ThreadData, NUM_THREADS};
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::collections::HashSet;
|
||||
use thread_id;
|
||||
use backtrace::Backtrace;
|
||||
use petgraph;
|
||||
use petgraph::graphmap::DiGraphMap;
|
||||
|
||||
/// Representation of a deadlocked thread
|
||||
pub struct DeadlockedThread {
|
||||
thread_id: usize,
|
||||
backtrace: Backtrace,
|
||||
}
|
||||
|
||||
impl DeadlockedThread {
|
||||
/// The system thread id
|
||||
pub fn thread_id(&self) -> usize {
|
||||
self.thread_id
|
||||
}
|
||||
|
||||
/// The thread backtrace
|
||||
pub fn backtrace(&self) -> &Backtrace {
|
||||
&self.backtrace
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DeadlockData {
|
||||
// Currently owned resources (keys)
|
||||
resources: UnsafeCell<Vec<usize>>,
|
||||
|
||||
// Set when there's a pending callstack request
|
||||
deadlocked: Cell<bool>,
|
||||
|
||||
// Sender used to report the backtrace
|
||||
backtrace_sender: UnsafeCell<Option<mpsc::Sender<DeadlockedThread>>>,
|
||||
|
||||
// System thread id
|
||||
thread_id: usize,
|
||||
}
|
||||
|
||||
impl DeadlockData {
|
||||
pub fn new() -> Self {
|
||||
DeadlockData {
|
||||
resources: UnsafeCell::new(Vec::new()),
|
||||
deadlocked: Cell::new(false),
|
||||
backtrace_sender: UnsafeCell::new(None),
|
||||
thread_id: thread_id::get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) unsafe fn on_unpark(td: &ThreadData) {
|
||||
if td.deadlock_data.deadlocked.get() {
|
||||
let sender = (*td.deadlock_data.backtrace_sender.get()).take().unwrap();
|
||||
sender
|
||||
.send(DeadlockedThread {
|
||||
thread_id: td.deadlock_data.thread_id,
|
||||
backtrace: Backtrace::new(),
|
||||
})
|
||||
.unwrap();
|
||||
// make sure to close this sender
|
||||
drop(sender);
|
||||
|
||||
// park until the end of the time
|
||||
td.parker.prepare_park();
|
||||
td.parker.park();
|
||||
unreachable!("unparked deadlocked thread!");
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn acquire_resource(key: usize) {
|
||||
let mut thread_data = None;
|
||||
let thread_data = get_thread_data(&mut thread_data);
|
||||
(*thread_data.deadlock_data.resources.get()).push(key);
|
||||
}
|
||||
|
||||
pub unsafe fn release_resource(key: usize) {
|
||||
let mut thread_data = None;
|
||||
let thread_data = get_thread_data(&mut thread_data);
|
||||
let resources = &mut (*thread_data.deadlock_data.resources.get());
|
||||
match resources.iter().rposition(|x| *x == key) {
|
||||
Some(p) => resources.swap_remove(p),
|
||||
None => panic!("key {} not found in thread resources", key),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn check_deadlock() -> Vec<Vec<DeadlockedThread>> {
|
||||
unsafe {
|
||||
// fast pass
|
||||
if check_wait_graph_fast() {
|
||||
// double check
|
||||
check_wait_graph_slow()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple algorithm that builds a wait graph f the threads and the resources,
|
||||
// then checks for the presence of cycles (deadlocks).
|
||||
// This variant isn't precise as it doesn't lock the entire table before checking
|
||||
unsafe fn check_wait_graph_fast() -> bool {
|
||||
let table = get_hashtable();
|
||||
let thread_count = NUM_THREADS.load(Ordering::Relaxed);
|
||||
let mut graph = DiGraphMap::<usize, ()>::with_capacity(thread_count * 2, thread_count * 2);
|
||||
|
||||
for b in &(*table).entries[..] {
|
||||
b.mutex.lock();
|
||||
let mut current = b.queue_head.get();
|
||||
while !current.is_null() {
|
||||
if !(*current).parked_with_timeout.get()
|
||||
&& !(*current).deadlock_data.deadlocked.get()
|
||||
{
|
||||
// .resources are waiting for their owner
|
||||
for &resource in &(*(*current).deadlock_data.resources.get()) {
|
||||
graph.add_edge(resource, current as usize, ());
|
||||
}
|
||||
// owner waits for resource .key
|
||||
graph.add_edge(current as usize, (*current).key.load(Ordering::Relaxed), ());
|
||||
}
|
||||
current = (*current).next_in_queue.get();
|
||||
}
|
||||
b.mutex.unlock();
|
||||
}
|
||||
|
||||
petgraph::algo::is_cyclic_directed(&graph)
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
|
||||
enum WaitGraphNode {
|
||||
Thread(*const ThreadData),
|
||||
Resource(usize),
|
||||
}
|
||||
|
||||
use self::WaitGraphNode::*;
|
||||
|
||||
// Contrary to the _fast variant this locks the entrie table before looking for cycles.
|
||||
// Returns all detected thread wait cycles.
|
||||
// Note that once a cycle is reported it's never reported again.
|
||||
unsafe fn check_wait_graph_slow() -> Vec<Vec<DeadlockedThread>> {
|
||||
let mut table = get_hashtable();
|
||||
loop {
|
||||
// Lock all buckets in the old table
|
||||
for b in &(*table).entries[..] {
|
||||
b.mutex.lock();
|
||||
}
|
||||
|
||||
// Now check if our table is still the latest one. Another thread could
|
||||
// have grown the hash table between us getting and locking the hash table.
|
||||
let new_table = get_hashtable();
|
||||
if new_table == table {
|
||||
break;
|
||||
}
|
||||
|
||||
// Unlock buckets and try again
|
||||
for b in &(*table).entries[..] {
|
||||
b.mutex.unlock();
|
||||
}
|
||||
|
||||
table = new_table;
|
||||
}
|
||||
|
||||
let thread_count = NUM_THREADS.load(Ordering::Relaxed);
|
||||
let mut graph =
|
||||
DiGraphMap::<WaitGraphNode, ()>::with_capacity(thread_count * 2, thread_count * 2);
|
||||
|
||||
for b in &(*table).entries[..] {
|
||||
let mut current = b.queue_head.get();
|
||||
while !current.is_null() {
|
||||
if !(*current).parked_with_timeout.get()
|
||||
&& !(*current).deadlock_data.deadlocked.get()
|
||||
{
|
||||
// .resources are waiting for their owner
|
||||
for &resource in &(*(*current).deadlock_data.resources.get()) {
|
||||
graph.add_edge(Resource(resource), Thread(current), ());
|
||||
}
|
||||
// owner waits for resource .key
|
||||
graph.add_edge(
|
||||
Thread(current),
|
||||
Resource((*current).key.load(Ordering::Relaxed)),
|
||||
(),
|
||||
);
|
||||
}
|
||||
current = (*current).next_in_queue.get();
|
||||
}
|
||||
}
|
||||
|
||||
for b in &(*table).entries[..] {
|
||||
b.mutex.unlock();
|
||||
}
|
||||
|
||||
// find cycles
|
||||
let cycles = graph_cycles(&graph);
|
||||
|
||||
let mut results = Vec::with_capacity(cycles.len());
|
||||
|
||||
for cycle in cycles {
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
for td in cycle {
|
||||
let bucket = lock_bucket((*td).key.load(Ordering::Relaxed));
|
||||
(*td).deadlock_data.deadlocked.set(true);
|
||||
*(*td).deadlock_data.backtrace_sender.get() = Some(sender.clone());
|
||||
let handle = (*td).parker.unpark_lock();
|
||||
bucket.mutex.unlock();
|
||||
// unpark the deadlocked thread!
|
||||
// on unpark it'll notice the deadlocked flag and report back
|
||||
handle.unpark();
|
||||
}
|
||||
// make sure to drop our sender before collecting results
|
||||
drop(sender);
|
||||
results.push(receiver.iter().collect());
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
// normalize a cycle to start with the "smallest" node
|
||||
fn normalize_cycle<T: Ord + Copy + Clone>(input: &[T]) -> Vec<T> {
|
||||
let min_pos = input
|
||||
.iter()
|
||||
.enumerate()
|
||||
.min_by_key(|&(_, &t)| t)
|
||||
.map(|(p, _)| p)
|
||||
.unwrap_or(0);
|
||||
input
|
||||
.iter()
|
||||
.cycle()
|
||||
.skip(min_pos)
|
||||
.take(input.len())
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
// returns all thread cycles in the wait graph
|
||||
fn graph_cycles(g: &DiGraphMap<WaitGraphNode, ()>) -> Vec<Vec<*const ThreadData>> {
|
||||
use petgraph::visit::NodeIndexable;
|
||||
use petgraph::visit::depth_first_search;
|
||||
use petgraph::visit::DfsEvent;
|
||||
|
||||
let mut cycles = HashSet::new();
|
||||
let mut path = Vec::with_capacity(g.node_bound());
|
||||
// start from threads to get the correct threads cycle
|
||||
let threads = g.nodes()
|
||||
.filter(|n| if let &Thread(_) = n { true } else { false });
|
||||
|
||||
depth_first_search(g, threads, |e| match e {
|
||||
DfsEvent::Discover(Thread(n), _) => path.push(n),
|
||||
DfsEvent::Finish(Thread(_), _) => {
|
||||
path.pop();
|
||||
}
|
||||
DfsEvent::BackEdge(_, Thread(n)) => {
|
||||
let from = path.iter().rposition(|&i| i == n).unwrap();
|
||||
cycles.insert(normalize_cycle(&path[from..]));
|
||||
}
|
||||
_ => (),
|
||||
});
|
||||
|
||||
cycles.iter().cloned().collect()
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use libc;
|
||||
#[cfg(not(any(windows, unix)))]
|
||||
use std::thread;
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use std::sync::atomic::{Ordering, fence};
|
||||
use std::sync::atomic::{fence, Ordering};
|
||||
|
||||
// Yields the rest of the current timeslice to the OS
|
||||
#[cfg(windows)]
|
||||
@ -58,9 +58,8 @@ fn cpu_relax(iterations: u32) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(all(feature = "nightly", not(any(target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "aarch64"))))]
|
||||
#[cfg(all(feature = "nightly",
|
||||
not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))))]
|
||||
#[inline]
|
||||
fn cpu_relax(iterations: u32) {
|
||||
for _ in 0..iterations {
|
||||
|
40
third_party/rust/parking_lot_core/src/stable.rs
vendored
40
third_party/rust/parking_lot_core/src/stable.rs
vendored
@ -10,7 +10,7 @@
|
||||
use std::sync::atomic;
|
||||
|
||||
// Re-export this for convenience
|
||||
pub use std::sync::atomic::{Ordering, fence};
|
||||
pub use std::sync::atomic::{fence, Ordering};
|
||||
|
||||
// Wrapper around AtomicUsize for non-nightly which has usable compare_exchange
|
||||
// and compare_exchange_weak methods.
|
||||
@ -55,23 +55,33 @@ impl AtomicUsize {
|
||||
self.0.fetch_or(val, order)
|
||||
}
|
||||
#[inline]
|
||||
pub fn compare_exchange(&self,
|
||||
old: usize,
|
||||
new: usize,
|
||||
order: Ordering,
|
||||
_: Ordering)
|
||||
-> Result<usize, usize> {
|
||||
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) }
|
||||
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> {
|
||||
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) }
|
||||
if res == old {
|
||||
Ok(res)
|
||||
} else {
|
||||
Err(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +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 std::sync::{Mutex, MutexGuard, Condvar};
|
||||
use std::sync::{Condvar, Mutex, MutexGuard};
|
||||
use std::cell::Cell;
|
||||
use std::time::Instant;
|
||||
|
||||
|
@ -29,7 +29,9 @@ pub struct ThreadParker {
|
||||
|
||||
impl ThreadParker {
|
||||
pub fn new() -> ThreadParker {
|
||||
ThreadParker { futex: AtomicI32::new(0) }
|
||||
ThreadParker {
|
||||
futex: AtomicI32::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
// Prepares the parker. This should be called before adding it to the queue.
|
||||
@ -50,8 +52,10 @@ impl ThreadParker {
|
||||
let r = libc::syscall(SYS_FUTEX, &self.futex, FUTEX_WAIT | FUTEX_PRIVATE, 1, 0);
|
||||
debug_assert!(r == 0 || r == -1);
|
||||
if r == -1 {
|
||||
debug_assert!(*libc::__errno_location() == libc::EINTR ||
|
||||
*libc::__errno_location() == libc::EAGAIN);
|
||||
debug_assert!(
|
||||
*libc::__errno_location() == libc::EINTR
|
||||
|| *libc::__errno_location() == libc::EAGAIN
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,9 +82,11 @@ impl ThreadParker {
|
||||
let r = libc::syscall(SYS_FUTEX, &self.futex, FUTEX_WAIT | FUTEX_PRIVATE, 1, &ts);
|
||||
debug_assert!(r == 0 || r == -1);
|
||||
if r == -1 {
|
||||
debug_assert!(*libc::__errno_location() == libc::EINTR ||
|
||||
*libc::__errno_location() == libc::EAGAIN ||
|
||||
*libc::__errno_location() == libc::ETIMEDOUT);
|
||||
debug_assert!(
|
||||
*libc::__errno_location() == libc::EINTR
|
||||
|| *libc::__errno_location() == libc::EAGAIN
|
||||
|| *libc::__errno_location() == libc::ETIMEDOUT
|
||||
);
|
||||
}
|
||||
}
|
||||
true
|
||||
|
@ -124,7 +124,9 @@ impl ThreadParker {
|
||||
let r = libc::pthread_mutex_lock(self.mutex.get());
|
||||
debug_assert_eq!(r, 0);
|
||||
|
||||
UnparkHandle { thread_parker: self }
|
||||
UnparkHandle {
|
||||
thread_parker: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,23 +22,26 @@ const STATE_TIMED_OUT: usize = 2;
|
||||
#[allow(non_snake_case)]
|
||||
pub struct KeyedEvent {
|
||||
handle: winapi::HANDLE,
|
||||
NtReleaseKeyedEvent: extern "system" fn(EventHandle: winapi::HANDLE,
|
||||
Key: winapi::PVOID,
|
||||
Alertable: winapi::BOOLEAN,
|
||||
Timeout: winapi::PLARGE_INTEGER)
|
||||
-> winapi::NTSTATUS,
|
||||
NtWaitForKeyedEvent: extern "system" fn(EventHandle: winapi::HANDLE,
|
||||
Key: winapi::PVOID,
|
||||
Alertable: winapi::BOOLEAN,
|
||||
Timeout: winapi::PLARGE_INTEGER)
|
||||
-> winapi::NTSTATUS,
|
||||
NtReleaseKeyedEvent: extern "system" fn(
|
||||
EventHandle: winapi::HANDLE,
|
||||
Key: winapi::PVOID,
|
||||
Alertable: winapi::BOOLEAN,
|
||||
Timeout: winapi::PLARGE_INTEGER,
|
||||
) -> winapi::NTSTATUS,
|
||||
NtWaitForKeyedEvent: extern "system" fn(
|
||||
EventHandle: winapi::HANDLE,
|
||||
Key: winapi::PVOID,
|
||||
Alertable: winapi::BOOLEAN,
|
||||
Timeout: winapi::PLARGE_INTEGER,
|
||||
) -> winapi::NTSTATUS,
|
||||
}
|
||||
|
||||
impl KeyedEvent {
|
||||
unsafe fn wait_for(&self,
|
||||
key: winapi::PVOID,
|
||||
timeout: winapi::PLARGE_INTEGER)
|
||||
-> winapi::NTSTATUS {
|
||||
unsafe fn wait_for(
|
||||
&self,
|
||||
key: winapi::PVOID,
|
||||
timeout: winapi::PLARGE_INTEGER,
|
||||
) -> winapi::NTSTATUS {
|
||||
(self.NtWaitForKeyedEvent)(self.handle, key, 0, timeout)
|
||||
}
|
||||
|
||||
@ -69,17 +72,19 @@ impl KeyedEvent {
|
||||
return None;
|
||||
}
|
||||
|
||||
let NtCreateKeyedEvent: extern "system" fn(KeyedEventHandle: winapi::PHANDLE,
|
||||
DesiredAccess: winapi::ACCESS_MASK,
|
||||
ObjectAttributes: winapi::PVOID,
|
||||
Flags: winapi::ULONG)
|
||||
-> winapi::NTSTATUS =
|
||||
mem::transmute(NtCreateKeyedEvent);
|
||||
let NtCreateKeyedEvent: extern "system" fn(
|
||||
KeyedEventHandle: winapi::PHANDLE,
|
||||
DesiredAccess: winapi::ACCESS_MASK,
|
||||
ObjectAttributes: winapi::PVOID,
|
||||
Flags: winapi::ULONG,
|
||||
) -> winapi::NTSTATUS = mem::transmute(NtCreateKeyedEvent);
|
||||
let mut handle = mem::uninitialized();
|
||||
let status = NtCreateKeyedEvent(&mut handle,
|
||||
winapi::GENERIC_READ | winapi::GENERIC_WRITE,
|
||||
ptr::null_mut(),
|
||||
0);
|
||||
let status = NtCreateKeyedEvent(
|
||||
&mut handle,
|
||||
winapi::GENERIC_READ | winapi::GENERIC_WRITE,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
);
|
||||
if status != winapi::STATUS_SUCCESS {
|
||||
return None;
|
||||
}
|
||||
@ -122,7 +127,9 @@ impl KeyedEvent {
|
||||
let diff = timeout - now;
|
||||
let nt_timeout = (diff.as_secs() as winapi::LARGE_INTEGER)
|
||||
.checked_mul(-10000000)
|
||||
.and_then(|x| x.checked_sub((diff.subsec_nanos() as winapi::LARGE_INTEGER + 99) / 100));
|
||||
.and_then(|x| {
|
||||
x.checked_sub((diff.subsec_nanos() as winapi::LARGE_INTEGER + 99) / 100)
|
||||
});
|
||||
let mut nt_timeout = match nt_timeout {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
|
@ -6,9 +6,9 @@
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use stable::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
use stable::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||
use std::time::Instant;
|
||||
|
||||
mod keyed_event;
|
||||
@ -36,8 +36,10 @@ impl Backend {
|
||||
} else if let Some(keyed_event) = keyed_event::KeyedEvent::create() {
|
||||
backend = Backend::KeyedEvent(keyed_event);
|
||||
} else {
|
||||
panic!("parking_lot requires either NT Keyed Events (WinXP+) or \
|
||||
WaitOnAddress/WakeByAddress (Win8+)");
|
||||
panic!(
|
||||
"parking_lot requires either NT Keyed Events (WinXP+) or \
|
||||
WaitOnAddress/WakeByAddress (Win8+)"
|
||||
);
|
||||
}
|
||||
|
||||
// Try to create a new object
|
||||
|
@ -16,11 +16,12 @@ use kernel32;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub struct WaitAddress {
|
||||
WaitOnAddress: extern "system" fn(Address: winapi::PVOID,
|
||||
CompareAddress: winapi::PVOID,
|
||||
AddressSize: winapi::SIZE_T,
|
||||
dwMilliseconds: winapi::DWORD)
|
||||
-> winapi::BOOL,
|
||||
WaitOnAddress: extern "system" fn(
|
||||
Address: winapi::PVOID,
|
||||
CompareAddress: winapi::PVOID,
|
||||
AddressSize: winapi::SIZE_T,
|
||||
dwMilliseconds: winapi::DWORD,
|
||||
) -> winapi::BOOL,
|
||||
WakeByAddressSingle: extern "system" fn(Address: winapi::PVOID),
|
||||
}
|
||||
|
||||
@ -29,20 +30,21 @@ impl WaitAddress {
|
||||
pub unsafe fn create() -> Option<WaitAddress> {
|
||||
// MSDN claims that that WaitOnAddress and WakeByAddressSingle are
|
||||
// located in kernel32.dll, but they are lying...
|
||||
let synch_dll = kernel32::GetModuleHandleA(b"api-ms-win-core-synch-l1-2-0.dll\0"
|
||||
.as_ptr() as winapi::LPCSTR);
|
||||
let synch_dll = kernel32::GetModuleHandleA(b"api-ms-win-core-synch-l1-2-0.dll\0".as_ptr()
|
||||
as winapi::LPCSTR);
|
||||
if synch_dll.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let WaitOnAddress = kernel32::GetProcAddress(synch_dll,
|
||||
b"WaitOnAddress\0".as_ptr() as winapi::LPCSTR);
|
||||
let WaitOnAddress =
|
||||
kernel32::GetProcAddress(synch_dll, b"WaitOnAddress\0".as_ptr() as winapi::LPCSTR);
|
||||
if WaitOnAddress.is_null() {
|
||||
return None;
|
||||
}
|
||||
let WakeByAddressSingle = kernel32::GetProcAddress(synch_dll,
|
||||
b"WakeByAddressSingle\0".as_ptr() as
|
||||
winapi::LPCSTR);
|
||||
let WakeByAddressSingle = kernel32::GetProcAddress(
|
||||
synch_dll,
|
||||
b"WakeByAddressSingle\0".as_ptr() as winapi::LPCSTR,
|
||||
);
|
||||
if WakeByAddressSingle.is_null() {
|
||||
return None;
|
||||
}
|
||||
@ -63,10 +65,12 @@ impl WaitAddress {
|
||||
pub unsafe fn park(&'static self, key: &AtomicUsize) {
|
||||
while key.load(Ordering::Acquire) != 0 {
|
||||
let cmp = 1usize;
|
||||
let r = (self.WaitOnAddress)(key as *const _ as winapi::PVOID,
|
||||
&cmp as *const _ as winapi::PVOID,
|
||||
mem::size_of::<usize>() as winapi::SIZE_T,
|
||||
winapi::INFINITE);
|
||||
let r = (self.WaitOnAddress)(
|
||||
key as *const _ as winapi::PVOID,
|
||||
&cmp as *const _ as winapi::PVOID,
|
||||
mem::size_of::<usize>() as winapi::SIZE_T,
|
||||
winapi::INFINITE,
|
||||
);
|
||||
debug_assert!(r == winapi::TRUE);
|
||||
}
|
||||
}
|
||||
@ -80,18 +84,24 @@ impl WaitAddress {
|
||||
let diff = timeout - now;
|
||||
let timeout = diff.as_secs()
|
||||
.checked_mul(1000)
|
||||
.and_then(|x| x.checked_add((diff.subsec_nanos() as u64 + 999999) / 1000000))
|
||||
.map(|ms| if ms > <winapi::DWORD>::max_value() as u64 {
|
||||
winapi::INFINITE
|
||||
} else {
|
||||
ms as winapi::DWORD
|
||||
.and_then(|x| {
|
||||
x.checked_add((diff.subsec_nanos() as u64 + 999999) / 1000000)
|
||||
})
|
||||
.map(|ms| {
|
||||
if ms > <winapi::DWORD>::max_value() as u64 {
|
||||
winapi::INFINITE
|
||||
} else {
|
||||
ms as winapi::DWORD
|
||||
}
|
||||
})
|
||||
.unwrap_or(winapi::INFINITE);
|
||||
let cmp = 1usize;
|
||||
let r = (self.WaitOnAddress)(key as *const _ as winapi::PVOID,
|
||||
&cmp as *const _ as winapi::PVOID,
|
||||
mem::size_of::<usize>() as winapi::SIZE_T,
|
||||
timeout);
|
||||
let r = (self.WaitOnAddress)(
|
||||
key as *const _ as winapi::PVOID,
|
||||
&cmp as *const _ as winapi::PVOID,
|
||||
mem::size_of::<usize>() as winapi::SIZE_T,
|
||||
timeout,
|
||||
);
|
||||
if r == winapi::FALSE {
|
||||
debug_assert_eq!(kernel32::GetLastError(), winapi::ERROR_TIMEOUT);
|
||||
}
|
||||
|
@ -6,9 +6,9 @@
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::sync::atomic::{AtomicUsize, Ordering, fence};
|
||||
use std::sync::atomic::{fence, AtomicUsize, Ordering};
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
use stable::{AtomicUsize, Ordering, fence};
|
||||
use stable::{fence, AtomicUsize, Ordering};
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
use std::cell::Cell;
|
||||
@ -89,14 +89,17 @@ pub struct WordLock {
|
||||
impl WordLock {
|
||||
#[inline]
|
||||
pub fn new() -> WordLock {
|
||||
WordLock { state: AtomicUsize::new(0) }
|
||||
WordLock {
|
||||
state: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn lock(&self) {
|
||||
if self.state
|
||||
.compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
|
||||
.is_ok() {
|
||||
.is_ok()
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.lock_slow();
|
||||
@ -119,11 +122,12 @@ impl WordLock {
|
||||
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,
|
||||
Err(x) => state = x,
|
||||
}
|
||||
@ -152,11 +156,12 @@ impl WordLock {
|
||||
thread_data.prev.set(ptr::null());
|
||||
thread_data.next.set(queue_head);
|
||||
}
|
||||
if let Err(x) = self.state
|
||||
.compare_exchange_weak(state,
|
||||
(state & !QUEUE_MASK) | thread_data as *const _ as usize,
|
||||
Ordering::Release,
|
||||
Ordering::Relaxed) {
|
||||
if let Err(x) = self.state.compare_exchange_weak(
|
||||
state,
|
||||
(state & !QUEUE_MASK) | thread_data as *const _ as usize,
|
||||
Ordering::Release,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
state = x;
|
||||
continue;
|
||||
}
|
||||
@ -183,10 +188,12 @@ impl WordLock {
|
||||
}
|
||||
|
||||
// Try to grab the queue lock
|
||||
match self.state.compare_exchange_weak(state,
|
||||
state | QUEUE_LOCKED_BIT,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed) {
|
||||
match self.state.compare_exchange_weak(
|
||||
state,
|
||||
state | QUEUE_LOCKED_BIT,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => break,
|
||||
Err(x) => state = x,
|
||||
}
|
||||
@ -218,10 +225,12 @@ impl WordLock {
|
||||
// thread now. Instead we let the next unlocker take care of waking
|
||||
// up a thread.
|
||||
if state & LOCKED_BIT != 0 {
|
||||
match self.state.compare_exchange_weak(state,
|
||||
state & !QUEUE_LOCKED_BIT,
|
||||
Ordering::Release,
|
||||
Ordering::Relaxed) {
|
||||
match self.state.compare_exchange_weak(
|
||||
state,
|
||||
state & !QUEUE_LOCKED_BIT,
|
||||
Ordering::Release,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => return,
|
||||
Err(x) => state = x,
|
||||
}
|
||||
@ -235,10 +244,12 @@ impl WordLock {
|
||||
let new_tail = (*queue_tail).prev.get();
|
||||
if new_tail.is_null() {
|
||||
loop {
|
||||
match self.state.compare_exchange_weak(state,
|
||||
state & LOCKED_BIT,
|
||||
Ordering::Release,
|
||||
Ordering::Relaxed) {
|
||||
match self.state.compare_exchange_weak(
|
||||
state,
|
||||
state & LOCKED_BIT,
|
||||
Ordering::Release,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => break,
|
||||
Err(x) => state = x,
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
{"files":{".travis.yml":"91edce5ea2a1956399db4b17f580c8b7995af3aa9801c4314865f560c55d6d09","Cargo.toml":"107fc4138f10e17b1b3e7b3ac7f95787100fed0a170303f6bbfaee1c0eedea43","README.md":"ecca7edfce86fe7b219535e3c14721d1de838de7035de077a4d497959260bccc","benches/bench.rs":"54cf4879d36ba2a9f3423af91bb93227b70849200e5bf74e384a166d6aa09893","lib.rs":"2d6b7216296c2f1b1e44bf41c0567f5e47de5fa8a3d984200ef315e8b7939aa3"},"package":"8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d"}
|
14
third_party/rust/smallvec-0.4.3/.travis.yml
vendored
14
third_party/rust/smallvec-0.4.3/.travis.yml
vendored
@ -1,14 +0,0 @@
|
||||
language: rust
|
||||
rust:
|
||||
- nightly
|
||||
- beta
|
||||
- stable
|
||||
script: |
|
||||
cargo build --verbose &&
|
||||
cargo build --all-features --verbose &&
|
||||
cargo test --verbose &&
|
||||
cargo test --all-features --verbose &&
|
||||
([ $TRAVIS_RUST_VERSION != nightly ] || cargo test --verbose --no-default-features) &&
|
||||
([ $TRAVIS_RUST_VERSION != nightly ] || cargo bench --verbose bench)
|
||||
notifications:
|
||||
webhooks: http://build.servo.org:54856/travis
|
40
third_party/rust/smallvec-0.4.3/Cargo.toml
vendored
40
third_party/rust/smallvec-0.4.3/Cargo.toml
vendored
@ -1,40 +0,0 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you 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)
|
||||
|
||||
[package]
|
||||
name = "smallvec"
|
||||
version = "0.4.3"
|
||||
authors = ["Simon Sapin <simon.sapin@exyr.org>"]
|
||||
description = "'Small vector' optimization: store up to a small number of items on the stack"
|
||||
documentation = "http://doc.servo.org/smallvec/"
|
||||
readme = "README.md"
|
||||
keywords = ["small", "vec", "vector", "stack", "no_std"]
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/servo/rust-smallvec"
|
||||
|
||||
[lib]
|
||||
name = "smallvec"
|
||||
path = "lib.rs"
|
||||
[dependencies.serde]
|
||||
version = "1"
|
||||
optional = true
|
||||
|
||||
[dependencies.heapsize]
|
||||
version = "0.4"
|
||||
optional = true
|
||||
[dev-dependencies.bincode]
|
||||
version = "0.8"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
heapsizeof = ["heapsize", "std"]
|
6
third_party/rust/smallvec-0.4.3/README.md
vendored
6
third_party/rust/smallvec-0.4.3/README.md
vendored
@ -1,6 +0,0 @@
|
||||
rust-smallvec
|
||||
=============
|
||||
|
||||
[Documentation](http://docs.rs/smallvec/)
|
||||
|
||||
"Small vector" optimization for Rust: store up to a small number of items on the stack
|
111
third_party/rust/smallvec-0.4.3/benches/bench.rs
vendored
111
third_party/rust/smallvec-0.4.3/benches/bench.rs
vendored
@ -1,111 +0,0 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate smallvec;
|
||||
extern crate test;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_push(b: &mut Bencher) {
|
||||
#[inline(never)]
|
||||
fn push_noinline(vec: &mut SmallVec<[u64; 16]>, x: u64) {
|
||||
vec.push(x)
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
|
||||
for x in 0..100 {
|
||||
push_noinline(&mut vec, x);
|
||||
}
|
||||
vec
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_insert(b: &mut Bencher) {
|
||||
#[inline(never)]
|
||||
fn insert_noinline(vec: &mut SmallVec<[u64; 16]>, x: u64) {
|
||||
vec.insert(0, x)
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
|
||||
for x in 0..100 {
|
||||
insert_noinline(&mut vec, x);
|
||||
}
|
||||
vec
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_insert_many(b: &mut Bencher) {
|
||||
#[inline(never)]
|
||||
fn insert_many_noinline<I: IntoIterator<Item=u64>>(
|
||||
vec: &mut SmallVec<[u64; 16]>, index: usize, iterable: I) {
|
||||
vec.insert_many(index, iterable)
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
|
||||
insert_many_noinline(&mut vec, 0, 0..100);
|
||||
insert_many_noinline(&mut vec, 0, 0..100);
|
||||
vec
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_extend(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
|
||||
vec.extend(0..100);
|
||||
vec
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_from_slice(b: &mut Bencher) {
|
||||
let v: Vec<u64> = (0..100).collect();
|
||||
b.iter(|| {
|
||||
let vec: SmallVec<[u64; 16]> = SmallVec::from_slice(&v);
|
||||
vec
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_extend_from_slice(b: &mut Bencher) {
|
||||
let v: Vec<u64> = (0..100).collect();
|
||||
b.iter(|| {
|
||||
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
|
||||
vec.extend_from_slice(&v);
|
||||
vec
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_insert_from_slice(b: &mut Bencher) {
|
||||
let v: Vec<u64> = (0..100).collect();
|
||||
b.iter(|| {
|
||||
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
|
||||
vec.insert_from_slice(0, &v);
|
||||
vec.insert_from_slice(0, &v);
|
||||
vec
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_pushpop(b: &mut Bencher) {
|
||||
#[inline(never)]
|
||||
fn pushpop_noinline(vec: &mut SmallVec<[u64; 16]>, x: u64) {
|
||||
vec.push(x);
|
||||
vec.pop();
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
|
||||
for x in 0..100 {
|
||||
pushpop_noinline(&mut vec, x);
|
||||
}
|
||||
vec
|
||||
});
|
||||
}
|
1686
third_party/rust/smallvec-0.4.3/lib.rs
vendored
1686
third_party/rust/smallvec-0.4.3/lib.rs
vendored
File diff suppressed because it is too large
Load Diff
14
toolkit/library/gtest/rust/Cargo.lock
generated
14
toolkit/library/gtest/rust/Cargo.lock
generated
@ -947,19 +947,19 @@ version = "0.4.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.4 (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]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.2.4"
|
||||
version = "0.2.7"
|
||||
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.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1225,11 +1225,6 @@ name = "smallbitvec"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.5.0"
|
||||
@ -1684,7 +1679,7 @@ dependencies = [
|
||||
"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_core 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a25dd36576d01cca115881dc920b1f0dd0037303ed8cfa0c5d0a4966151757f7"
|
||||
"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"
|
||||
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
|
||||
@ -1715,7 +1710,6 @@ dependencies = [
|
||||
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
|
||||
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
||||
"checksum smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "79b776f00dfe01df905fa3b2eaa1659522e99e3fc4a7b1334171622205c4bdcf"
|
||||
"checksum smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d"
|
||||
"checksum smallvec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "872c0ff227000041c520cca51e883b858d388ab0ecf646bab76f065cebaec025"
|
||||
"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
|
||||
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
||||
|
14
toolkit/library/rust/Cargo.lock
generated
14
toolkit/library/rust/Cargo.lock
generated
@ -935,19 +935,19 @@ version = "0.4.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.4 (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]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.2.4"
|
||||
version = "0.2.7"
|
||||
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.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1217,11 +1217,6 @@ name = "smallbitvec"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.5.0"
|
||||
@ -1696,7 +1691,7 @@ dependencies = [
|
||||
"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_core 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a25dd36576d01cca115881dc920b1f0dd0037303ed8cfa0c5d0a4966151757f7"
|
||||
"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"
|
||||
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
|
||||
@ -1727,7 +1722,6 @@ dependencies = [
|
||||
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
|
||||
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
||||
"checksum smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "79b776f00dfe01df905fa3b2eaa1659522e99e3fc4a7b1334171622205c4bdcf"
|
||||
"checksum smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d"
|
||||
"checksum smallvec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "872c0ff227000041c520cca51e883b858d388ab0ecf646bab76f065cebaec025"
|
||||
"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
|
||||
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
||||
|
Loading…
Reference in New Issue
Block a user