No bug - Update parking_lot_core and revendor to remove duplicate version of smallvec. r=me

MozReview-Commit-ID: 6B2hp9CLs2z
This commit is contained in:
Bobby Holley 2017-03-22 17:51:49 -07:00
parent c280467718
commit ca0f202c0c
18 changed files with 336 additions and 845 deletions

View File

@ -1 +1 @@
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","Cargo.toml":"133226f5f42038bf3bbf3266d955a6b6933306d0107593eac3a0b25cf8a08862","src/lib.rs":"f5a0333cbb54faba082d1d8621beb50e711169590cc35e73268bd2841bd1163f","src/parking_lot.rs":"17c34c9cd3bc3e649567a920466ef0799be66c556d34d4dbc9c246a154a4b647","src/spinwait.rs":"682e5a3fc71d1d7a7d8da377d1d93415fa64b4f53809bd80bbf2942628e3a23d","src/stable.rs":"ddfa0601589bb86d7fb5a6d697601c40a47d395641e26ba126ff666fd7ee7715","src/thread_parker/generic.rs":"6e3c7ef287691673c5001362da8757ac30f47481c804397f1c313153971f1d61","src/thread_parker/linux.rs":"894e289090ba21235b1f8bd0ea57defa6e199998e635a61b1292e38d50c5c46a","src/thread_parker/unix.rs":"bb1102ff79ab9ef98ce0df55e74ba561b92e39db55bcf5260c3dc017129994f4","src/thread_parker/windows.rs":"c10871429ce0bf757517c69dc9b1ba9e14bf8ff4363b04a13604f98d9c525e9b","src/util.rs":"2d07c0c010a857790ae2ed6a1215eeed8af76859e076797ea1ba8dec82169e84","src/word_lock.rs":"a3a33b4e13c79ff84cf049f47694f165c050baa179dac6262318ef05b8c9f8db"},"package":"fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"}
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","Cargo.toml":"8ba636346d2228cb56ba5468f224fde5be21f90b903422ac462ca7b3cfbd1f97","src/lib.rs":"6649792fe4bef4cbac34090bc599a86dc58d4528a8bfba4fce6a56bee3537c46","src/parking_lot.rs":"f18ed052d295746d1495a2cfab5a7fd25947542764d294dd1df1f43b36e5361e","src/spinwait.rs":"682e5a3fc71d1d7a7d8da377d1d93415fa64b4f53809bd80bbf2942628e3a23d","src/stable.rs":"cc18c58404dc6017924d88fb9f4ed94e5320b8cb0a36985162b23130b8cd7480","src/thread_parker/generic.rs":"6e3c7ef287691673c5001362da8757ac30f47481c804397f1c313153971f1d61","src/thread_parker/linux.rs":"0a3c63a8cba192827edb55dd785ccab22229370ad2bc4b52e81cc25c1fb63696","src/thread_parker/unix.rs":"bb1102ff79ab9ef98ce0df55e74ba561b92e39db55bcf5260c3dc017129994f4","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":"a3a33b4e13c79ff84cf049f47694f165c050baa179dac6262318ef05b8c9f8db"},"package":"56a19dcbb5d1e32b6cccb8a9aa1fc2a38418c8699652e735e2bf391a3dc0aa16"}

View File

@ -1,6 +1,6 @@
[package]
name = "parking_lot_core"
version = "0.2.0"
version = "0.2.1"
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"
@ -9,7 +9,7 @@ repository = "https://github.com/Amanieu/parking_lot"
keywords = ["mutex", "condvar", "rwlock", "once", "thread"]
[dependencies]
smallvec = "0.1"
smallvec = "0.3"
rand = "0.3"
[target.'cfg(unix)'.dependencies]

View File

@ -38,7 +38,7 @@
#![warn(missing_docs)]
#![cfg_attr(feature = "nightly", feature(const_fn))]
#![cfg_attr(feature = "nightly", feature(integer_atomics))]
#![cfg_attr(all(feature = "nightly", target_os = "linux"), feature(integer_atomics))]
#![cfg_attr(feature = "nightly", feature(asm))]
extern crate smallvec;
@ -59,7 +59,7 @@ mod thread_parker;
#[path = "thread_parker/unix.rs"]
mod thread_parker;
#[cfg(windows)]
#[path = "thread_parker/windows.rs"]
#[path = "thread_parker/windows/mod.rs"]
mod thread_parker;
#[cfg(not(any(windows, unix)))]
#[path = "thread_parker/generic.rs"]

View File

