# This file is a part of Julia. License is MIT: https://julialang.org/license
# This file contains the minimal support of RandomDevice for Base's own usage.
# The actual RandomDevice type that makes use of this infrastructure is defined
# in the Random stdlib.
module DevRandomState
if !Sys.iswindows()
mutable struct FileRef
@atomic file::Union{IOStream, Nothing}
end
const DEV_RANDOM = FileRef(nothing)
const DEV_URANDOM = FileRef(nothing)
end
function __init__()
if !Sys.iswindows()
@atomic DEV_RANDOM.file = nothing
@atomic DEV_URANDOM.file = nothing
end
end
end
if Sys.iswindows()
function RtlGenRandom!(A::Union{Array, Ref})
Base.windowserror("SystemFunction036 (RtlGenRandom)", 0 == ccall(
(:SystemFunction036, :Advapi32), stdcall, UInt8, (Ptr{Cvoid}, UInt32),
A, sizeof(A)))
end
# Manually implemented to work without the Random machinery
function _rand_uint()
r = Ref{Cuint}()
RtlGenRandom!(r)
return r[]
end
else # !windows
function _get_dev_random_fd(unlimited::Bool)
ref = unlimited ? DevRandomState.DEV_URANDOM : DevRandomState.DEV_RANDOM
fd = ref.file
if fd === nothing
fd = open(unlimited ? "/dev/urandom" : "/dev/random")
old, ok = @atomicreplace ref.file nothing => fd
if !ok
close(fd)
fd = old::IOStream
end
end
return fd
end
# Manually implemented to work without the Random machinery
function _rand_uint()
return read(_get_dev_random_fd(true), Cuint)
end
end # os-test
function _ad_hoc_entropy()
println(stderr,
"Entropy pool not available to seed RNG; using ad-hoc entropy sources.")
seed = reinterpret(UInt64, time())
seed = hash(seed, getpid() % UInt)
try
seed = hash(seed, parse(UInt64,
read(pipeline(`ifconfig`, `sha1sum`), String)[1:40],
base = 16) % UInt)
catch
end
return seed
end
function _make_uint_seed()
try
_rand_uint()
catch
return _ad_hoc_entropy() % Cuint
end
end