Remove lazy_static dependancy (#52)
This commit is contained in:
committed by
Artyom Pavlov
parent
b1e81542f8
commit
0c72017424
+4
-3
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user