Skip to content

Commit 59ad091

Browse files
gbaraldiJameson Nash
authored andcommitted
Fix OncePerThread issue when building a sysimage using the current sysimage (#57656)
This is quite tricky to test unfortunately, but #57544 caught this and this fixes that --------- Co-authored-by: Jameson Nash <[email protected]> (cherry picked from commit bf01638)
1 parent 3778b80 commit 59ad091

File tree

2 files changed

+63
-11
lines changed

2 files changed

+63
-11
lines changed

base/lock.jl

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -702,10 +702,6 @@ mutable struct OncePerProcess{T, F} <: Function
702702

703703
function OncePerProcess{T,F}(initializer::F) where {T, F}
704704
once = new{T,F}(nothing, PerStateInitial, true, initializer, ReentrantLock())
705-
ccall(:jl_set_precompile_field_replace, Cvoid, (Any, Any, Any),
706-
once, :value, nothing)
707-
ccall(:jl_set_precompile_field_replace, Cvoid, (Any, Any, Any),
708-
once, :state, PerStateInitial)
709705
return once
710706
end
711707
end
@@ -721,6 +717,10 @@ OncePerProcess(initializer) = OncePerProcess{Base.promote_op(initializer), typeo
721717
try
722718
state = @atomic :monotonic once.state
723719
if state == PerStateInitial
720+
ccall(:jl_set_precompile_field_replace, Cvoid, (Any, Any, Any),
721+
once, :value, nothing)
722+
ccall(:jl_set_precompile_field_replace, Cvoid, (Any, Any, Any),
723+
once, :state, PerStateInitial)
724724
once.value = once.initializer()
725725
elseif state == PerStateErrored
726726
error("OncePerProcess initializer failed previously")
@@ -809,10 +809,6 @@ mutable struct OncePerThread{T, F} <: Function
809809
function OncePerThread{T,F}(initializer::F) where {T, F}
810810
xs, ss = AtomicMemory{T}(), AtomicMemory{UInt8}()
811811
once = new{T,F}(xs, ss, initializer)
812-
ccall(:jl_set_precompile_field_replace, Cvoid, (Any, Any, Any),
813-
once, :xs, xs)
814-
ccall(:jl_set_precompile_field_replace, Cvoid, (Any, Any, Any),
815-
once, :ss, ss)
816812
return once
817813
end
818814
end
@@ -849,6 +845,12 @@ OncePerThread(initializer) = OncePerThread{Base.promote_op(initializer), typeof(
849845
ss = @atomic :monotonic once.ss
850846
xs = @atomic :monotonic once.xs
851847
if tid > length(ss)
848+
if length(ss) == 0 # We are the first to initialize
849+
ccall(:jl_set_precompile_field_replace, Cvoid, (Any, Any, Any),
850+
once, :xs, xs)
851+
ccall(:jl_set_precompile_field_replace, Cvoid, (Any, Any, Any),
852+
once, :ss, ss)
853+
end
852854
@assert len <= length(ss) <= length(newss) "logical constraint violation"
853855
fill_monotonic!(newss, PerStateInitial)
854856
xs = copyto_monotonic!(newxs, xs)

test/compileall.jl

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,60 @@
22
# We make it a separate test target here, so that it can run in parallel
33
# with the rest of the tests.
44

5-
mktempdir() do dir
6-
@test success(pipeline(`$(Base.julia_cmd()) --compile=all --strip-ir --output-o $(dir)/sys.o.a -e 'exit()'`, stderr=stderr)) skip=(Sys.WORD_SIZE == 32)
5+
function precompile_test_harness(@nospecialize(f))
6+
load_path = mktempdir()
7+
try
8+
pushfirst!(LOAD_PATH, load_path)
9+
pushfirst!(DEPOT_PATH, load_path)
10+
f(load_path)
11+
finally
12+
try
13+
rm(load_path, force=true, recursive=true)
14+
catch err
15+
@show err
16+
end
17+
filter!(()(load_path), LOAD_PATH)
18+
filter!(()(load_path), DEPOT_PATH)
19+
end
20+
return nothing
21+
end
22+
23+
precompile_test_harness() do dir
24+
Foo_file = joinpath(dir, "OncePerFoo.jl")
25+
image_file = joinpath(dir, "img.jl")
26+
write(Foo_file,
27+
"""module OncePerFoo
28+
29+
const f = OncePerThread{Nothing}() do
30+
println(Core.stdout, "Running thread init...")
31+
end
32+
33+
f() # Executed during pre-compilation
34+
35+
end # module OncePerFoo
36+
""")
37+
38+
write(image_file,
39+
"""
40+
Base.init_depot_path()
41+
Base.init_load_path()
42+
using OncePerFoo
43+
44+
function main()
45+
OncePerFoo.f()
46+
return 0
47+
end
48+
49+
OncePerFoo.f() # fire init during compilation time
50+
51+
""")
52+
Base.compilecache(Base.PkgId("OncePerFoo"))
53+
new_env = Dict(["JULIA_DEPOT_PATH" => join(DEPOT_PATH, Sys.iswindows() ? ';' : ':'),
54+
"JULIA_LOAD_PATH" => join(LOAD_PATH, Sys.iswindows() ? ';' : ':')])
55+
@test success(pipeline(addenv(`$(Base.julia_cmd()) --compile=all -t1,0 --strip-ir --output-o $(dir)/sys.o.a $(image_file) `, new_env), stderr=stderr, stdout=stdout)) skip=(Sys.WORD_SIZE == 32)
756
if isfile(joinpath(dir, "sys.o.a"))
857
Base.Linking.link_image(joinpath(dir, "sys.o.a"), joinpath(dir, "sys.so"))
9-
@test success(`$(Base.julia_cmd()) -J $(dir)/sys.so -e 'Base.scrub_repl_backtrace(nothing); exit()'`)
58+
str = readchomp(`$(Base.julia_cmd()) -t1,0 -J $(dir)/sys.so -e 'Base.scrub_repl_backtrace(nothing); println("loaded"); main()'`)
59+
@test split(str, '\n') == ["loaded", "Running thread init..."]
1060
end
1161
end

0 commit comments

Comments
 (0)