An in-memory RNG that shares its file descriptor.

This commit is contained in:
Alan Jeffrey 2017-01-05 13:51:53 +00:00
parent 143dfc879e
commit 7ace30f9bd
15 changed files with 203 additions and 23 deletions

16
Cargo.lock generated
View file

@ -188,7 +188,7 @@ dependencies = [
"bluetooth_traits 0.0.1", "bluetooth_traits 0.0.1",
"device 0.0.1 (git+https://github.com/servo/devices)", "device 0.0.1 (git+https://github.com/servo/devices)",
"ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "servo_rand 0.0.1",
"tinyfiledialogs 2.5.9 (git+https://github.com/jdm/tinyfiledialogs)", "tinyfiledialogs 2.5.9 (git+https://github.com/jdm/tinyfiledialogs)",
"uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -436,11 +436,11 @@ dependencies = [
"offscreen_gl_context 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "offscreen_gl_context 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1", "plugins 0.0.1",
"profile_traits 0.0.1", "profile_traits 0.0.1",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"script_traits 0.0.1", "script_traits 0.0.1",
"serde 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_config 0.0.1", "servo_config 0.0.1",
"servo_rand 0.0.1",
"servo_remutex 0.0.1", "servo_remutex 0.0.1",
"servo_url 0.0.1", "servo_url 0.0.1",
"style_traits 0.0.1", "style_traits 0.0.1",
@ -2285,7 +2285,6 @@ dependencies = [
"phf_macros 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", "phf_macros 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
"plugins 0.0.1", "plugins 0.0.1",
"profile_traits 0.0.1", "profile_traits 0.0.1",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"range 0.0.1", "range 0.0.1",
"ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ref_slice 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ref_slice 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2298,6 +2297,7 @@ dependencies = [
"servo_atoms 0.0.1", "servo_atoms 0.0.1",
"servo_config 0.0.1", "servo_config 0.0.1",
"servo_geometry 0.0.1", "servo_geometry 0.0.1",
"servo_rand 0.0.1",
"servo_url 0.0.1", "servo_url 0.0.1",
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1", "style 0.0.1",
@ -2606,6 +2606,15 @@ dependencies = [
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "servo_rand"
version = "0.0.1"
dependencies = [
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "servo_remutex" name = "servo_remutex"
version = "0.0.1" version = "0.0.1"
@ -2747,7 +2756,6 @@ dependencies = [
"phf 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_codegen 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quickersort 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "quickersort 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -14,7 +14,7 @@ bitflags = "0.7"
bluetooth_traits = {path = "../bluetooth_traits"} bluetooth_traits = {path = "../bluetooth_traits"}
device = {git = "https://github.com/servo/devices", features = ["bluetooth-test"]} device = {git = "https://github.com/servo/devices", features = ["bluetooth-test"]}
ipc-channel = "0.5" ipc-channel = "0.5"
rand = "0.3" servo_rand = {path = "../rand"}
uuid = {version = "0.3.1", features = ["v4"]} uuid = {version = "0.3.1", features = ["v4"]}
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]

View file

@ -7,7 +7,7 @@ extern crate bitflags;
extern crate bluetooth_traits; extern crate bluetooth_traits;
extern crate device; extern crate device;
extern crate ipc_channel; extern crate ipc_channel;
extern crate rand; extern crate servo_rand;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
extern crate tinyfiledialogs; extern crate tinyfiledialogs;
extern crate uuid; extern crate uuid;
@ -22,7 +22,7 @@ use bluetooth_traits::scanfilter::{BluetoothScanfilter, BluetoothScanfilterSeque
use device::bluetooth::{BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic}; use device::bluetooth::{BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic};
use device::bluetooth::{BluetoothGATTDescriptor, BluetoothGATTService}; use device::bluetooth::{BluetoothGATTDescriptor, BluetoothGATTService};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use rand::Rng; use servo_rand::Rng;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::string::String; use std::string::String;
@ -397,7 +397,7 @@ impl BluetoothManager {
fn generate_device_id(&mut self) -> String { fn generate_device_id(&mut self) -> String {
let mut device_id; let mut device_id;
let mut rng = rand::thread_rng(); let mut rng = servo_rand::thread_rng();
loop { loop {
device_id = rng.gen::<u32>().to_string(); device_id = rng.gen::<u32>().to_string();
if !self.cached_devices.contains_key(&device_id) { if !self.cached_devices.contains_key(&device_id) {

View file

@ -28,12 +28,12 @@ net_traits = {path = "../net_traits"}
offscreen_gl_context = "0.5.0" offscreen_gl_context = "0.5.0"
plugins = {path = "../plugins"} plugins = {path = "../plugins"}
profile_traits = {path = "../profile_traits"} profile_traits = {path = "../profile_traits"}
rand = "0.3"
script_traits = {path = "../script_traits"} script_traits = {path = "../script_traits"}
serde = "0.8" serde = "0.8"
serde_derive = "0.8" serde_derive = "0.8"
style_traits = {path = "../style_traits"} style_traits = {path = "../style_traits"}
servo_config = {path = "../config", features = ["servo"]} servo_config = {path = "../config", features = ["servo"]}
servo_rand = {path = "../rand"}
servo_remutex = {path = "../remutex"} servo_remutex = {path = "../remutex"}
servo_url = {path = "../url", features = ["servo"]} servo_url = {path = "../url", features = ["servo"]}

View file

@ -93,7 +93,6 @@ use offscreen_gl_context::{GLContextAttributes, GLLimits};
use pipeline::{InitialPipelineState, Pipeline}; use pipeline::{InitialPipelineState, Pipeline};
use profile_traits::mem; use profile_traits::mem;
use profile_traits::time; use profile_traits::time;
use rand::{Rng, SeedableRng, StdRng, random};
use script_traits::{AnimationState, AnimationTickType, CompositorEvent}; use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg}; use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg};
use script_traits::{DocumentState, LayoutControlMsg, LoadData}; use script_traits::{DocumentState, LayoutControlMsg, LoadData};
@ -104,6 +103,7 @@ use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, W
use script_traits::{SWManagerMsg, ScopeThings, WindowSizeType}; use script_traits::{SWManagerMsg, ScopeThings, WindowSizeType};
use servo_config::opts; use servo_config::opts;
use servo_config::prefs::PREFS; use servo_config::prefs::PREFS;
use servo_rand::{Rng, SeedableRng, ServoRng, random};
use servo_remutex::ReentrantMutex; use servo_remutex::ReentrantMutex;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::borrow::ToOwned; use std::borrow::ToOwned;
@ -276,7 +276,7 @@ pub struct Constellation<Message, LTF, STF> {
/// The random number generator and probability for closing pipelines. /// The random number generator and probability for closing pipelines.
/// This is for testing the hardening of the constellation. /// This is for testing the hardening of the constellation.
random_pipeline_closure: Option<(StdRng, f32)>, random_pipeline_closure: Option<(ServoRng, f32)>,
/// Phantom data that keeps the Rust type system happy. /// Phantom data that keeps the Rust type system happy.
phantom: PhantomData<(Message, LTF, STF)>, phantom: PhantomData<(Message, LTF, STF)>,
@ -530,7 +530,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
handled_warnings: VecDeque::new(), handled_warnings: VecDeque::new(),
random_pipeline_closure: opts::get().random_pipeline_closure_probability.map(|prob| { random_pipeline_closure: opts::get().random_pipeline_closure_probability.map(|prob| {
let seed = opts::get().random_pipeline_closure_seed.unwrap_or_else(random); let seed = opts::get().random_pipeline_closure_seed.unwrap_or_else(random);
let rng = StdRng::from_seed(&[seed]); let rng = ServoRng::from_seed(&[seed]);
warn!("Randomly closing pipelines."); warn!("Randomly closing pipelines.");
info!("Using seed {} for random pipeline closure.", seed); info!("Using seed {} for random pipeline closure.", seed);
(rng, prob) (rng, prob)

View file

@ -32,12 +32,12 @@ extern crate net_traits;
extern crate offscreen_gl_context; extern crate offscreen_gl_context;
#[macro_use] #[macro_use]
extern crate profile_traits; extern crate profile_traits;
extern crate rand;
extern crate script_traits; extern crate script_traits;
extern crate serde; extern crate serde;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
extern crate servo_config; extern crate servo_config;
extern crate servo_rand;
extern crate servo_remutex; extern crate servo_remutex;
extern crate servo_url; extern crate servo_url;
extern crate style_traits; extern crate style_traits;

View file

@ -0,0 +1,15 @@
[package]
name = "servo_rand"
version = "0.0.1"
authors = ["The Servo Project Developers"]
license = "MPL-2.0"
publish = false
[lib]
name = "servo_rand"
path = "lib.rs"
[dependencies]
lazy_static = "0.2"
log = "0.3"
rand = "0.3"

158
components/rand/lib.rs Normal file
View file

@ -0,0 +1,158 @@
/* 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/. */
/// A random number generator which shares one instance of an `OsRng`.
///
/// A problem with `OsRng`, which is inherited by `StdRng` and so
/// `ThreadRng`, is that it reads from `/dev/random`, and so consumes
/// a file descriptor. For multi-threaded applications like Servo,
/// it is easy to exhaust the supply of file descriptors this way.
///
/// This crate fixes that, by only using one `OsRng`, which is just
/// used to seed and re-seed an `ServoRng`.
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate rand;
pub use rand::{Rand, Rng, SeedableRng};
#[cfg(target_pointer_width = "64")]
use rand::isaac::Isaac64Rng as IsaacWordRng;
#[cfg(target_pointer_width = "32")]
use rand::isaac::IsaacRng as IsaacWordRng;
use rand::os::OsRng;
use rand::reseeding::{ReseedingRng, Reseeder};
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;
use std::sync::Mutex;
use std::u64;
// Slightly annoying having to cast between sizes.
#[cfg(target_pointer_width = "64")]
fn as_isaac_seed(seed: &[usize]) -> &[u64] {
unsafe { mem::transmute(seed) }
}
#[cfg(target_pointer_width = "32")]
fn as_isaac_seed(seed: &[usize]) -> &[u32] {
unsafe { mem::transmute(seed) }
}
// The shared RNG which may hold on to a file descriptor
lazy_static! {
static ref OS_RNG: Mutex<OsRng> = match OsRng::new() {
Ok(r) => Mutex::new(r),
Err(e) => panic!("Failed to seed OsRng: {}", e),
};
}
// Generate 32K of data between reseedings
const RESEED_THRESHOLD: u64 = 32_768;
// An in-memory RNG that only uses the shared file descriptor for seeding and reseeding.
pub struct ServoRng {
rng: ReseedingRng<IsaacWordRng, ServoReseeder>,
}
impl Rng for ServoRng {
#[inline]
fn next_u32(&mut self) -> u32 {
self.rng.next_u32()
}
#[inline]
fn next_u64(&mut self) -> u64 {
self.rng.next_u64()
}
}
impl<'a> SeedableRng<&'a [usize]> for ServoRng {
/// Create a manually-reseeding instane of `ServoRng`.
///
/// Note that this RNG does not reseed itself, so care is needed to reseed the RNG
/// is required to be cryptographically sound.
fn from_seed(seed: &[usize]) -> ServoRng {
debug!("Creating new manually-reseeded ServoRng.");
let isaac_rng = IsaacWordRng::from_seed(as_isaac_seed(seed));
let reseeding_rng = ReseedingRng::new(isaac_rng, u64::MAX, ServoReseeder);
ServoRng { rng: reseeding_rng }
}
/// Reseed the RNG.
fn reseed(&mut self, seed: &'a [usize]) {
debug!("Manually reseeding ServoRng.");
self.rng.reseed((ServoReseeder, as_isaac_seed(seed)))
}
}
impl ServoRng {
/// Create an auto-reseeding instance of `ServoRng`.
///
/// This uses the shared `OsRng`, so avoids consuming
/// a file descriptor.
pub fn new() -> ServoRng {
debug!("Creating new ServoRng.");
let mut os_rng = OS_RNG.lock().expect("Poisoned lock.");
let isaac_rng = IsaacWordRng::rand(&mut *os_rng);
let reseeding_rng = ReseedingRng::new(isaac_rng, RESEED_THRESHOLD, ServoReseeder);
ServoRng { rng: reseeding_rng }
}
}
// The reseeder for the in-memory RNG.
struct ServoReseeder;
impl Reseeder<IsaacWordRng> for ServoReseeder {
fn reseed(&mut self, rng: &mut IsaacWordRng) {
debug!("Reseeding ServoRng.");
let mut os_rng = OS_RNG.lock().expect("Poisoned lock.");
*rng = IsaacWordRng::rand(&mut *os_rng);
}
}
impl Default for ServoReseeder {
fn default() -> ServoReseeder {
ServoReseeder
}
}
// A thread-local RNG, designed as a drop-in replacement for rand::ThreadRng.
#[derive(Clone)]
pub struct ServoThreadRng {
rng: Rc<RefCell<ServoRng>>,
}
// A thread-local RNG, designed as a drop-in replacement for rand::thread_rng.
pub fn thread_rng() -> ServoThreadRng {
SERVO_THREAD_RNG.with(|t| t.clone())
}
thread_local! {
static SERVO_THREAD_RNG: ServoThreadRng = ServoThreadRng { rng: Rc::new(RefCell::new(ServoRng::new())) };
}
impl Rng for ServoThreadRng {
fn next_u32(&mut self) -> u32 {
self.rng.borrow_mut().next_u32()
}
fn next_u64(&mut self) -> u64 {
self.rng.borrow_mut().next_u64()
}
#[inline]
fn fill_bytes(&mut self, bytes: &mut [u8]) {
self.rng.borrow_mut().fill_bytes(bytes)
}
}
// Generates a random value using the thread-local random number generator.
// A drop-in replacement for rand::random.
#[inline]
pub fn random<T: Rand>() -> T {
thread_rng().gen()
}

View file

@ -60,7 +60,6 @@ phf = "0.7.18"
phf_macros = "0.7.18" phf_macros = "0.7.18"
plugins = {path = "../plugins"} plugins = {path = "../plugins"}
profile_traits = {path = "../profile_traits"} profile_traits = {path = "../profile_traits"}
rand = "0.3"
range = {path = "../range"} range = {path = "../range"}
ref_filter_map = "1.0.1" ref_filter_map = "1.0.1"
ref_slice = "1.0" ref_slice = "1.0"
@ -73,6 +72,7 @@ serde = "0.8"
servo_atoms = {path = "../atoms"} servo_atoms = {path = "../atoms"}
servo_config = {path = "../config", features = ["servo"] } servo_config = {path = "../config", features = ["servo"] }
servo_geometry = {path = "../geometry" } servo_geometry = {path = "../geometry" }
servo_rand = {path = "../rand"}
servo_url = {path = "../url", features = ["servo"] } servo_url = {path = "../url", features = ["servo"] }
smallvec = "0.1" smallvec = "0.1"
style = {path = "../style"} style = {path = "../style"}

View file

@ -12,23 +12,23 @@ use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::globalscope::GlobalScope; use dom::globalscope::GlobalScope;
use js::jsapi::{JSContext, JSObject}; use js::jsapi::{JSContext, JSObject};
use js::jsapi::{JS_GetArrayBufferViewType, Type}; use js::jsapi::{JS_GetArrayBufferViewType, Type};
use rand::{OsRng, Rng}; use servo_rand::{ServoRng, Rng};
unsafe_no_jsmanaged_fields!(OsRng); unsafe_no_jsmanaged_fields!(ServoRng);
// https://developer.mozilla.org/en-US/docs/Web/API/Crypto // https://developer.mozilla.org/en-US/docs/Web/API/Crypto
#[dom_struct] #[dom_struct]
pub struct Crypto { pub struct Crypto {
reflector_: Reflector, reflector_: Reflector,
#[ignore_heap_size_of = "Defined in rand"] #[ignore_heap_size_of = "Defined in rand"]
rng: DOMRefCell<OsRng>, rng: DOMRefCell<ServoRng>,
} }
impl Crypto { impl Crypto {
fn new_inherited() -> Crypto { fn new_inherited() -> Crypto {
Crypto { Crypto {
reflector_: Reflector::new(), reflector_: Reflector::new(),
rng: DOMRefCell::new(OsRng::new().unwrap()), rng: DOMRefCell::new(ServoRng::new()),
} }
} }

View file

@ -29,10 +29,10 @@ use js::rust::Runtime;
use msg::constellation_msg::FrameId; use msg::constellation_msg::FrameId;
use net_traits::{IpcSend, load_whole_resource}; use net_traits::{IpcSend, load_whole_resource};
use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType}; use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
use rand::random;
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx};
use script_runtime::ScriptThreadEventCategory::WorkerEvent; use script_runtime::ScriptThreadEventCategory::WorkerEvent;
use script_traits::{TimerEvent, TimerSource, WorkerGlobalScopeInit, WorkerScriptLoadOrigin}; use script_traits::{TimerEvent, TimerSource, WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
use servo_rand::random;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::mem::replace; use std::mem::replace;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};

View file

@ -44,9 +44,9 @@ use html5ever_atoms::LocalName;
use hyper::header::{Charset, ContentDisposition, ContentType, DispositionParam, DispositionType}; use hyper::header::{Charset, ContentDisposition, ContentType, DispositionParam, DispositionType};
use hyper::method::Method; use hyper::method::Method;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use rand::random;
use script_thread::{MainThreadScriptMsg, Runnable}; use script_thread::{MainThreadScriptMsg, Runnable};
use script_traits::LoadData; use script_traits::LoadData;
use servo_rand::random;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::Cell; use std::cell::Cell;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;

View file

@ -25,10 +25,10 @@ use js::jsval::UndefinedValue;
use js::rust::Runtime; use js::rust::Runtime;
use net_traits::{load_whole_resource, IpcSend, CustomResponseMediator}; use net_traits::{load_whole_resource, IpcSend, CustomResponseMediator};
use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType}; use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
use rand::random;
use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx, ScriptChan}; use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx, ScriptChan};
use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg, WorkerScriptLoadOrigin}; use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg, WorkerScriptLoadOrigin};
use servo_config::prefs::PREFS; use servo_config::prefs::PREFS;
use servo_rand::random;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel}; use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
use std::thread; use std::thread;

View file

@ -73,7 +73,6 @@ extern crate parking_lot;
extern crate phf; extern crate phf;
#[macro_use] #[macro_use]
extern crate profile_traits; extern crate profile_traits;
extern crate rand;
extern crate range; extern crate range;
extern crate ref_filter_map; extern crate ref_filter_map;
extern crate ref_slice; extern crate ref_slice;
@ -86,6 +85,7 @@ extern crate serde;
#[macro_use] extern crate servo_atoms; #[macro_use] extern crate servo_atoms;
#[macro_use] extern crate servo_config; #[macro_use] extern crate servo_config;
extern crate servo_geometry; extern crate servo_geometry;
extern crate servo_rand;
extern crate servo_url; extern crate servo_url;
extern crate smallvec; extern crate smallvec;
#[macro_use] #[macro_use]

View file

@ -44,7 +44,6 @@ owning_ref = "0.2.2"
parking_lot = "0.3.3" parking_lot = "0.3.3"
phf = "0.7.20" phf = "0.7.20"
quickersort = "2.0.0" quickersort = "2.0.0"
rand = "0.3"
rayon = "0.6" rayon = "0.6"
rustc-serialize = "0.3" rustc-serialize = "0.3"
selectors = "0.15" selectors = "0.15"