Skip to content

Commit 109b54e

Browse files
committed
remove TLS
1 parent 19c39fb commit 109b54e

10 files changed

Lines changed: 432 additions & 286 deletions

src/dragonfly_haiku.rs

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/dragonfly_haiku_emscripten.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! Implementation for DragonFly / Haiku
10+
use Error;
11+
use std::fs::File;
12+
use std::io::Read;
13+
use std::num::NonZeroU32;
14+
use std::sync::atomic::{AtomicUsize, Ordering};
15+
use std::os::unix::io::{RawFd, AsRawFd, FromRawFd};
16+
use std::{thread, mem};
17+
18+
// replace with AtomicI32 on stabilization and MSRV bump
19+
static RNG_FD: AtomicUsize = AtomicUsize::new(-1i32 as usize);
20+
// replace with AtomicU8 on stabilization and MSRV bump
21+
static RNG_STATE: AtomicUsize = AtomicUsize::new(0);
22+
23+
const STATE_INIT_ONGOING: usize = 1 << 0;
24+
const STATE_INIT_DONE: usize = 1 << 1;
25+
26+
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
27+
let fd = RNG_FD.load(Ordering::Acquire) as i32;
28+
if fd >= 0 {
29+
return use_fd(fd, dest);
30+
}
31+
let fd = loop {
32+
let state = RNG_STATE.fetch_or(STATE_INIT_ONGOING, Ordering::AcqRel);
33+
if state & STATE_INIT_DONE != 0 {
34+
// initialization is complete, use fd from atomic
35+
break RNG_FD.load(Ordering::Acquire) as RawFd;
36+
} else if state & STATE_INIT_ONGOING == 0 {
37+
// start initialization and return resulting fd
38+
match init_fd() {
39+
Ok(fd) => {
40+
RNG_STATE.store(STATE_INIT_DONE, Ordering::Release);
41+
RNG_FD.store(fd as usize, Ordering::Release);
42+
break fd
43+
},
44+
Err(err) => {
45+
RNG_STATE.store(0, Ordering::Release);
46+
return Err(err);
47+
}
48+
}
49+
}
50+
// initialization is not finished, so wait
51+
thread::yield_now();
52+
};
53+
use_fd(fd, dest)
54+
}
55+
56+
#[cfg(not(target_os = "emscripten"))]
57+
fn use_fd(fd: RawFd, dest: &mut [u8]) -> Result<(), Error> {
58+
let mut f = unsafe { File::from_raw_fd(fd) };
59+
f.read_exact(dest)?;
60+
mem::forget(f);
61+
Ok(())
62+
}
63+
64+
#[cfg(target_os = "emscripten")]
65+
fn use_fd(fd: RawFd, dest: &mut [u8]) -> Result<(), Error> {
66+
let mut f = unsafe { File::from_raw_fd(fd) };
67+
// `Crypto.getRandomValues` documents `dest` should be at most 65536
68+
// bytes. `crypto.randomBytes` documents: "To minimize threadpool
69+
// task length variation, partition large randomBytes requests when
70+
// doing so as part of fulfilling a client request.
71+
for chunk in dest.chunks_mut(65536) {
72+
f.read_exact(chunk)?;
73+
}
74+
mem::forget(f);
75+
Ok(())
76+
}
77+
78+
fn init_fd() -> Result<RawFd, Error> {
79+
let f = File::open("/dev/random")?;
80+
let fd = f.as_raw_fd();
81+
RNG_FD.store(fd as usize, Ordering::Release);
82+
mem::forget(f);
83+
Ok(fd)
84+
}
85+
86+
#[inline(always)]
87+
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

src/emscripten.rs

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/lib.rs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,6 @@ extern crate wasm_bindgen;
134134
#[cfg(not(feature = "log"))] macro_rules! error { ($($x:tt)*) => () }
135135

