Skip to content

Commit 6dd0db7

Browse files
committed
Also keep only a single fd open on Redox
1 parent 1e63e4e commit 6dd0db7

File tree

1 file changed

+35
-14
lines changed

1 file changed

+35
-14
lines changed

src/os.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -530,32 +530,53 @@ mod imp {
530530
use std::fs::File;
531531
use std::io::Read;
532532
use std::io::ErrorKind::*;
533+
use std::sync::{Once, Mutex, ONCE_INIT};
533534

534535
#[derive(Debug)]
535-
pub struct OsRng {
536-
dev_random: File,
537-
}
536+
pub struct OsRng();
537+
538+
// TODO: remove outer Option when `Mutex::new(None)` is a constant expression
539+
static mut READ_RNG_FILE: Option<Mutex<Option<File>>> = None;
540+
static READ_RNG_ONCE: Once = ONCE_INIT;
538541

539542
impl OsRng {
540543
pub fn new() -> Result<OsRng, Error> {
541-
let dev_random = File::open("rand:").map_err(|err| {
542-
match err.kind() {
543-
Interrupted => Error::new(ErrorKind::Transient, "interrupted"),
544-
WouldBlock => Error::with_cause(ErrorKind::NotReady,
545-
"opening random device would block", err),
546-
_ => Error::with_cause(ErrorKind::Unavailable,
547-
"error while opening random device", err)
548-
}
549-
})?;
550-
Ok(OsRng { dev_random: dev_random })
544+
READ_RNG_ONCE.call_once(|| {
545+
unsafe { READ_RNG_FILE = Some(Mutex::new(None)) }
546+
});
547+
548+
// We try opening the file outside the `call_once` fn because we cannot
549+
// clone the error, thus we must retry on failure.
550+
551+
let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() };
552+
let mut guard = mutex.lock().unwrap();
553+
if (*guard).is_none() {
554+
info!("OsRng: opening random device 'rand:'");
555+
let file = File::open("rand:").map_err(|err| {
556+
match err.kind() {
557+
Interrupted => Error::new(ErrorKind::Transient, "interrupted"),
558+
WouldBlock => Error::with_cause(ErrorKind::NotReady,
559+
"opening random device would block", err),
560+
_ => Error::with_cause(ErrorKind::Unavailable,
561+
"error while opening random device", err)
562+
}
563+
})?;
564+
*guard = Some(file);
565+
};
566+
Ok(OsRng())
551567
}
552568

553569
pub fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
554570
if dest.len() == 0 { return Ok(()); }
555571
trace!("OsRng: reading {} bytes from random device", dest.len());
556572

573+
// Since we have an instance of Self, we can assume that our memory was
574+
// set with a valid object.
575+
let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() };
576+
let mut guard = mutex.lock().unwrap();
577+
let file = (*guard).as_mut().unwrap();
557578
// Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`.
558-
self.dev_random.read_exact(dest).map_err(|err| {
579+
file.read_exact(dest).map_err(|err| {
559580
Error::with_cause(ErrorKind::Unavailable,
560581
"error reading random device", err)
561582
})

0 commit comments

Comments
 (0)