@ -13,7 +13,7 @@ use std::time::{Instant, Duration};
use std::cell::{Cell, UnsafeCell};
use std::ptr;
use std::mem;
use smallvec::SmallVec8;
use smallvec::SmallVec;
use rand::{self, XorShiftRng, Rng};
use thread_parker::ThreadParker;
use word_lock::WordLock;
@ -723,7 +723,7 @@ pub unsafe fn unpark_all(key: usize, unpark_token: UnparkToken) -> usize {
let mut link = &bucket.queue_head;
let mut current = bucket.queue_head.get();
let mut previous = ptr::null();
let mut threads = SmallVec8::new();
let mut threads = SmallVec::<[_; 8]>::new();
while !current.is_null() {
if (*current).key.load(Ordering::Relaxed) == key {
// Remove the thread from the queue
@ -942,7 +942,7 @@ unsafe fn unpark_filter_internal(key: usize,
let mut link = &bucket.queue_head;
let mut current = bucket.queue_head.get();
let mut previous = ptr::null();
let mut threads = SmallVec8::new();
let mut threads = SmallVec::<[_; 8]>::new();
let mut result = UnparkResult {
unparked_threads: 0,
have_more_threads: false,

View File

@ -62,11 +62,7 @@ impl AtomicUsize {
_: 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,
@ -76,10 +72,6 @@ impl AtomicUsize {
_: 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) }
}
}

View File

@ -93,7 +93,7 @@ impl ThreadParker {
// We don't need to lock anything, just clear the state
self.futex.store(0, Ordering::Release);
UnparkHandle { thread_parker: self }
UnparkHandle { futex: &self.futex }
}
}
@ -101,7 +101,7 @@ impl ThreadParker {
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle {
thread_parker: *const ThreadParker,
futex: *const AtomicI32,
}
impl UnparkHandle {
@ -110,10 +110,7 @@ impl UnparkHandle {
pub unsafe fn unpark(self) {
// The thread data may have been freed at this point, but it doesn't
// matter since the syscall will just return EFAULT in that case.
let r = libc::syscall(SYS_FUTEX,
&(*self.thread_parker).futex,
FUTEX_WAKE | FUTEX_PRIVATE,
1);
let r = libc::syscall(SYS_FUTEX, self.futex, FUTEX_WAKE | FUTEX_PRIVATE, 1);
debug_assert!(r == 0 || r == 1 || r == -1);
if r == -1 {
debug_assert_eq!(*libc::__errno_location(), libc::EFAULT);

View File

@ -6,17 +6,21 @@
// 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};
#[cfg(not(feature = "nightly"))]
use stable::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use stable::{AtomicUsize, Ordering};
use std::time::Instant;
use std::ptr;
use std::mem;
use winapi;
use kernel32;
const STATE_UNPARKED: usize = 0;
const STATE_PARKED: usize = 1;
const STATE_TIMED_OUT: usize = 2;
#[allow(non_snake_case)]
struct KeyedEvent {
pub struct KeyedEvent {
handle: winapi::HANDLE,
NtReleaseKeyedEvent: extern "system" fn(EventHandle: winapi::HANDLE,
Key: winapi::PVOID,
@ -42,51 +46,27 @@ impl KeyedEvent {
(self.NtReleaseKeyedEvent)(self.handle, key, 0, ptr::null_mut())
}
unsafe fn get() -> &'static KeyedEvent {
static KEYED_EVENT: AtomicUsize = ATOMIC_USIZE_INIT;
// Fast path: use the existing object
let keyed_event = KEYED_EVENT.load(Ordering::Acquire);
if keyed_event != 0 {
return &*(keyed_event as *const KeyedEvent);
};
// Try to create a new object
let keyed_event = Box::into_raw(KeyedEvent::create());
match KEYED_EVENT.compare_exchange(0,
keyed_event as usize,
Ordering::Release,
Ordering::Relaxed) {
Ok(_) => &*(keyed_event as *const KeyedEvent),
Err(x) => {
// We lost the race, free our object and return the global one
Box::from_raw(keyed_event);
&*(x as *const KeyedEvent)
}
}
}
#[allow(non_snake_case)]
unsafe fn create() -> Box<KeyedEvent> {
pub unsafe fn create() -> Option<KeyedEvent> {
let ntdll = kernel32::GetModuleHandleA(b"ntdll.dll\0".as_ptr() as winapi::LPCSTR);
if ntdll.is_null() {
panic!("Could not get module handle for ntdll.dll");
return None;
}
let NtCreateKeyedEvent =
kernel32::GetProcAddress(ntdll, b"NtCreateKeyedEvent\0".as_ptr() as winapi::LPCSTR);
if NtCreateKeyedEvent.is_null() {
panic!("Entry point NtCreateKeyedEvent not found in ntdll.dll");
return None;
}
let NtReleaseKeyedEvent =
kernel32::GetProcAddress(ntdll, b"NtReleaseKeyedEvent\0".as_ptr() as winapi::LPCSTR);
if NtReleaseKeyedEvent.is_null() {
panic!("Entry point NtReleaseKeyedEvent not found in ntdll.dll");
return None;
}
let NtWaitForKeyedEvent =
kernel32::GetProcAddress(ntdll, b"NtWaitForKeyedEvent\0".as_ptr() as winapi::LPCSTR);
if NtWaitForKeyedEvent.is_null() {
panic!("Entry point NtWaitForKeyedEvent not found in ntdll.dll");
return None;
}
let NtCreateKeyedEvent: extern "system" fn(KeyedEventHandle: winapi::PHANDLE,
@ -101,76 +81,37 @@ impl KeyedEvent {
ptr::null_mut(),
0);
if status != winapi::STATUS_SUCCESS {
panic!("NtCreateKeyedEvent failed: {:x}", status);
return None;
}
Box::new(KeyedEvent {
Some(KeyedEvent {
handle: handle,
NtReleaseKeyedEvent: mem::transmute(NtReleaseKeyedEvent),
NtWaitForKeyedEvent: mem::transmute(NtWaitForKeyedEvent),
})
}
}
impl Drop for KeyedEvent {
fn drop(&mut self) {
unsafe {
let ok = kernel32::CloseHandle(self.handle);
debug_assert_eq!(ok, winapi::TRUE);
}
}
}
const STATE_UNPARKED: usize = 0;
const STATE_PARKED: usize = 1;
const STATE_TIMED_OUT: usize = 2;
// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
key: AtomicUsize,
keyed_event: &'static KeyedEvent,
}
impl ThreadParker {
pub fn new() -> ThreadParker {
// Initialize the keyed event here to ensure we don't get any panics
// later on, which could leave synchronization primitives in a broken
// state.
ThreadParker {
key: AtomicUsize::new(STATE_UNPARKED),
keyed_event: unsafe { KeyedEvent::get() },
}
pub unsafe fn prepare_park(&'static self, key: &AtomicUsize) {
key.store(STATE_PARKED, Ordering::Relaxed);
}
// Prepares the parker. This should be called before adding it to the queue.
pub unsafe fn prepare_park(&self) {
self.key.store(STATE_PARKED, Ordering::Relaxed);
pub unsafe fn timed_out(&'static self, key: &AtomicUsize) -> bool {
key.load(Ordering::Relaxed) == STATE_TIMED_OUT
}
// Checks if the park timed out. This should be called while holding the
// queue lock after park_until has returned false.
pub unsafe fn timed_out(&self) -> bool {
self.key.load(Ordering::Relaxed) == STATE_TIMED_OUT
}
// Parks the thread until it is unparked. This should be called after it has
// been added to the queue, after unlocking the queue.
pub unsafe fn park(&self) {
let status = self.keyed_event.wait_for(self as *const _ as winapi::PVOID, ptr::null_mut());
pub unsafe fn park(&'static self, key: &AtomicUsize) {
let status = self.wait_for(key as *const _ as winapi::PVOID, ptr::null_mut());
debug_assert_eq!(status, winapi::STATUS_SUCCESS);
}
// Parks the thread until it is unparked or the timeout is reached. This
// should be called after it has been added to the queue, after unlocking
// the queue. Returns true if we were unparked and false if we timed out.
pub unsafe fn park_until(&self, timeout: Instant) -> bool {
pub unsafe fn park_until(&'static self, key: &AtomicUsize, timeout: Instant) -> bool {
let now = Instant::now();
if timeout <= now {
// If another thread unparked us, we need to call
// NtWaitForKeyedEvent otherwise that thread will stay stuck at
// NtReleaseKeyedEvent.
if self.key.swap(STATE_TIMED_OUT, Ordering::Relaxed) == STATE_UNPARKED {
self.park();
if key.swap(STATE_TIMED_OUT, Ordering::Relaxed) == STATE_UNPARKED {
self.park(key);
return true;
}
return false;
@ -186,12 +127,12 @@ impl ThreadParker {
Some(x) => x,
None => {
// Timeout overflowed, just sleep indefinitely
self.park();
self.park(key);
return true;
}
};
let status = self.keyed_event.wait_for(self as *const _ as winapi::PVOID, &mut nt_timeout);
let status = self.wait_for(key as *const _ as winapi::PVOID, &mut nt_timeout);
if status == winapi::STATUS_SUCCESS {
return true;
}
@ -199,22 +140,34 @@ impl ThreadParker {
// If another thread unparked us, we need to call NtWaitForKeyedEvent
// otherwise that thread will stay stuck at NtReleaseKeyedEvent.
if self.key.swap(STATE_TIMED_OUT, Ordering::Relaxed) == STATE_UNPARKED {
self.park();
if key.swap(STATE_TIMED_OUT, Ordering::Relaxed) == STATE_UNPARKED {
self.park(key);
return true;
}
false
}
// Locks the parker to prevent the target thread from exiting. This is
// necessary to ensure that thread-local ThreadData objects remain valid.
// This should be called while holding the queue lock.
pub unsafe fn unpark_lock(&self) -> UnparkHandle {
pub unsafe fn unpark_lock(&'static self, key: &AtomicUsize) -> UnparkHandle {
// If the state was STATE_PARKED then we need to wake up the thread
if self.key.swap(STATE_UNPARKED, Ordering::Relaxed) == STATE_PARKED {
UnparkHandle { thread_parker: self }
if key.swap(STATE_UNPARKED, Ordering::Relaxed) == STATE_PARKED {
UnparkHandle {
key: key,
keyed_event: self,
}
} else {
UnparkHandle { thread_parker: ptr::null() }
UnparkHandle {
key: ptr::null(),
keyed_event: self,
}
}
}
}
impl Drop for KeyedEvent {
fn drop(&mut self) {
unsafe {
let ok = kernel32::CloseHandle(self.handle);
debug_assert_eq!(ok, winapi::TRUE);
}
}
}
@ -223,17 +176,16 @@ impl ThreadParker {
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle {
thread_parker: *const ThreadParker,
key: *const AtomicUsize,
keyed_event: &'static KeyedEvent,
}
impl UnparkHandle {
// Wakes up the parked thread. This should be called after the queue lock is
// released to avoid blocking the queue for too long.
pub unsafe fn unpark(self) {
if !self.thread_parker.is_null() {
let status = (*self.thread_parker)
.keyed_event
.release(self.thread_parker as winapi::PVOID);
if !self.key.is_null() {
let status = self.keyed_event.release(self.key as winapi::PVOID);
debug_assert_eq!(status, winapi::STATUS_SUCCESS);
}
}

View File

@ -0,0 +1,137 @@
// 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.
#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
#[cfg(not(feature = "nightly"))]
use stable::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use std::time::Instant;
mod keyed_event;
mod waitaddress;
enum Backend {
KeyedEvent(keyed_event::KeyedEvent),
WaitAddress(waitaddress::WaitAddress),
}
impl Backend {
unsafe fn get() -> &'static Backend {
static BACKEND: AtomicUsize = ATOMIC_USIZE_INIT;
// Fast path: use the existing object
let backend = BACKEND.load(Ordering::Acquire);
if backend != 0 {
return &*(backend as *const Backend);
};
// Try to create a new Backend
let backend;
if let Some(waitaddress) = waitaddress::WaitAddress::create() {
backend = Backend::WaitAddress(waitaddress);
} 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+)");
}
// Try to create a new object
let backend = Box::into_raw(Box::new(backend));
match BACKEND.compare_exchange(0, backend as usize, Ordering::Release, Ordering::Relaxed) {
Ok(_) => &*(backend as *const Backend),
Err(x) => {
// We lost the race, free our object and return the global one
Box::from_raw(backend);
&*(x as *const Backend)
}
}
}
}
// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
key: AtomicUsize,
backend: &'static Backend,
}
impl ThreadParker {
pub fn new() -> ThreadParker {
// Initialize the backend here to ensure we don't get any panics
// later on, which could leave synchronization primitives in a broken
// state.
ThreadParker {
key: AtomicUsize::new(0),
backend: unsafe { Backend::get() },
}
}
// Prepares the parker. This should be called before adding it to the queue.
pub unsafe fn prepare_park(&self) {
match *self.backend {
Backend::KeyedEvent(ref x) => x.prepare_park(&self.key),
Backend::WaitAddress(ref x) => x.prepare_park(&self.key),
}
}
// Checks if the park timed out. This should be called while holding the
// queue lock after park_until has returned false.
pub unsafe fn timed_out(&self) -> bool {
match *self.backend {
Backend::KeyedEvent(ref x) => x.timed_out(&self.key),
Backend::WaitAddress(ref x) => x.timed_out(&self.key),
}
}
// Parks the thread until it is unparked. This should be called after it has
// been added to the queue, after unlocking the queue.
pub unsafe fn park(&self) {
match *self.backend {
Backend::KeyedEvent(ref x) => x.park(&self.key),
Backend::WaitAddress(ref x) => x.park(&self.key),
}
}
// Parks the thread until it is unparked or the timeout is reached. This
// should be called after it has been added to the queue, after unlocking
// the queue. Returns true if we were unparked and false if we timed out.
pub unsafe fn park_until(&self, timeout: Instant) -> bool {
match *self.backend {
Backend::KeyedEvent(ref x) => x.park_until(&self.key, timeout),
Backend::WaitAddress(ref x) => x.park_until(&self.key, timeout),
}
}
// Locks the parker to prevent the target thread from exiting. This is
// necessary to ensure that thread-local ThreadData objects remain valid.
// This should be called while holding the queue lock.
pub unsafe fn unpark_lock(&self) -> UnparkHandle {
match *self.backend {
Backend::KeyedEvent(ref x) => UnparkHandle::KeyedEvent(x.unpark_lock(&self.key)),
Backend::WaitAddress(ref x) => UnparkHandle::WaitAddress(x.unpark_lock(&self.key)),
}
}
}
// Handle for a thread that is about to be unparked. We need to mark the thread
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub enum UnparkHandle {
KeyedEvent(keyed_event::UnparkHandle),
WaitAddress(waitaddress::UnparkHandle),
}
impl UnparkHandle {
// Wakes up the parked thread. This should be called after the queue lock is
// released to avoid blocking the queue for too long.
pub unsafe fn unpark(self) {
match self {
UnparkHandle::KeyedEvent(x) => x.unpark(),
UnparkHandle::WaitAddress(x) => x.unpark(),
}
}
}

View File

@ -0,0 +1,128 @@
// 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.
#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(not(feature = "nightly"))]
use stable::{AtomicUsize, Ordering};
use std::time::Instant;
use std::mem;
use winapi;
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,
WakeByAddressSingle: extern "system" fn(Address: winapi::PVOID),
}
impl WaitAddress {
#[allow(non_snake_case)]
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);
if synch_dll.is_null() {
return None;
}
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);
if WakeByAddressSingle.is_null() {
return None;
}
Some(WaitAddress {
WaitOnAddress: mem::transmute(WaitOnAddress),
WakeByAddressSingle: mem::transmute(WakeByAddressSingle),
})
}
pub unsafe fn prepare_park(&'static self, key: &AtomicUsize) {
key.store(1, Ordering::Relaxed);
}
pub unsafe fn timed_out(&'static self, key: &AtomicUsize) -> bool {
key.load(Ordering::Relaxed) != 0
}
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);
debug_assert!(r == winapi::TRUE);
}
}
pub unsafe fn park_until(&'static self, key: &AtomicUsize, timeout: Instant) -> bool {
while key.load(Ordering::Acquire) != 0 {
let now = Instant::now();
if timeout <= now {
return false;
}
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
})
.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);
if r == winapi::FALSE {
debug_assert_eq!(kernel32::GetLastError(), winapi::ERROR_TIMEOUT);
}
}
true
}
pub unsafe fn unpark_lock(&'static self, key: &AtomicUsize) -> UnparkHandle {
// We don't need to lock anything, just clear the state
key.store(0, Ordering::Release);
UnparkHandle {
key: key,
waitaddress: self,
}
}
}
// Handle for a thread that is about to be unparked. We need to mark the thread
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle {
key: *const AtomicUsize,
waitaddress: &'static WaitAddress,
}
impl UnparkHandle {
// Wakes up the parked thread. This should be called after the queue lock is
// released to avoid blocking the queue for too long.
pub unsafe fn unpark(self) {
(self.waitaddress.WakeByAddressSingle)(self.key as winapi::PVOID);
}
}

View File

@ -1 +0,0 @@
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"1e747fe88fd7f3851492acddd8a051ddb65fdf28bc66bce87635d091c5791c78","Cargo.toml":"129458de74d26efa7902323cd543b4e478aa4bcf3e5c76ebf95c93949686c564","README.md":"85c6105e404b1febba9e06773350cc81fe5966369530210669b3465c66237a09","lib.rs":"ae2fda3b1e527c9ff7afd01ecb2b747225376bd0c009e5012117a16fd17b0817"},"package":"fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410"}

View File

@ -1,2 +0,0 @@
target
Cargo.lock

View File

@ -1,7 +0,0 @@
language: rust
rust:
- nightly
- beta
- stable
notifications:
webhooks: http://build.servo.org:54856/travis

View File

@ -1,15 +0,0 @@
[package]
name = "smallvec"
version = "0.1.8"
authors = ["Simon Sapin <simon.sapin@exyr.org>"]
license = "MPL-2.0"
repository = "https://github.com/servo/rust-smallvec"
description = "'Small vector' optimization: store up to a small number of items on the stack"
keywords = ["small", "vec", "vector", "stack"]
readme = "README.md"
documentation = "http://doc.servo.org/smallvec/"
[lib]
name = "smallvec"
path = "lib.rs"
doctest = false

View File

@ -1,6 +0,0 @@
rust-smallvec
=============
[Documentation](http://doc.servo.org/smallvec/)
"Small vector" optimization for Rust: store up to a small number of items on the stack

View File

@ -1,672 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Small vectors in various sizes. These store a certain number of elements inline and fall back
//! to the heap for larger allocations.
use std::cmp;
use std::fmt;
use std::iter::{IntoIterator, FromIterator};
use std::mem;
use std::ops;
use std::ptr;
use std::slice;
use SmallVecData::{Inline, Heap};
pub trait VecLike<T>:
ops::Index<usize, Output=T> +
ops::IndexMut<usize> +
ops::Index<ops::Range<usize>, Output=[T]> +
ops::IndexMut<ops::Range<usize>> +
ops::Index<ops::RangeFrom<usize>, Output=[T]> +
ops::IndexMut<ops::RangeFrom<usize>> +
ops::Index<ops::RangeTo<usize>, Output=[T]> +
ops::IndexMut<ops::RangeTo<usize>> +
ops::Index<ops::RangeFull, Output=[T]> +
ops::IndexMut<ops::RangeFull> +
ops::Deref +
ops::DerefMut {
fn len(&self) -> usize;
fn push(&mut self, value: T);
}
impl<T> VecLike<T> for Vec<T> {
#[inline]
fn len(&self) -> usize {
Vec::len(self)
}
#[inline]
fn push(&mut self, value: T) {
Vec::push(self, value);
}
}
unsafe fn deallocate<T>(ptr: *mut T, capacity: usize) {
let _vec: Vec<T> = Vec::from_raw_parts(ptr, 0, capacity);
// Let it drop.
}
pub struct SmallVecMoveIterator<'a, T: 'a> {
iter: slice::IterMut<'a,T>,
}
impl<'a, T: 'a> Iterator for SmallVecMoveIterator<'a,T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
match self.iter.next() {
None => None,
Some(reference) => {
unsafe {
Some(ptr::read(reference))
}
}
}
}
}
impl<'a, T: 'a> Drop for SmallVecMoveIterator<'a,T> {
fn drop(&mut self) {
// Destroy the remaining elements.
for _ in self.by_ref() {}
}
}
enum SmallVecData<A: Array> {
Inline { array: A },
Heap { ptr: *mut A::Item, capacity: usize },
}
unsafe impl<A: Array + Send> Send for SmallVecData<A> {}
unsafe impl<A: Array + Sync> Sync for SmallVecData<A> {}
impl<A: Array> Drop for SmallVecData<A> {
fn drop(&mut self) {
unsafe {
match *self {
ref mut inline @ Inline { .. } => {
// Inhibit the array destructor.
ptr::write(inline, Heap {
ptr: ptr::null_mut(),
capacity: 0,
});
}
Heap { ptr, capacity } => deallocate(ptr, capacity),
}
}
}
}
pub struct SmallVec<A: Array> {
len: usize,
data: SmallVecData<A>,
}
impl<A: Array> SmallVec<A> {
pub unsafe fn set_len(&mut self, new_len: usize) {
self.len = new_len
}
pub fn inline_size(&self) -> usize {
A::size()
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
match self.data {
Inline { .. } => A::size(),
Heap { capacity, .. } => capacity,
}
}
pub fn spilled(&self) -> bool {
match self.data {
Inline { .. } => false,
Heap { .. } => true,
}
}
/// NB: For efficiency reasons (avoiding making a second copy of the inline elements), this
/// actually clears out the original array instead of moving it.
/// FIXME: Rename this to `drain`? Its more like `Vec::drain` than `Vec::into_iter`.
pub fn into_iter<'a>(&'a mut self) -> SmallVecMoveIterator<'a, A::Item> {
unsafe {
let current_len = self.len();
self.set_len(0);
let ptr = match self.data {
Inline { ref mut array } => array.ptr_mut(),
Heap { ptr, .. } => ptr,
};
let slice = slice::from_raw_parts_mut(ptr, current_len);
SmallVecMoveIterator {
iter: slice.iter_mut(),
}
}
}
pub fn push(&mut self, value: A::Item) {
let cap = self.capacity();
if self.len == cap {
self.grow(cmp::max(cap * 2, 1))
}
unsafe {
let end = self.as_mut_ptr().offset(self.len as isize);
ptr::write(end, value);
let len = self.len;
self.set_len(len + 1)
}
}
pub fn push_all_move<V: IntoIterator<Item=A::Item>>(&mut self, other: V) {
for value in other {
self.push(value)
}
}
pub fn pop(&mut self) -> Option<A::Item> {
if self.len == 0 {
return None
}
let last_index = self.len - 1;
if (last_index as isize) < 0 {
panic!("overflow")
}
unsafe {
let end_ptr = self.as_mut_ptr().offset(last_index as isize);
let value = ptr::replace(end_ptr, mem::uninitialized());
self.set_len(last_index);
Some(value)
}
}
pub fn grow(&mut self, new_cap: usize) {
let mut vec: Vec<A::Item> = Vec::with_capacity(new_cap);
let new_alloc = vec.as_mut_ptr();
unsafe {
mem::forget(vec);
ptr::copy_nonoverlapping(self.as_ptr(), new_alloc, self.len);
match self.data {
Inline { .. } => {}
Heap { ptr, capacity } => deallocate(ptr, capacity),
}
ptr::write(&mut self.data, Heap {
ptr: new_alloc,
capacity: new_cap,
});
}
}
pub fn reserve(&mut self, additional: usize) {
let len = self.len();
if self.capacity() - len < additional {
match len.checked_add(additional).and_then(usize::checked_next_power_of_two) {
Some(cap) => self.grow(cap),
None => self.grow(usize::max_value()),
}
}
}
pub fn reserve_exact(&mut self, additional: usize) {
let len = self.len();
if self.capacity() - len < additional {
match len.checked_add(additional) {
Some(cap) => self.grow(cap),
None => panic!("reserve_exact overflow"),
}
}
}
pub fn shrink_to_fit(&mut self) {
let len = self.len;
if self.spilled() && self.capacity() > len {
self.grow(len);
}
}
pub fn truncate(&mut self, len: usize) {
let end_ptr = self.as_ptr();
while len < self.len {
unsafe {
let last_index = self.len - 1;
self.set_len(last_index);
ptr::read(end_ptr.offset(last_index as isize));
}
}
}
pub fn swap_remove(&mut self, index: usize) -> A::Item {
let len = self.len;
self.swap(len - 1, index);
self.pop().unwrap()
}
pub fn clear(&mut self) {
self.truncate(0);
}
pub fn remove(&mut self, index: usize) -> A::Item {
let len = self.len();
assert!(index < len);
unsafe {
let ptr = self.as_mut_ptr().offset(index as isize);
let item = ptr::read(ptr);
ptr::copy(ptr.offset(1), ptr, len - index - 1);
self.set_len(len - 1);
item
}
}
pub fn insert(&mut self, index: usize, element: A::Item) {
self.reserve(1);
let len = self.len;
assert!(index <= len);
unsafe {
let ptr = self.as_mut_ptr().offset(index as isize);
ptr::copy(ptr, ptr.offset(1), len - index);
ptr::write(ptr, element);
self.set_len(len + 1);
}
}
}
impl<A: Array> ops::Deref for SmallVec<A> {
type Target = [A::Item];
#[inline]
fn deref(&self) -> &[A::Item] {
let ptr: *const _ = match self.data {
Inline { ref array } => array.ptr(),
Heap { ptr, .. } => ptr,
};
unsafe {
slice::from_raw_parts(ptr, self.len)
}
}
}
impl<A: Array> ops::DerefMut for SmallVec<A> {
#[inline]
fn deref_mut(&mut self) -> &mut [A::Item] {
let ptr = match self.data {
Inline { ref mut array } => array.ptr_mut(),
Heap { ptr, .. } => ptr,
};
unsafe {
slice::from_raw_parts_mut(ptr, self.len)
}
}
}
macro_rules! impl_index {
($index_type: ty, $output_type: ty) => {
impl<A: Array> ops::Index<$index_type> for SmallVec<A> {
type Output = $output_type;
#[inline]
fn index(&self, index: $index_type) -> &$output_type {
&(&**self)[index]
}
}
impl<A: Array> ops::IndexMut<$index_type> for SmallVec<A> {
#[inline]
fn index_mut(&mut self, index: $index_type) -> &mut $output_type {
&mut (&mut **self)[index]
}
}
}
}
impl_index!(usize, A::Item);
impl_index!(ops::Range<usize>, [A::Item]);
impl_index!(ops::RangeFrom<usize>, [A::Item]);
impl_index!(ops::RangeTo<usize>, [A::Item]);
impl_index!(ops::RangeFull, [A::Item]);
impl<A: Array> VecLike<A::Item> for SmallVec<A> {
#[inline]
fn len(&self) -> usize {
SmallVec::len(self)
}
#[inline]
fn push(&mut self, value: A::Item) {
SmallVec::push(self, value);
}
}
impl<A: Array> FromIterator<A::Item> for SmallVec<A> {
fn from_iter<I: IntoIterator<Item=A::Item>>(iterable: I) -> SmallVec<A> {
let mut v = SmallVec::new();
v.extend(iterable);
v
}
}
impl<A: Array> SmallVec<A> {
pub fn extend<I: IntoIterator<Item=A::Item>>(&mut self, iterable: I) {
let iter = iterable.into_iter();
let (lower_size_bound, _) = iter.size_hint();
let target_len = self.len + lower_size_bound;
if target_len > self.capacity() {
self.grow(target_len);
}
for elem in iter {
self.push(elem);
}
}
}
impl<A: Array> fmt::Debug for SmallVec<A> where A::Item: fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", &**self)
}
}
impl<A: Array> SmallVec<A> {
#[inline]
pub fn new() -> SmallVec<A> {
unsafe {
SmallVec {
len: 0,
data: Inline { array: mem::zeroed() },
}
}
}
}
impl<A: Array> Drop for SmallVec<A> {
fn drop(&mut self) {
// Note on panic safety: dropping an element may panic,
// but the inner SmallVecData destructor will still run
unsafe {
let ptr = self.as_ptr();
for i in 0 .. self.len {
ptr::read(ptr.offset(i as isize));
}
}
}
}
impl<A: Array> Clone for SmallVec<A> where A::Item: Clone {
fn clone(&self) -> SmallVec<A> {
let mut new_vector = SmallVec::new();
for element in self.iter() {
new_vector.push((*element).clone())
}
new_vector
}
}
impl<A: Array, B: Array> PartialEq<SmallVec<B>> for SmallVec<A>
where A::Item: PartialEq<B::Item> {
#[inline]
fn eq(&self, other: &SmallVec<B>) -> bool { self[..] == other[..] }
#[inline]
fn ne(&self, other: &SmallVec<B>) -> bool { self[..] != other[..] }
}
impl<A: Array> Eq for SmallVec<A> where A::Item: Eq {}
impl<A: Array> PartialOrd for SmallVec<A> where A::Item: PartialOrd {
#[inline]
fn partial_cmp(&self, other: &SmallVec<A>) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(&**self, &**other)
}
}
impl<A: Array> Ord for SmallVec<A> where A::Item: Ord {
#[inline]
fn cmp(&self, other: &SmallVec<A>) -> cmp::Ordering {
Ord::cmp(&**self, &**other)
}
}
unsafe impl<A: Array> Send for SmallVec<A> where A::Item: Send {}
// TODO: Remove these and its users.
/// Deprecated alias to ease transition from an earlier version.
pub type SmallVec1<T> = SmallVec<[T; 1]>;
/// Deprecated alias to ease transition from an earlier version.
pub type SmallVec2<T> = SmallVec<[T; 2]>;
/// Deprecated alias to ease transition from an earlier version.
pub type SmallVec4<T> = SmallVec<[T; 4]>;
/// Deprecated alias to ease transition from an earlier version.
pub type SmallVec8<T> = SmallVec<[T; 8]>;
/// Deprecated alias to ease transition from an earlier version.
pub type SmallVec16<T> = SmallVec<[T; 16]>;
/// Deprecated alias to ease transition from an earlier version.
pub type SmallVec24<T> = SmallVec<[T; 24]>;
/// Deprecated alias to ease transition from an earlier version.
pub type SmallVec32<T> = SmallVec<[T; 32]>;
pub unsafe trait Array {
type Item;
fn size() -> usize;
fn ptr(&self) -> *const Self::Item;
fn ptr_mut(&mut self) -> *mut Self::Item;
}
macro_rules! impl_array(
($($size:expr),+) => {
$(
unsafe impl<T> Array for [T; $size] {
type Item = T;
fn size() -> usize { $size }
fn ptr(&self) -> *const T { &self[0] }
fn ptr_mut(&mut self) -> *mut T { &mut self[0] }
}
)+
}
);
impl_array!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32,
0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000,
0x10000, 0x20000, 0x40000, 0x80000, 0x100000);
#[cfg(test)]
pub mod tests {
use SmallVec;
use std::borrow::ToOwned;
// We heap allocate all these strings so that double frees will show up under valgrind.
#[test]
pub fn test_inline() {
let mut v = SmallVec::<[_; 16]>::new();
v.push("hello".to_owned());
v.push("there".to_owned());
assert_eq!(&*v, &[
"hello".to_owned(),
"there".to_owned(),
][..]);
}
#[test]
pub fn test_spill() {
let mut v = SmallVec::<[_; 2]>::new();
v.push("hello".to_owned());
assert_eq!(v[0], "hello");
v.push("there".to_owned());
v.push("burma".to_owned());
assert_eq!(v[0], "hello");
v.push("shave".to_owned());
assert_eq!(&*v, &[
"hello".to_owned(),
"there".to_owned(),
"burma".to_owned(),
"shave".to_owned(),
][..]);
}
#[test]
pub fn test_double_spill() {
let mut v = SmallVec::<[_; 2]>::new();
v.push("hello".to_owned());
v.push("there".to_owned());
v.push("burma".to_owned());
v.push("shave".to_owned());
v.push("hello".to_owned());
v.push("there".to_owned());
v.push("burma".to_owned());
v.push("shave".to_owned());
assert_eq!(&*v, &[
"hello".to_owned(),
"there".to_owned(),
"burma".to_owned(),
"shave".to_owned(),
"hello".to_owned(),
"there".to_owned(),
"burma".to_owned(),
"shave".to_owned(),
][..]);
}
/// https://github.com/servo/rust-smallvec/issues/4
#[test]
fn issue_4() {
SmallVec::<[Box<u32>; 2]>::new();
}
/// https://github.com/servo/rust-smallvec/issues/5
#[test]
fn issue_5() {
assert!(Some(SmallVec::<[&u32; 2]>::new()).is_some());
}
#[test]
fn into_iter() {
let mut v: SmallVec<[u8; 2]> = SmallVec::new();
v.push(3);
assert_eq!(v.into_iter().collect::<Vec<_>>(), &[3]);
// spilling the vec
v.push(3);
v.push(4);
v.push(5);
assert_eq!(v.into_iter().collect::<Vec<_>>(), &[3, 4, 5]);
}
#[test]
fn test_capacity() {
let mut v: SmallVec<[u8; 2]> = SmallVec::new();
v.reserve(1);
assert_eq!(v.capacity(), 2);
assert!(!v.spilled());
v.reserve_exact(0x100);
assert!(v.capacity() >= 0x100);
v.push(0);
v.push(1);
v.push(2);
v.push(3);
v.shrink_to_fit();
assert!(v.capacity() < 0x100);
}
#[test]
fn test_truncate() {
let mut v: SmallVec<[Box<u8>; 8]> = SmallVec::new();
for x in 0..8 {
v.push(Box::new(x));
}
v.truncate(4);
assert_eq!(v.len(), 4);
assert!(!v.spilled());
assert_eq!(*v.swap_remove(1), 1);
assert_eq!(*v.remove(1), 3);
v.insert(1, Box::new(3));
assert_eq!(&v.iter().map(|v| **v).collect::<Vec<_>>(), &[0, 3, 2]);
}
#[test]
#[should_panic]
fn test_drop_panic_smallvec() {
// This test should only panic once, and not double panic,
// which would mean a double drop
struct DropPanic;
impl Drop for DropPanic {
fn drop(&mut self) {
panic!("drop");
}
}
let mut v = SmallVec::<[_; 1]>::new();
v.push(DropPanic);
}
#[test]
fn test_eq() {
let mut a: SmallVec<[u32; 2]> = SmallVec::new();
let mut b: SmallVec<[u32; 2]> = SmallVec::new();
let mut c: SmallVec<[u32; 2]> = SmallVec::new();
// a = [1, 2]
a.push(1);
a.push(2);
// b = [1, 2]
b.push(1);
b.push(2);
// c = [3, 4]
c.push(3);
c.push(4);
assert!(a == b);
assert!(a != c);
}
#[test]
fn test_ord() {
let mut a: SmallVec<[u32; 2]> = SmallVec::new();
let mut b: SmallVec<[u32; 2]> = SmallVec::new();
let mut c: SmallVec<[u32; 2]> = SmallVec::new();
// a = [1]
a.push(1);
// b = [1, 1]
b.push(1);
b.push(1);
// c = [1, 2]
c.push(1);
c.push(2);
assert!(a < b);
assert!(b > a);
assert!(b < c);
assert!(c > b);
}
}

