Skip to content

Commit

Permalink
Use OS-level blocking in LazyUsize
Browse files Browse the repository at this point in the history
  • Loading branch information
matklad committed Jan 1, 2020
1 parent d661aa7 commit a7dc21f
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 24 deletions.
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
html_root_url = "https://rust-random.github.io/rand/"
)]
#![no_std]
#![cfg_attr(feature = "stdweb", recursion_limit = "128")]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]

Expand Down
39 changes: 16 additions & 23 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,17 @@ use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
// }
// the effects of c() or writes to shared memory will not necessarily be
// observed and additional synchronization methods with be needed.
pub struct LazyUsize(AtomicUsize);
pub struct LazyUsize {
value: AtomicUsize,
once: std::sync::Once,
}

impl LazyUsize {
pub const fn new() -> Self {
Self(AtomicUsize::new(Self::UNINIT))
Self {
value: AtomicUsize::new(Self::UNINIT),
once: std::sync::Once::new(),
}
}

// The initialization is not completed.
Expand All @@ -43,10 +49,10 @@ impl LazyUsize {
// 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(Relaxed);
let mut val = self.value.load(Relaxed);
if val == Self::UNINIT {
val = init();
self.0.store(val, Relaxed);
self.value.store(val, Relaxed);
}
val
}
Expand All @@ -57,28 +63,15 @@ impl LazyUsize {
// and future calls to sync_init will rerun their init() function.
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) {
match self.value.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(
match val {
Self::UNINIT | Self::ACTIVE => Self::UNINIT,
val => val,
},
Relaxed,
);
return val;
}
Self::ACTIVE => wait(),
val => return val,
}
}
self.once.call_once(|| {
let val = init();
self.value.store(val, Relaxed);
});
return self.value.load(Relaxed);
}
}

Expand Down

0 comments on commit a7dc21f

Please sign in to comment.