Remove lazy_static dependancy (#52)

This commit is contained in:
Joseph Richey
2019-07-04 08:29:48 -07:00
committed by Artyom Pavlov
parent b1e81542f8
commit 0c72017424
7 changed files with 107 additions and 34 deletions
+4 -3
View File
@@ -102,13 +102,14 @@ matrix:
- rust: nightly
env: DESCRIPTION="cross-platform build only"
# Redox: wait for https://github.com/rust-lang/rust/issues/60139
install:
- rustup target add x86_64-sun-solaris
- rustup target add x86_64-unknown-cloudabi
- rustup target add x86_64-unknown-freebsd
- rustup target add x86_64-fuchsia
- rustup target add x86_64-unknown-netbsd
- rustup target add x86_64-unknown-redox
# - rustup target add x86_64-unknown-redox
- rustup target add x86_64-fortanix-unknown-sgx
# For no_std targets
- rustup component add rust-src
@@ -119,7 +120,7 @@ matrix:
- cargo build --target=x86_64-unknown-freebsd --all-features
- cargo build --target=x86_64-fuchsia --all-features
- cargo build --target=x86_64-unknown-netbsd --all-features
- cargo build --target=x86_64-unknown-redox --all-features
# - cargo build --target=x86_64-unknown-redox --all-features
- cargo build --target=x86_64-fortanix-unknown-sgx --all-features
- cargo xbuild --target=x86_64-unknown-uefi
# also test minimum dependency versions are usable
@@ -129,7 +130,7 @@ matrix:
- cargo build --target=x86_64-unknown-freebsd --all-features
- cargo build --target=x86_64-fuchsia --all-features
- cargo build --target=x86_64-unknown-netbsd --all-features
- cargo build --target=x86_64-unknown-redox --all-features
# - cargo build --target=x86_64-unknown-redox --all-features
- cargo build --target=x86_64-fortanix-unknown-sgx --all-features
- cargo xbuild --target=x86_64-unknown-uefi
+1 -6
View File
@@ -20,17 +20,12 @@ members = ["tests/wasm_bindgen"]
[dependencies]
log = { version = "0.4", optional = true }
[target.'cfg(any(unix, target_os = "wasi"))'.dependencies]
[target.'cfg(any(unix, target_os = "redox", target_os = "wasi"))'.dependencies]
libc = "0.2.54"
# For holding file descriptors
[target.'cfg(any(unix, target_os = "redox"))'.dependencies]
lazy_static = "1.3.0"
[target.wasm32-unknown-unknown.dependencies]
wasm-bindgen = { version = "0.2.29", optional = true }
stdweb = { version = "0.4.9", optional = true }
lazy_static = "1.3.0"
[features]
std = []
+3 -3
View File
@@ -142,11 +142,11 @@ extern crate std;
mod error;
pub use crate::error::Error;
#[allow(dead_code)]
mod util;
// These targets need weak linkage to libc randomness functions.
#[cfg(any(target_os = "macos", target_os = "solaris", target_os = "illumos"))]
#[cfg(any(unix, target_os = "redox"))]
#[allow(dead_code)]
mod util_libc;
// System-specific implementations.
+19 -11
View File
@@ -9,10 +9,15 @@
//! Implementations that just need to read from a file
extern crate std;
use crate::util_libc::LazyFd;
use crate::Error;
use core::mem::ManuallyDrop;
use core::num::NonZeroU32;
use lazy_static::lazy_static;
use std::{fs::File, io::Read};
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
use std::{
fs::File,
io::{self, Read},
};
#[cfg(target_os = "redox")]
const FILE_PATH: &str = "rand:";
@@ -29,28 +34,31 @@ const FILE_PATH: &str = "/dev/urandom";
const FILE_PATH: &str = "/dev/random";
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
lazy_static! {
static ref FILE: Result<File, Error> = init_file();
}
let mut f = FILE.as_ref()?;
static FD: LazyFd = LazyFd::new();
let fd = FD.init(init_file).ok_or(io::Error::last_os_error())?;
let file = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) });
let mut file_ref: &File = &file;
if cfg!(target_os = "emscripten") {
// `Crypto.getRandomValues` documents `dest` should be at most 65536 bytes.
for chunk in dest.chunks_mut(65536) {
f.read_exact(chunk)?;
file_ref.read_exact(chunk)?;
}
} else {
f.read_exact(dest)?;
file_ref.read_exact(dest)?;
}
Ok(())
}
fn init_file() -> Result<File, Error> {
fn init_file() -> Option<RawFd> {
if FILE_PATH == "/dev/urandom" {
// read one byte from "/dev/random" to ensure that OS RNG has initialized
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
File::open("/dev/random")
.ok()?
.read_exact(&mut [0u8; 1])
.ok()?;
}
Ok(File::open(FILE_PATH)?)
Some(File::open(FILE_PATH).ok()?.into_raw_fd())
}
#[inline(always)]
+46 -6
View File
@@ -6,10 +6,26 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use core::sync::atomic::{AtomicUsize, Ordering};
use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
// This structure represents a laziliy initialized static usize value. Useful
// when it is perferable to just rerun initialization instead of locking.
// Both unsync_init and sync_init will invoke an init() function until it
// succeeds, then return the cached value for future calls.
//
// Both methods support init() "failing". If the init() method returns UNINIT,
// that value will be returned as normal, but will not be cached.
//
// Users should only depend on the _value_ returned by init() functions.
// Specifically, for the following init() function:
// fn init() -> usize {
// a();
// let v = b();
// c();
// v
// }
// the effects of c() or writes to shared memory will not necessarily be
// observed and additional syncronization methods with be needed.
pub struct LazyUsize(AtomicUsize);
impl LazyUsize {
@@ -19,20 +35,44 @@ impl LazyUsize {
// The initialization is not completed.
pub const UNINIT: usize = usize::max_value();
// The initialization is currently running.
pub const ACTIVE: usize = usize::max_value() - 1;
// Runs the init() function at least once, returning the value of some run
// of init(). Unlike std::sync::Once, the init() function may be run
// multiple times. If init() returns UNINIT, future calls to unsync_init()
// will always retry. This makes UNINIT ideal for representing failure.
// of init(). Multiple callers can run their init() functions in parallel.
// init() should always return the same value, if it succeeds.
pub fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize {
// Relaxed ordering is fine, as we only have a single atomic variable.
let mut val = self.0.load(Ordering::Relaxed);
let mut val = self.0.load(Relaxed);
if val == Self::UNINIT {
val = init();
self.0.store(val, Ordering::Relaxed);
self.0.store(val, Relaxed);
}
val
}
// Synchronously runs the init() function. Only one caller will have their
// init() function running at a time, and exactly one successful call will
// be run. The init() function should never return LazyUsize::ACTIVE.
pub fn sync_init(&self, init: impl FnOnce() -> usize, mut wait: impl FnMut()) -> usize {
// Common and fast path with no contention. Don't wast time on CAS.
match self.0.load(Relaxed) {
Self::UNINIT | Self::ACTIVE => {}
val => return val,
}
// Relaxed ordering is fine, as we only have a single atomic variable.
loop {
match self.0.compare_and_swap(Self::UNINIT, Self::ACTIVE, Relaxed) {
Self::UNINIT => {
let val = init();
self.0.store(val, Relaxed);
return val;
}
Self::ACTIVE => wait(),
val => return val,
}
}
}
}
// Identical to LazyUsize except with bool instead of usize.
+26
View File
@@ -36,3 +36,29 @@ impl Weak {
NonNull::new(addr as *mut _)
}
}
pub struct LazyFd(LazyUsize);
impl LazyFd {
pub const fn new() -> Self {
Self(LazyUsize::new())
}
// If init() returns Some(x), x should be nonnegative.
pub fn init(&self, init: impl FnOnce() -> Option<libc::c_int>) -> Option<libc::c_int> {
let fd = self.0.sync_init(
|| match init() {
// OK as val >= 0 and val <= c_int::MAX < usize::MAX
Some(val) => val as usize,
None => LazyUsize::UNINIT,
},
|| unsafe {
libc::usleep(1000);
},
);
match fd {
LazyUsize::UNINIT => None,
val => Some(val as libc::c_int),
}
}
}
+8 -5
View File
@@ -15,7 +15,7 @@ use stdweb::web::error::Error as WebError;
use stdweb::{_js_impl, js};
use crate::Error;
use lazy_static::lazy_static;
use std::sync::Once;
#[derive(Clone, Copy, Debug)]
enum RngSource {
@@ -25,11 +25,14 @@ enum RngSource {
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
assert_eq!(mem::size_of::<usize>(), 4);
static ONCE: Once = Once::new();
static mut RNG_SOURCE: Result<RngSource, Error> = Err(Error::UNAVAILABLE);
lazy_static! {
static ref RNG_SOURCE: Result<RngSource, Error> = getrandom_init();
}
getrandom_fill((*RNG_SOURCE)?, dest)
// SAFETY: RNG_SOURCE is only written once, before being read.
ONCE.call_once(|| unsafe {
RNG_SOURCE = getrandom_init();
});
getrandom_fill(unsafe { RNG_SOURCE }?, dest)
}
fn getrandom_init() -> Result<RngSource, Error> {