-
Notifications
You must be signed in to change notification settings - Fork 192
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Structures for lock-free initialization
- Loading branch information
Showing
8 changed files
with
126 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright 2019 Developers of the Rand project. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use core::sync::atomic::{AtomicUsize, Ordering}; | ||
|
||
// This structure represents a laziliy initialized static usize value. Useful | ||
// when it is perferable to just rerun initialization instead of locking. | ||
pub struct LazyUsize(AtomicUsize); | ||
|
||
impl LazyUsize { | ||
pub const fn new() -> Self { | ||
Self(AtomicUsize::new(usize::max_value())) | ||
} | ||
|
||
// 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 usize::max_value(), the init() function | ||
// will always be retried on a future call to unsync_init(). This makes it | ||
// ideal for representing failure. | ||
pub fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { | ||
// Relaxed ordering is fine, as init() is allowed to run mulitple times. | ||
if self.0.load(Ordering::Relaxed) == usize::max_value() { | ||
self.0.store(init(), Ordering::Relaxed) | ||
} | ||
self.0.load(Ordering::Relaxed) | ||
} | ||
} | ||
|
||
// Identical to LazyUsize except with bool instead of usize. | ||
pub struct LazyBool(LazyUsize); | ||
|
||
impl LazyBool { | ||
pub const fn new() -> Self { | ||
Self(LazyUsize::new()) | ||
} | ||
|
||
pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { | ||
self.0.unsync_init(|| init() as usize) != 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright 2019 Developers of the Rand project. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use crate::util::LazyUsize; | ||
use core::marker::PhantomData; | ||
use core::mem; | ||
|
||
// A "weak" binding to a C function that may or may not be present at runtime. | ||
// Used for supporting newer OS features while still building on older systems. | ||
// F must be a function pointer of type `unsafe extern "C" fn`. Based off of the | ||
// weak! macro in libstd. | ||
pub struct Weak<F> { | ||
name: &'static str, | ||
addr: LazyUsize, | ||
_marker: PhantomData<F>, | ||
} | ||
|
||
impl<F> Weak<F> { | ||
// Construct a binding to a C function with a given name. This function is | ||
// unsafe because `name` _must_ be null terminated, and if the symbol is | ||
// present at runtime it _must_ have type F. | ||
pub const unsafe fn new(name: &'static str) -> Self { | ||
Self { | ||
name, | ||
addr: LazyUsize::new(), | ||
_marker: PhantomData, | ||
} | ||
} | ||
|
||
// Returns the function pointer if it is present at runtime. Otherwise, | ||
// return None, indicating the function does not exist. | ||
pub fn func(&self) -> Option<F> { | ||
assert_eq!(mem::size_of::<Option<F>>(), mem::size_of::<usize>()); | ||
|
||
let addr = self.addr.unsync_init(|| unsafe { | ||
libc::dlsym(libc::RTLD_DEFAULT, self.name.as_ptr() as *const _) as usize | ||
}); | ||
unsafe { mem::transmute_copy(&addr) } | ||
} | ||
} |