136136
#[cfg(any(
137-
target_os = "android",
138-
target_os = "netbsd",
139-
target_os = "solaris",
140-
target_os = "illumos",
141-
target_os = "redox",
142-
target_os = "dragonfly",
143-
target_os = "haiku",
144-
target_os = "linux",
145137
target_arch = "wasm32",
146138
))]
147139
mod utils;
@@ -164,18 +156,19 @@ macro_rules! mod_use {
164156
mod_use!(cfg(target_os = "android"), linux_android);
165157
mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig);
166158
mod_use!(cfg(target_os = "cloudabi"), cloudabi);
167-
mod_use!(cfg(target_os = "dragonfly"), dragonfly_haiku);
168-
mod_use!(cfg(target_os = "emscripten"), emscripten);
159+
mod_use!(cfg(target_os = "dragonfly"), dragonfly_haiku_emscripten);
160+
mod_use!(cfg(target_os = "emscripten"), dragonfly_haiku_emscripten);
169161
mod_use!(cfg(target_os = "freebsd"), freebsd);
170162
mod_use!(cfg(target_os = "fuchsia"), fuchsia);
171-
mod_use!(cfg(target_os = "haiku"), dragonfly_haiku);
163+
mod_use!(cfg(target_os = "haiku"), dragonfly_haiku_emscripten);
172164
mod_use!(cfg(target_os = "ios"), macos);
173165
mod_use!(cfg(target_os = "linux"), linux_android);
174166
mod_use!(cfg(target_os = "macos"), macos);
175167
mod_use!(cfg(target_os = "netbsd"), netbsd);
176168
mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig);
177169
mod_use!(cfg(target_os = "redox"), redox);
178-
mod_use!(cfg(any(target_os = "solaris", target_os = "illumos")), solarish);
170+
mod_use!(cfg(target_os = "solaris"), solaris);
171+
mod_use!(cfg(target_os = "illumos"), solaris);
179172
mod_use!(cfg(windows), windows);
180173
mod_use!(cfg(target_env = "sgx"), sgx);
181174

src/linux_android.rs

Lines changed: 78 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,77 +10,100 @@
1010
extern crate libc;
1111

1212
use Error;
13-
use utils::use_init;
1413
use std::fs::File;
15-
use std::io;
14+
use std::{io, mem, thread};
1615
use std::io::Read;
17-
use std::cell::RefCell;
1816
use std::num::NonZeroU32;
19-
use std::sync::atomic::{AtomicBool, Ordering};
17+
use std::sync::atomic::{AtomicUsize, Ordering};
18+
use std::os::unix::io::{AsRawFd, FromRawFd};
2019

21-
static RNG_INIT: AtomicBool = AtomicBool::new(false);
20+
// replace with AtomicU8 on stabilization and MSRV bump
21+
static RNG_STATE: AtomicUsize = AtomicUsize::new(0);
22+
// replace with AtomicI32 on stabilization and MSRV bump
23+
static RNG_FD: AtomicUsize = AtomicUsize::new(0);
2224

23-
enum RngSource {
24-
GetRandom,
25-
Device(File),
25+
const STATE_INIT_ONGOING: usize = 1 << 0;
26+
const STATE_USE_SYSCALL: usize = 1 << 1;
27+
const STATE_USE_FD: usize = 1 << 2;
28+
29+
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
30+
let state = RNG_STATE.load(Ordering::Acquire);
31+
if state & STATE_USE_SYSCALL != 0 {
32+
use_syscall(dest)
33+
} else if state & STATE_USE_FD != 0 {
34+
use_fd(dest)
35+
} else {
36+
init_loop(dest)
37+
}
2638
}
2739

