1919//! libc::dlsym.
2020extern crate std;
2121
22- use crate :: Error ;
23- use crate :: utils:: use_init;
24- use std:: { thread_local, io:: { self , Read } , fs:: File } ;
25- use core:: cell:: RefCell ;
22+ use crate :: { utils:: use_file, Error } ;
23+ use core:: mem;
2624use core:: num:: NonZeroU32 ;
25+ use std:: io;
26+ use lazy_static:: lazy_static;
2727
2828#[ cfg( target_os = "illumos" ) ]
2929type GetRandomFn = unsafe extern "C" fn ( * mut u8 , libc:: size_t , libc:: c_uint ) -> libc:: ssize_t ;
@@ -32,12 +32,21 @@ type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) ->
3232
3333enum RngSource {
3434 GetRandom ( GetRandomFn ) ,
35- Device ( File ) ,
35+ File ,
3636}
3737
38- thread_local ! (
39- static RNG_SOURCE : RefCell <Option <RngSource >> = RefCell :: new( None ) ;
40- ) ;
38+ lazy_static ! {
39+ static ref RNG_SOURCE : RngSource = {
40+ let name = "getrandom\0 " ;
41+ let addr = unsafe { libc:: dlsym( libc:: RTLD_DEFAULT , name. as_ptr( ) as * const _) } ;
42+
43+ if addr. is_null( ) {
44+ RngSource :: File
45+ } else {
46+ RngSource :: GetRandom ( unsafe { mem:: transmute( addr) } )
47+ }
48+ } ;
49+ }
4150
4251fn libc_getrandom ( rand : GetRandomFn , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
4352 let ret = unsafe { rand ( dest. as_mut_ptr ( ) , dest. len ( ) , 0 ) as libc:: ssize_t } ;
@@ -53,49 +62,15 @@ fn libc_getrandom(rand: GetRandomFn, dest: &mut [u8]) -> Result<(), Error> {
5362pub fn getrandom_inner ( dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
5463 // 256 bytes is the lowest common denominator across all the Solaris
5564 // derived platforms for atomically obtaining random data.
56- RNG_SOURCE . with ( |f| {
57- use_init (
58- f,
59- || {
60- let s = match fetch_getrandom ( ) {
61- Some ( fptr) => RngSource :: GetRandom ( fptr) ,
62- None => RngSource :: Device ( File :: open ( "/dev/random" ) ?) ,
63- } ;
64- Ok ( s)
65- } ,
66- |f| {
67- match f {
68- RngSource :: GetRandom ( rp) => {
69- for chunk in dest. chunks_mut ( 256 ) {
70- libc_getrandom ( * rp, chunk) ?
71- }
72- }
73- RngSource :: Device ( randf) => {
74- for chunk in dest. chunks_mut ( 256 ) {
75- randf. read_exact ( chunk) ?
76- }
77- }
78- } ;
79- Ok ( ( ) )
80- } ,
81- )
82- } )
83- }
84-
85- fn fetch_getrandom ( ) -> Option < GetRandomFn > {
86- use std:: mem;
87- use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
88-
89- static FPTR : AtomicUsize = AtomicUsize :: new ( 1 ) ;
90-
91- if FPTR . load ( Ordering :: SeqCst ) == 1 {
92- let name = "getrandom\0 " ;
93- let addr = unsafe { libc:: dlsym ( libc:: RTLD_DEFAULT , name. as_ptr ( ) as * const _ ) as usize } ;
94- FPTR . store ( addr, Ordering :: SeqCst ) ;
65+ match * RNG_SOURCE {
66+ RngSource :: GetRandom ( rp) => {
67+ for chunk in dest. chunks_mut ( 256 ) {
68+ libc_getrandom ( rp, chunk) ?
69+ }
70+ Ok ( ( ) )
71+ }
72+ RngSource :: File => use_file ( Some ( 256 ) , dest) ,
9573 }
96-
97- let ptr = FPTR . load ( Ordering :: SeqCst ) ;
98- unsafe { mem:: transmute :: < usize , Option < GetRandomFn > > ( ptr) }
9974}
10075
10176#[ inline( always) ]
0 commit comments