View File

@ -547,19 +547,19 @@ version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot_core"
version = "0.2.0"
version = "0.2.1"
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.20 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -802,11 +802,6 @@ name = "siphasher"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.3.2"
@ -1230,7 +1225,7 @@ dependencies = [
"checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
"checksum owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d52571ddcb42e9c900c901a18d8d67e393df723fcd51dd59c5b1a85d0acb6cc"
"checksum parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fa12d706797d42551663426a45e2db2e0364bd1dbf6aeada87e89c5f981f43e9"
"checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"
"checksum parking_lot_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56a19dcbb5d1e32b6cccb8a9aa1fc2a38418c8699652e735e2bf391a3dc0aa16"
"checksum pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ceca1642c89148ca05611cc775a0c383abef355fc4907c4e95f49f7b09d6287c"
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
@ -1254,7 +1249,6 @@ dependencies = [
"checksum serde_json 0.9.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6501ac6f8b74f9b1033f7ddf79a08edfa0f58d6f8e3190cb8dc97736afa257a8"
"checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a"
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
"checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410"
"checksum smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dca03f2f42500a9ef8ac0d16183dff8bed40e3dcf98f9d4147928548d5c4236e"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)" = "37c279fb816210c9bb28b2c292664581e7b87b4561e86b94df462664d8620bb8"

View File

@ -534,19 +534,19 @@ version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot_core"
version = "0.2.0"
version = "0.2.1"
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.20 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -789,11 +789,6 @@ name = "siphasher"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.3.2"
@ -1217,7 +1212,7 @@ dependencies = [
"checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
"checksum owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d52571ddcb42e9c900c901a18d8d67e393df723fcd51dd59c5b1a85d0acb6cc"
"checksum parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fa12d706797d42551663426a45e2db2e0364bd1dbf6aeada87e89c5f981f43e9"
"checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"
"checksum parking_lot_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56a19dcbb5d1e32b6cccb8a9aa1fc2a38418c8699652e735e2bf391a3dc0aa16"
"checksum pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ceca1642c89148ca05611cc775a0c383abef355fc4907c4e95f49f7b09d6287c"
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
@ -1241,7 +1236,6 @@ dependencies = [
"checksum serde_json 0.9.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6501ac6f8b74f9b1033f7ddf79a08edfa0f58d6f8e3190cb8dc97736afa257a8"
"checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a"
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
"checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410"
"checksum smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dca03f2f42500a9ef8ac0d16183dff8bed40e3dcf98f9d4147928548d5c4236e"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)" = "37c279fb816210c9bb28b2c292664581e7b87b4561e86b94df462664d8620bb8"