28-
thread_local!(
29-
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
30-
);
40+
fn init_loop(dest: &mut [u8]) -> Result<(), Error> {
41+
loop {
42+
let state = RNG_STATE.fetch_or(STATE_INIT_ONGOING, Ordering::AcqRel);
3143

32-
fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
33-
let ret = unsafe {
34-
libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0)
35-
};
36-
if ret < 0 || (ret as usize) != dest.len() {
37-
error!("Linux getrandom syscall failed with return value {}", ret);
38-
return Err(io::Error::last_os_error());
44+
if state & STATE_INIT_ONGOING != 0 {
45+
thread::yield_now();
46+
continue;
47+
}
48+
return if state & STATE_USE_SYSCALL != 0 {
49+
use_syscall(dest)
50+
} else if state & STATE_USE_FD != 0 {
51+
use_fd(dest)
52+
} else {
53+
init(dest)
54+
};
3955
}
40-
Ok(())
4156
}
4257

43-
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
44-
RNG_SOURCE.with(|f| {
45-
use_init(f,
46-
|| {
47-
let s = if is_getrandom_available() {
48-
RngSource::GetRandom
49-
} else {
50-
// read one byte from "/dev/random" to ensure that
51-
// OS RNG has initialized
52-
if !RNG_INIT.load(Ordering::Relaxed) {
53-
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
54-
RNG_INIT.store(true, Ordering::Relaxed)
58+
fn init(dest: &mut [u8]) -> Result<(), Error> {
59+
match use_syscall(&mut []) {
60+
Ok(()) => {
61+
RNG_STATE.store(STATE_USE_SYSCALL, Ordering::Release);
62+
use_syscall(dest)
63+
},
64+
Err(err) if err.code().get() as i32 == libc::ENOSYS => {
65+
match init_fd() {
66+
Ok(fd) => {
67+
RNG_FD.store(fd as usize, Ordering::Release);
68+
RNG_STATE.store(STATE_USE_FD, Ordering::Release);
69+
use_fd(dest)
70+
},
71+
Err(err) => {
72+
RNG_STATE.store(0, Ordering::Release);
73+
Err(err.into())
5574
}
56-
RngSource::Device(File::open("/dev/urandom")?)
57-
};
58-
Ok(s)
59-
}, |f| {
60-
match f {
61-
RngSource::GetRandom => syscall_getrandom(dest),
62-
RngSource::Device(f) => f.read_exact(dest),
63-
}.map_err(From::from)
64-
})
65-
})
75+
}
76+
},
77+
Err(err) => Err(err),
78+
}
6679
}
6780

68-
fn is_getrandom_available() -> bool {
69-
use std::sync::{Once, ONCE_INIT};
70-
71-
static CHECKER: Once = ONCE_INIT;
72-
static AVAILABLE: AtomicBool = AtomicBool::new(false);
81+
fn init_fd() -> io::Result<i32> {
82+
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
83+
let f = File::open("/dev/urandom")?;
84+
let fd = f.as_raw_fd();
85+
mem::forget(f);
86+
Ok(fd)
87+
}
7388

74-
CHECKER.call_once(|| {
75-
let mut buf: [u8; 0] = [];
76-
let available = match syscall_getrandom(&mut buf) {
77-
Ok(()) => true,
78-
Err(err) => err.raw_os_error() != Some(libc::ENOSYS),
79-
};
80-
AVAILABLE.store(available, Ordering::Relaxed);
81-
});
89+
fn use_syscall(dest: &mut [u8]) -> Result<(), Error> {
90+
let ret = unsafe {
91+
libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0)
92+
};
93+
if ret < 0 || (ret as usize) != dest.len() {
94+
return Err(io::Error::last_os_error().into());
95+
}
96+
Ok(())
97+
}
8298

83-
AVAILABLE.load(Ordering::Relaxed)
99+
fn use_fd(dest: &mut [u8]) -> Result<(), Error> {
100+
unsafe {
101+
let fd = RNG_FD.load(Ordering::Acquire) as i32;
102+
let mut f = File::from_raw_fd(fd);
103+
f.read_exact(dest)?;
104+
mem::forget(f);
105+
}
106+
Ok(())
84107
}
85108

86109
#[inline(always)]

0 commit comments

Comments
 (0)