Skip to content

Commit c74814e

Browse files
authored
reset RandomDevice file from __init__ (#42537)
This prevents us from seeing an invalid `IOStream` object from a saved system image, and also ensures the files are opened once for all threads.
1 parent 05ed348 commit c74814e

File tree

1 file changed

+22
-8
lines changed

1 file changed

+22
-8
lines changed

stdlib/Random/src/RNGs.jl

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,26 @@ else # !windows
2323
rand(rd::RandomDevice, sp::SamplerBoolBitInteger) = read(getfile(rd), sp[])
2424
rand(rd::RandomDevice, ::SamplerType{Bool}) = read(getfile(rd), UInt8) % Bool
2525

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}
3228
end
3329

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
3646

3747
end # os-test
3848

@@ -411,6 +421,10 @@ for T in BitInteger_types
411421
end
412422

413423
function __init__()
424+
@static if !Sys.iswindows()
425+
@atomic DEV_RANDOM.file = nothing
426+
@atomic DEV_URANDOM.file = nothing
427+
end
414428
seed!(GLOBAL_RNG)
415429
end
416430

0 commit comments

Comments
 (0)