Skip to content

Commit a47b8ce

Browse files
committed
Move Weak into a separate module
1 parent cf65e83 commit a47b8ce

File tree

4 files changed

+70
-69
lines changed

4 files changed

+70
-69
lines changed

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ cfg_if! {
306306
#[path = "solaris.rs"] mod imp;
307307
} else if #[cfg(target_os = "netbsd")] {
308308
mod util_libc;
309+
mod weak;
309310
#[path = "netbsd.rs"] mod imp;
310311
} else if #[cfg(target_os = "fuchsia")] {
311312
#[path = "fuchsia.rs"] mod imp;

src/netbsd.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
//! Implementation for NetBSD
2-
use crate::{
3-
util_libc::{sys_fill_exact, Weak},
4-
Error,
5-
};
6-
use core::{mem::MaybeUninit, ptr};
2+
use crate::{util_libc::sys_fill_exact, weak::Weak, Error};
3+
use core::{ffi::c_void, mem::MaybeUninit, ptr};
74

85
fn kern_arnd(buf: &mut [MaybeUninit<u8>]) -> libc::ssize_t {
96
static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND];
@@ -28,8 +25,14 @@ fn kern_arnd(buf: &mut [MaybeUninit<u8>]) -> libc::ssize_t {
2825
type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t;
2926

3027
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
28+
fn link_getrandom() -> *mut c_void {
29+
static NAME: &[u8] = b"getrandom\0";
30+
unsafe { libc::dlsym(libc::RTLD_DEFAULT, NAME.as_ptr() as *const _) }
31+
}
32+
3133
// getrandom(2) was introduced in NetBSD 10.0
32-
static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") };
34+
static GETRANDOM: Weak = Weak::new(link_getrandom);
35+
3336
if let Some(fptr) = GETRANDOM.ptr() {
3437
let func: GetRandomFn = unsafe { core::mem::transmute(fptr) };
3538
return sys_fill_exact(dest, |buf| unsafe {

src/util_libc.rs

+1-63
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
#![allow(dead_code)]
22
use crate::Error;
3-
use core::{
4-
mem::MaybeUninit,
5-
num::NonZeroU32,
6-
ptr::NonNull,
7-
sync::atomic::{fence, AtomicPtr, Ordering},
8-
};
9-
use libc::c_void;
3+
use core::{mem::MaybeUninit, num::NonZeroU32};
104

115
cfg_if! {
126
if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] {
@@ -76,62 +70,6 @@ pub fn sys_fill_exact(
7670
Ok(())
7771
}
7872

79-
// A "weak" binding to a C function that may or may not be present at runtime.
80-
// Used for supporting newer OS features while still building on older systems.
81-
// Based off of the DlsymWeak struct in libstd:
82-
// https://github.com/rust-lang/rust/blob/1.61.0/library/std/src/sys/unix/weak.rs#L84
83-
// except that the caller must manually cast self.ptr() to a function pointer.
84-
pub struct Weak {
85-
name: &'static str,
86-
addr: AtomicPtr<c_void>,
87-
}
88-
89-
impl Weak {
90-
// A non-null pointer value which indicates we are uninitialized. This
91-
// constant should ideally not be a valid address of a function pointer.
92-
// However, if by chance libc::dlsym does return UNINIT, there will not
93-
// be undefined behavior. libc::dlsym will just be called each time ptr()
94-
// is called. This would be inefficient, but correct.
95-
// TODO: Replace with core::ptr::invalid_mut(1) when that is stable.
96-
const UNINIT: *mut c_void = 1 as *mut c_void;
97-
98-
// Construct a binding to a C function with a given name. This function is
99-
// unsafe because `name` _must_ be null terminated.
100-
pub const unsafe fn new(name: &'static str) -> Self {
101-
Self {
102-
name,
103-
addr: AtomicPtr::new(Self::UNINIT),
104-
}
105-
}
106-
107-
// Return the address of a function if present at runtime. Otherwise,
108-
// return None. Multiple callers can call ptr() concurrently. It will
109-
// always return _some_ value returned by libc::dlsym. However, the
110-
// dlsym function may be called multiple times.
111-
pub fn ptr(&self) -> Option<NonNull<c_void>> {
112-
// Despite having only a single atomic variable (self.addr), we still
113-
// cannot always use Ordering::Relaxed, as we need to make sure a
114-
// successful call to dlsym() is "ordered before" any data read through
115-
// the returned pointer (which occurs when the function is called).
116-
// Our implementation mirrors that of the one in libstd, meaning that
117-
// the use of non-Relaxed operations is probably unnecessary.
118-
match self.addr.load(Ordering::Relaxed) {
119-
Self::UNINIT => {
120-
let symbol = self.name.as_ptr() as *const _;
121-
let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, symbol) };
122-
// Synchronizes with the Acquire fence below
123-
self.addr.store(addr, Ordering::Release);
124-
NonNull::new(addr)
125-
}
126-
addr => {
127-
let func = NonNull::new(addr)?;
128-
fence(Ordering::Acquire);
129-
Some(func)
130-
}
131-
}
132-
}
133-
}
134-
13573
// SAFETY: path must be null terminated, FD must be manually closed.
13674
pub unsafe fn open_readonly(path: &str) -> Result<libc::c_int, Error> {
13775
debug_assert_eq!(path.as_bytes().last(), Some(&0));

src/weak.rs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use core::{
2+
ffi::c_void,
3+
ptr::NonNull,
4+
sync::atomic::{fence, AtomicPtr, Ordering},
5+
};
6+
7+
// A "weak" binding to a C function that may or may not be present at runtime.
8+
// Used for supporting newer OS features while still building on older systems.
9+
// Based off of the DlsymWeak struct in libstd:
10+
// https://github.com/rust-lang/rust/blob/1.61.0/library/std/src/sys/unix/weak.rs#L84
11+
// except that the caller must manually cast self.ptr() to a function pointer.
12+
pub struct Weak {
13+
addr: AtomicPtr<c_void>,
14+
link_fn: fn() -> *mut c_void,
15+
}
16+
17+
impl Weak {
18+
// A non-null pointer value which indicates we are uninitialized. This
19+
// constant should ideally not be a valid address of a function pointer.
20+
// However, if by chance libc::dlsym does return UNINIT, there will not
21+
// be undefined behavior. libc::dlsym will just be called each time ptr()
22+
// is called. This would be inefficient, but correct.
23+
// TODO: Replace with core::ptr::invalid_mut(1) when that is stable.
24+
const UNINIT: *mut c_void = 1 as *mut c_void;
25+
26+
// Construct a weak binding a C function.
27+
pub const fn new(link_fn: fn() -> *mut c_void) -> Self {
28+
Self {
29+
addr: AtomicPtr::new(Self::UNINIT),
30+
link_fn,
31+
}
32+
}
33+
34+
// Return the address of a function if present at runtime. Otherwise,
35+
// return None. Multiple callers can call ptr() concurrently. It will
36+
// always return _some_ value returned by libc::dlsym. However, the
37+
// dlsym function may be called multiple times.
38+
pub fn ptr(&self) -> Option<NonNull<c_void>> {
39+
// Despite having only a single atomic variable (self.addr), we still
40+
// cannot always use Ordering::Relaxed, as we need to make sure a
41+
// successful call to dlsym() is "ordered before" any data read through
42+
// the returned pointer (which occurs when the function is called).
43+
// Our implementation mirrors that of the one in libstd, meaning that
44+
// the use of non-Relaxed operations is probably unnecessary.
45+
match self.addr.load(Ordering::Relaxed) {
46+
Self::UNINIT => {
47+
let addr = (self.link_fn)();
48+
// Synchronizes with the Acquire fence below
49+
self.addr.store(addr, Ordering::Release);
50+
NonNull::new(addr)
51+
}
52+
addr => {
53+
let func = NonNull::new(addr)?;
54+
fence(Ordering::Acquire);
55+
Some(func)
56+
}
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)