19
19
//! libc::dlsym.
20
20
extern crate std;
21
21
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 :: { once:: Once , utils:: use_file, Error } ;
23
+ use core:: mem;
26
24
use core:: num:: NonZeroU32 ;
25
+ use std:: io;
27
26
28
27
#[ cfg( target_os = "illumos" ) ]
29
28
type GetRandomFn = unsafe extern "C" fn ( * mut u8 , libc:: size_t , libc:: c_uint ) -> libc:: ssize_t ;
@@ -32,12 +31,10 @@ type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) ->
32
31
33
32
enum RngSource {
34
33
GetRandom ( GetRandomFn ) ,
35
- Device ( File ) ,
34
+ File ,
36
35
}
37
36
38
- thread_local ! (
39
- static RNG_SOURCE : RefCell <Option <RngSource >> = RefCell :: new( None ) ;
40
- ) ;
37
+ static RNG_SOURCE : Once < RngSource > = Once :: new ( ) ;
41
38
42
39
fn libc_getrandom ( rand : GetRandomFn , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
43
40
let ret = unsafe { rand ( dest. as_mut_ptr ( ) , dest. len ( ) , 0 ) as libc:: ssize_t } ;
@@ -51,51 +48,28 @@ fn libc_getrandom(rand: GetRandomFn, dest: &mut [u8]) -> Result<(), Error> {
51
48
}
52
49
53
50
pub fn getrandom_inner ( dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
54
- // 256 bytes is the lowest common denominator across all the Solaris
55
- // 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 } ;
51
+ let source = RNG_SOURCE . call_once ( || {
52
+ let name = "getrandom\0 " ;
53
+ let addr = unsafe { libc:: dlsym ( libc:: RTLD_DEFAULT , name. as_ptr ( ) as * const _ ) } ;
88
54
89
- static FPTR : AtomicUsize = AtomicUsize :: new ( 1 ) ;
55
+ if addr. is_null ( ) {
56
+ RngSource :: File
57
+ } else {
58
+ RngSource :: GetRandom ( unsafe { mem:: transmute ( addr) } )
59
+ }
60
+ } ) ;
90
61
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 ) ;
62
+ // 256 bytes is the lowest common denominator across all the Solaris
63
+ // derived platforms for atomically obtaining random data.
64
+ match source {
65
+ RngSource :: GetRandom ( rp) => {
66
+ for chunk in dest. chunks_mut ( 256 ) {
67
+ libc_getrandom ( * rp, chunk) ?
68
+ }
69
+ Ok ( ( ) )
70
+ }
71
+ RngSource :: File => use_file ( "/dev/urandom" , Some ( 256 ) , dest) ,
95
72
}
96
-
97
- let ptr = FPTR . load ( Ordering :: SeqCst ) ;
98
- unsafe { mem:: transmute :: < usize , Option < GetRandomFn > > ( ptr) }
99
73
}
100
74
101
75
#[ inline( always) ]
0 commit comments