From 1f6c479f806cf74573b3235bd87c9e1ecaefcd88 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 29 Jan 2024 14:51:11 -0500 Subject: [PATCH 1/3] shortcut if cycle detected in extension precompilation --- base/loading.jl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index 8bcaa4b2ab5b3..55eeb8d076043 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1438,6 +1438,13 @@ function run_extension_callbacks(pkgid::PkgId) extids = pop!(EXT_DORMITORY, pkgid, nothing) extids === nothing && return for extid in extids + if in(extid.id, precompilation_stack) && !isprecompiled(extid.id) + @debug """ + Dependency cycle detected in extension precompilation: $(precompilation_stack_list()) > $(extid.id.name) + $(extid.id.name) will not be loaded here. + """ + continue + end if extid.ntriggers > 0 # indicate pkgid is loaded extid.ntriggers -= 1 @@ -2569,14 +2576,14 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o:: end const precompilation_stack = Vector{PkgId}() +precompilation_stack_list() = join(map(p->p.name, precompilation_stack), " > ") # Helpful for debugging when precompilation is unexpectedly nested. # Enable with `JULIA_DEBUG=nested_precomp`. Note that it expected to be nested in classical code-load precompilation # TODO: Add detection if extension precompilation is nested and error / return early? function track_nested_precomp(pkgs::Vector{PkgId}) append!(precompilation_stack, pkgs) if length(precompilation_stack) > 1 - list() = join(map(p->p.name, precompilation_stack), " > ") - @debug "Nested precompilation: $(list())" _group=:nested_precomp + @debug "Nested precompilation: $(precompilation_stack_list())" _group=:nested_precomp end end From 00f7b3f4edfe6f1938cc15801afd409c2cf91f61 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Wed, 14 Feb 2024 22:27:32 -0500 Subject: [PATCH 2/3] rm isprecompiled check --- base/loading.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/loading.jl b/base/loading.jl index 55eeb8d076043..16a1e12cb6c2a 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1438,7 +1438,7 @@ function run_extension_callbacks(pkgid::PkgId) extids = pop!(EXT_DORMITORY, pkgid, nothing) extids === nothing && return for extid in extids - if in(extid.id, precompilation_stack) && !isprecompiled(extid.id) + if in(extid.id, precompilation_stack) @debug """ Dependency cycle detected in extension precompilation: $(precompilation_stack_list()) > $(extid.id.name) $(extid.id.name) will not be loaded here. From 33d9e2a3ca209b4bd73fd4efe5e18a35ace47b34 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Wed, 14 Feb 2024 22:28:24 -0500 Subject: [PATCH 3/3] add test --- test/extensions/circular/A/Project.toml | 14 +++++++++++ test/extensions/circular/A/ext/CExt.jl | 3 +++ test/extensions/circular/A/ext/DExt.jl | 3 +++ test/extensions/circular/A/src/A.jl | 3 +++ test/extensions/circular/B/Project.toml | 7 ++++++ test/extensions/circular/B/src/B.jl | 3 +++ test/extensions/circular/C/Project.toml | 3 +++ test/extensions/circular/C/src/C.jl | 3 +++ test/extensions/circular/D/Project.toml | 3 +++ test/extensions/circular/D/src/D.jl | 3 +++ test/extensions/circular/Manifest.toml | 32 +++++++++++++++++++++++++ test/extensions/circular/Project.toml | 5 ++++ test/loading.jl | 7 ++++++ 13 files changed, 89 insertions(+) create mode 100644 test/extensions/circular/A/Project.toml create mode 100644 test/extensions/circular/A/ext/CExt.jl create mode 100644 test/extensions/circular/A/ext/DExt.jl create mode 100644 test/extensions/circular/A/src/A.jl create mode 100644 test/extensions/circular/B/Project.toml create mode 100644 test/extensions/circular/B/src/B.jl create mode 100644 test/extensions/circular/C/Project.toml create mode 100644 test/extensions/circular/C/src/C.jl create mode 100644 test/extensions/circular/D/Project.toml create mode 100644 test/extensions/circular/D/src/D.jl create mode 100644 test/extensions/circular/Manifest.toml create mode 100644 test/extensions/circular/Project.toml diff --git a/test/extensions/circular/A/Project.toml b/test/extensions/circular/A/Project.toml new file mode 100644 index 0000000000000..9b55fcbf05001 --- /dev/null +++ b/test/extensions/circular/A/Project.toml @@ -0,0 +1,14 @@ +name = "A" +uuid = "c8938445-7efa-411c-ba8f-721576f9f47a" +version = "0.1.0" + +[deps] +B = "ef00b25e-dd85-47e0-9cd9-ed3c1ff51032" + +[weakdeps] +C = "d95b043b-fbe6-48a2-93d2-75fba1b51518" +D = "64e66ba5-e914-4adb-a5f6-036ef0c801f3" + +[extensions] +CExt = "C" +DExt = "D" diff --git a/test/extensions/circular/A/ext/CExt.jl b/test/extensions/circular/A/ext/CExt.jl new file mode 100644 index 0000000000000..33b4a5fc7cd3c --- /dev/null +++ b/test/extensions/circular/A/ext/CExt.jl @@ -0,0 +1,3 @@ +module CExt + +end # module diff --git a/test/extensions/circular/A/ext/DExt.jl b/test/extensions/circular/A/ext/DExt.jl new file mode 100644 index 0000000000000..915dfc89196f2 --- /dev/null +++ b/test/extensions/circular/A/ext/DExt.jl @@ -0,0 +1,3 @@ +module DExt + +end # module diff --git a/test/extensions/circular/A/src/A.jl b/test/extensions/circular/A/src/A.jl new file mode 100644 index 0000000000000..b555e27e24287 --- /dev/null +++ b/test/extensions/circular/A/src/A.jl @@ -0,0 +1,3 @@ +module A + +end # module diff --git a/test/extensions/circular/B/Project.toml b/test/extensions/circular/B/Project.toml new file mode 100644 index 0000000000000..21205c7c345a5 --- /dev/null +++ b/test/extensions/circular/B/Project.toml @@ -0,0 +1,7 @@ +name = "B" +uuid = "ef00b25e-dd85-47e0-9cd9-ed3c1ff51032" +version = "0.1.0" + +[deps] +C = "d95b043b-fbe6-48a2-93d2-75fba1b51518" +D = "64e66ba5-e914-4adb-a5f6-036ef0c801f3" diff --git a/test/extensions/circular/B/src/B.jl b/test/extensions/circular/B/src/B.jl new file mode 100644 index 0000000000000..d5bdf6392c9f4 --- /dev/null +++ b/test/extensions/circular/B/src/B.jl @@ -0,0 +1,3 @@ +module B + +end # module diff --git a/test/extensions/circular/C/Project.toml b/test/extensions/circular/C/Project.toml new file mode 100644 index 0000000000000..a913862e5a36f --- /dev/null +++ b/test/extensions/circular/C/Project.toml @@ -0,0 +1,3 @@ +name = "C" +uuid = "d95b043b-fbe6-48a2-93d2-75fba1b51518" +version = "0.1.0" diff --git a/test/extensions/circular/C/src/C.jl b/test/extensions/circular/C/src/C.jl new file mode 100644 index 0000000000000..489fa1e07ea91 --- /dev/null +++ b/test/extensions/circular/C/src/C.jl @@ -0,0 +1,3 @@ +module C + +end # module diff --git a/test/extensions/circular/D/Project.toml b/test/extensions/circular/D/Project.toml new file mode 100644 index 0000000000000..0e7bda4162265 --- /dev/null +++ b/test/extensions/circular/D/Project.toml @@ -0,0 +1,3 @@ +name = "D" +uuid = "64e66ba5-e914-4adb-a5f6-036ef0c801f3" +version = "0.1.0" diff --git a/test/extensions/circular/D/src/D.jl b/test/extensions/circular/D/src/D.jl new file mode 100644 index 0000000000000..e87de9cb2024a --- /dev/null +++ b/test/extensions/circular/D/src/D.jl @@ -0,0 +1,3 @@ +module D + +end # module diff --git a/test/extensions/circular/Manifest.toml b/test/extensions/circular/Manifest.toml new file mode 100644 index 0000000000000..cd5f52f1de4ec --- /dev/null +++ b/test/extensions/circular/Manifest.toml @@ -0,0 +1,32 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.11.0-DEV" +manifest_format = "2.0" +project_hash = "6c189c4d9e1e9194c4a4d7627740c379ecff4942" + +[[deps.A]] +deps = ["B"] +path = "./A" +uuid = "c8938445-7efa-411c-ba8f-721576f9f47a" +version = "0.1.0" +weakdeps = ["C", "D"] + + [deps.A.extensions] + CExt = "C" + DExt = "D" + +[[deps.B]] +deps = ["C", "D"] +path = "./B" +uuid = "ef00b25e-dd85-47e0-9cd9-ed3c1ff51032" +version = "0.1.0" + +[[deps.C]] +path = "./C" +uuid = "d95b043b-fbe6-48a2-93d2-75fba1b51518" +version = "0.1.0" + +[[deps.D]] +path = "./D" +uuid = "64e66ba5-e914-4adb-a5f6-036ef0c801f3" +version = "0.1.0" diff --git a/test/extensions/circular/Project.toml b/test/extensions/circular/Project.toml new file mode 100644 index 0000000000000..beed7a9072ad4 --- /dev/null +++ b/test/extensions/circular/Project.toml @@ -0,0 +1,5 @@ +[deps] +A = "c8938445-7efa-411c-ba8f-721576f9f47a" +B = "ef00b25e-dd85-47e0-9cd9-ed3c1ff51032" +C = "d95b043b-fbe6-48a2-93d2-75fba1b51518" +D = "64e66ba5-e914-4adb-a5f6-036ef0c801f3" diff --git a/test/loading.jl b/test/loading.jl index 53e05a4a76bbc..ca39a415ade08 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -1143,6 +1143,13 @@ end finally copy!(LOAD_PATH, old_load_path) end + + # issue 53081 + @testset "avoid circular precompilation deadlock through extensions" begin + testenv = joinpath(@__DIR__, "extensions", "circular") + s = read(`$(Base.julia_cmd()) --startup-file=no --project=$testenv -e 'using A'`, String) + @test !occursin("Error during loading of extension", s) + end finally try rm(depot_path, force=true, recursive=true)