@@ -23,16 +23,26 @@ else # !windows
23
23
rand (rd:: RandomDevice , sp:: SamplerBoolBitInteger ) = read (getfile (rd), sp[])
24
24
rand (rd:: RandomDevice , :: SamplerType{Bool} ) = read (getfile (rd), UInt8) % Bool
25
25
26
- function getfile (rd:: RandomDevice )
27
- devrandom = rd. unlimited ? DEV_URANDOM : DEV_RANDOM
28
- # TODO : there is a data-race, this can leak up to nthreads() copies of the file descriptors,
29
- # so use a "thread-once" utility once available
30
- isassigned (devrandom) || (devrandom[] = open (rd. unlimited ? " /dev/urandom" : " /dev/random" ))
31
- devrandom[]
26
+ mutable struct FileRef
27
+ @atomic file:: Union{IOStream, Nothing}
32
28
end
33
29
34
- const DEV_RANDOM = Ref {IOStream} ()
35
- const DEV_URANDOM = Ref {IOStream} ()
30
+ const DEV_RANDOM = FileRef (nothing )
31
+ const DEV_URANDOM = FileRef (nothing )
32
+
33
+ function getfile (rd:: RandomDevice )
34
+ ref = rd. unlimited ? DEV_URANDOM : DEV_RANDOM
35
+ fd = ref. file
36
+ if fd === nothing
37
+ fd = open (rd. unlimited ? " /dev/urandom" : " /dev/random" )
38
+ old, ok = @atomicreplace ref. file nothing => fd
39
+ if ! ok
40
+ close (fd)
41
+ fd = old:: IOStream
42
+ end
43
+ end
44
+ return fd
45
+ end
36
46
37
47
end # os-test
38
48
@@ -411,6 +421,10 @@ for T in BitInteger_types
411
421
end
412
422
413
423
function __init__ ()
424
+ @static if ! Sys. iswindows ()
425
+ @atomic DEV_RANDOM. file = nothing
426
+ @atomic DEV_URANDOM. file = nothing
427
+ end
414
428
seed! (GLOBAL_RNG)
415
429
end
416
430
0 commit comments