Skip to content

Commit ad8893b

Browse files
committed
loading: add missing deadlock causing #45704
Does not explicitly close issue #45704, as perhaps the deserialized module should still be valid after the replacement warning.
1 parent d81724a commit ad8893b

File tree

1 file changed

+64
-39
lines changed

1 file changed

+64
-39
lines changed

base/loading.jl

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ function dummy_uuid(project_file::String)
167167
end
168168
project_path = try
169169
realpath(project_file)
170-
catch
170+
catch ex
171+
ex isa IOError || rethrow()
171172
project_file
172173
end
173174
uuid = uuid5(ns_dummy_uuid, project_path)
@@ -367,15 +368,15 @@ function locate_package(pkg::PkgId)::Union{Nothing,String}
367368
for env in load_path()
368369
# look for the toplevel pkg `pkg.name` in this entry
369370
found = project_deps_get(env, pkg.name)
370-
found === nothing && continue
371-
if pkg == found
372-
# pkg.name is present in this directory or project file,
373-
# return the path the entry point for the code, if it could be found
374-
# otherwise, signal failure
375-
return implicit_manifest_uuid_path(env, pkg)
371+
if found !== nothing
372+
@assert found.name == pkg.name
373+
if found.uuid === nothing
374+
# pkg.name is present in this directory or project file,
375+
# return the path the entry point for the code, if it could be found
376+
# otherwise, signal failure
377+
return implicit_manifest_uuid_path(env, pkg)
378+
end
376379
end
377-
@assert found.uuid !== nothing
378-
return locate_package(found) # restart search now that we know the uuid for pkg
379380
end
380381
else
381382
for env in load_path()
@@ -848,6 +849,7 @@ end
848849
# or an Exception that describes why it couldn't be loaded
849850
# and it reconnects the Base.Docs.META
850851
function _include_from_serialized(pkg::PkgId, path::String, depmods::Vector{Any})
852+
assert_havelock(require_lock)
851853
sv = ccall(:jl_restore_incremental, Any, (Cstring, Any), path, depmods)
852854
if isa(sv, Exception)
853855
return sv
@@ -881,6 +883,7 @@ function _include_from_serialized(pkg::PkgId, path::String, depmods::Vector{Any}
881883
end
882884

883885
function run_package_callbacks(modkey::PkgId)
886+
assert_havelock(require_lock)
884887
unlock(require_lock)
885888
try
886889
for callback in package_callbacks
@@ -897,34 +900,51 @@ function run_package_callbacks(modkey::PkgId)
897900
end
898901

899902
function _tryrequire_from_serialized(modkey::PkgId, build_id::UInt64, modpath::Union{Nothing, String}, depth::Int = 0)
903+
assert_havelock(require_lock)
904+
local loaded = nothing
900905
if root_module_exists(modkey)
901906
M = root_module(modkey)
902907
if PkgId(M) == modkey && module_build_id(M) === build_id
903-
return M
908+
loaded = M
904909
end
905910
else
906-
if modpath === nothing
907-
modpath = locate_package(modkey)
908-
modpath === nothing && return nothing
911+
loading = get(package_locks, modkey, false)
912+
if loading !== false
913+
# load already in progress for this module
914+
return wait(loading)
909915
end
910-
mod = _require_search_from_serialized(modkey, String(modpath), depth)
911-
get!(PkgOrigin, pkgorigins, modkey).path = modpath
912-
if !isa(mod, Bool)
913-
run_package_callbacks(modkey)
914-
for M in mod::Vector{Any}
915-
M = M::Module
916-
if PkgId(M) == modkey && module_build_id(M) === build_id
917-
return M
916+
package_locks[modkey] = Threads.Condition(require_lock)
917+
try
918+
if modpath === nothing
919+
modpath = locate_package(modkey)
920+
modpath === nothing && return nothing
921+
end
922+
mod = _require_search_from_serialized(modkey, String(modpath), depth)
923+
get!(PkgOrigin, pkgorigins, modkey).path = modpath
924+
if !isa(mod, Bool)
925+
for M in mod::Vector{Any}
926+
M = M::Module
927+
if PkgId(M) == modkey && module_build_id(M) === build_id
928+
loaded = M
929+
break
930+
end
918931
end
919932
end
933+
finally
934+
loading = pop!(package_locks, modkey)
935+
notify(loading, loaded, all=true)
936+
end
937+
if loaded !== nothing
938+
run_package_callbacks(modkey)
920939
end
921940
end
922-
return nothing
941+
return loaded
923942
end
924943

925944
function _require_from_serialized(pkg::PkgId, path::String)
926945
# loads a precompile cache file, ignoring stale_cachfile tests
927946
# load all of the dependent modules first
947+
assert_havelock(require_lock)
928948
local depmodnames
929949
io = open(path, "r")
930950
try
@@ -953,6 +973,7 @@ const TIMING_IMPORTS = Threads.Atomic{Int}(0)
953973
# returns `false` if the module isn't known to be precompilable
954974
# returns the set of modules restored if the cache load succeeded
955975
@constprop :none function _require_search_from_serialized(pkg::PkgId, sourcepath::String, depth::Int = 0)
976+
assert_havelock(require_lock)
956977
timing_imports = TIMING_IMPORTS[] > 0
957978
try
958979
if timing_imports
@@ -969,7 +990,8 @@ const TIMING_IMPORTS = Threads.Atomic{Int}(0)
969990
staledeps = staledeps::Vector{Any}
970991
try
971992
touch(path_to_try) # update timestamp of precompilation file
972-
catch # file might be read-only and then we fail to update timestamp, which is fine
993+
catch ex # file might be read-only and then we fail to update timestamp, which is fine
994+
ex isa IOError || rethrow()
973995
end
974996
# finish loading module graph into staledeps
975997
for i in 1:length(staledeps)
@@ -987,6 +1009,7 @@ const TIMING_IMPORTS = Threads.Atomic{Int}(0)
9871009
if staledeps === true
9881010
continue
9891011
end
1012+
#@debug "Loading cache file $path for $pkg at $sourcepath"
9901013
restored = _include_from_serialized(pkg, path_to_try, staledeps)
9911014
if isa(restored, Exception)
9921015
@debug "Deserialization checks failed while attempting to load cache from $path_to_try" exception=restored
@@ -1165,18 +1188,19 @@ const pkgorigins = Dict{PkgId,PkgOrigin}()
11651188
require(uuidkey::PkgId) = @lock require_lock _require_prelocked(uuidkey)
11661189

11671190
function _require_prelocked(uuidkey::PkgId)
1168-
just_loaded_pkg = false
1191+
assert_havelock(require_lock)
11691192
if !root_module_exists(uuidkey)
1170-
_require(uuidkey)
1193+
newm = _require(uuidkey)
1194+
if newm === nothing
1195+
error("package `$(uuidkey.name)` did not define the expected \
1196+
module `$(uuidkey.name)`, check for typos in package module name")
1197+
end
11711198
# After successfully loading, notify downstream consumers
11721199
run_package_callbacks(uuidkey)
1173-
just_loaded_pkg = true
1174-
end
1175-
if just_loaded_pkg && !root_module_exists(uuidkey)
1176-
error("package `$(uuidkey.name)` did not define the expected \
1177-
module `$(uuidkey.name)`, check for typos in package module name")
1200+
else
1201+
newm = root_module(uuidkey)
11781202
end
1179-
return root_module(uuidkey)
1203+
return newm
11801204
end
11811205

11821206
const loaded_modules = Dict{PkgId,Module}()
@@ -1249,18 +1273,19 @@ function set_pkgorigin_version_path(pkg, path)
12491273
pkgorigin.path = path
12501274
end
12511275

1252-
# Returns `nothing` or the name of the newly-created cachefile
1276+
# Returns `nothing` or the new(ish) module
12531277
function _require(pkg::PkgId)
1278+
assert_havelock(require_lock)
12541279
# handle recursive calls to require
12551280
loading = get(package_locks, pkg, false)
12561281
if loading !== false
12571282
# load already in progress for this module
1258-
wait(loading)
1259-
return
1283+
return wait(loading)
12601284
end
12611285
package_locks[pkg] = Threads.Condition(require_lock)
12621286

12631287
last = toplevel_load[]
1288+
loaded = nothing
12641289
try
12651290
toplevel_load[] = false
12661291
# perform the search operation to select the module file require intends to load
@@ -1277,7 +1302,7 @@ function _require(pkg::PkgId)
12771302
if JLOptions().use_compiled_modules != 0
12781303
m = _require_search_from_serialized(pkg, path)
12791304
if !isa(m, Bool)
1280-
return
1305+
return m
12811306
end
12821307
end
12831308

@@ -1312,7 +1337,7 @@ function _require(pkg::PkgId)
13121337
if isa(m, Exception)
13131338
@warn "The call to compilecache failed to create a usable precompiled cache file for $pkg" exception=m
13141339
else
1315-
return
1340+
return m
13161341
end
13171342
end
13181343
end
@@ -1329,7 +1354,7 @@ function _require(pkg::PkgId)
13291354
unlock(require_lock)
13301355
try
13311356
include(__toplevel__, path)
1332-
return
1357+
loaded = get(loaded_modules, key, nothing)
13331358
finally
13341359
lock(require_lock)
13351360
if uuid !== old_uuid
@@ -1339,9 +1364,9 @@ function _require(pkg::PkgId)
13391364
finally
13401365
toplevel_load[] = last
13411366
loading = pop!(package_locks, pkg)
1342-
notify(loading, all=true)
1367+
notify(loading, loaded, all=true)
13431368
end
1344-
nothing
1369+
return loaded
13451370
end
13461371

13471372
# relative-path load

0 commit comments

Comments
 (0)