11# This file is a part of Julia. License is MIT: https://julialang.org/license
22
33# Base.require is the implementation for the `import` statement
4+ const require_lock = ReentrantLock ()
45
56# Cross-platform case-sensitive path canonicalization
67
129130const ns_dummy_uuid = UUID (" fe0723d6-3a44-4c41-8065-ee0f42c8ceab" )
130131
131132function dummy_uuid (project_file:: String )
133+ @lock require_lock begin
132134 cache = LOADING_CACHE[]
133135 if cache != = nothing
134136 uuid = get (cache. dummy_uuid, project_file, nothing )
@@ -144,6 +146,7 @@ function dummy_uuid(project_file::String)
144146 cache. dummy_uuid[project_file] = uuid
145147 end
146148 return uuid
149+ end
147150end
148151
149152# # package path slugs: turning UUID + SHA1 into a pair of 4-byte "slugs" ##
@@ -236,8 +239,7 @@ struct TOMLCache
236239end
237240const TOML_CACHE = TOMLCache (TOML. Parser (), Dict {String, Dict{String, Any}} ())
238241
239- const TOML_LOCK = ReentrantLock ()
240- parsed_toml (project_file:: AbstractString ) = parsed_toml (project_file, TOML_CACHE, TOML_LOCK)
242+ parsed_toml (project_file:: AbstractString ) = parsed_toml (project_file, TOML_CACHE, require_lock)
241243function parsed_toml (project_file:: AbstractString , toml_cache:: TOMLCache , toml_lock:: ReentrantLock )
242244 lock (toml_lock) do
243245 cache = LOADING_CACHE[]
@@ -337,13 +339,15 @@ Use [`dirname`](@ref) to get the directory part and [`basename`](@ref)
337339to get the file name part of the path.
338340"""
339341function pathof (m:: Module )
340- pkgid = get (Base. module_keys, m, nothing )
342+ @lock require_lock begin
343+ pkgid = get (module_keys, m, nothing )
341344 pkgid === nothing && return nothing
342- origin = get (Base . pkgorigins, pkgid, nothing )
345+ origin = get (pkgorigins, pkgid, nothing )
343346 origin === nothing && return nothing
344347 path = origin. path
345348 path === nothing && return nothing
346349 return fixup_stdlib_path (path)
350+ end
347351end
348352
349353"""
@@ -366,7 +370,7 @@ julia> pkgdir(Foo, "src", "file.jl")
366370 The optional argument `paths` requires at least Julia 1.7.
367371"""
368372function pkgdir (m:: Module , paths:: String... )
369- rootmodule = Base . moduleroot (m)
373+ rootmodule = moduleroot (m)
370374 path = pathof (rootmodule)
371375 path === nothing && return nothing
372376 return joinpath (dirname (dirname (path)), paths... )
@@ -383,6 +387,7 @@ const preferences_names = ("JuliaLocalPreferences.toml", "LocalPreferences.toml"
383387# - `true`: `env` is an implicit environment
384388# - `path`: the path of an explicit project file
385389function env_project_file (env:: String ):: Union{Bool,String}
390+ @lock require_lock begin
386391 cache = LOADING_CACHE[]
387392 if cache != = nothing
388393 project_file = get (cache. env_project_file, env, nothing )
@@ -406,6 +411,7 @@ function env_project_file(env::String)::Union{Bool,String}
406411 cache. env_project_file[env] = project_file
407412 end
408413 return project_file
414+ end
409415end
410416
411417function project_deps_get (env:: String , name:: String ):: Union{Nothing,PkgId}
473479
474480# find project file's corresponding manifest file
475481function project_file_manifest_path (project_file:: String ):: Union{Nothing,String}
482+ @lock require_lock begin
476483 cache = LOADING_CACHE[]
477484 if cache != = nothing
478485 manifest_path = get (cache. project_file_manifest_path, project_file, missing )
@@ -501,6 +508,7 @@ function project_file_manifest_path(project_file::String)::Union{Nothing,String}
501508 cache. project_file_manifest_path[project_file] = manifest_path
502509 end
503510 return manifest_path
511+ end
504512end
505513
506514# given a directory (implicit env from LOAD_PATH) and a name,
@@ -688,7 +696,7 @@ function implicit_manifest_deps_get(dir::String, where::PkgId, name::String)::Un
688696 @assert where . uuid != = nothing
689697 project_file = entry_point_and_project_file (dir, where . name)[2 ]
690698 project_file === nothing && return nothing # a project file is mandatory for a package with a uuid
691- proj = project_file_name_uuid (project_file, where . name, )
699+ proj = project_file_name_uuid (project_file, where . name)
692700 proj == where || return nothing # verify that this is the correct project file
693701 # this is the correct project, so stop searching here
694702 pkg_uuid = explicit_project_deps_get (project_file, name)
@@ -753,19 +761,26 @@ function _include_from_serialized(path::String, depmods::Vector{Any})
753761 if isa (sv, Exception)
754762 return sv
755763 end
756- restored = sv[1 ]
757- if ! isa (restored, Exception)
758- for M in restored:: Vector{Any}
759- M = M:: Module
760- if isdefined (M, Base. Docs. META)
761- push! (Base. Docs. modules, M)
762- end
763- if parentmodule (M) === M
764- register_root_module (M)
765- end
764+ sv = sv:: SimpleVector
765+ restored = sv[1 ]:: Vector{Any}
766+ for M in restored
767+ M = M:: Module
768+ if isdefined (M, Base. Docs. META)
769+ push! (Base. Docs. modules, M)
770+ end
771+ if parentmodule (M) === M
772+ register_root_module (M)
773+ end
774+ end
775+ inits = sv[2 ]:: Vector{Any}
776+ if ! isempty (inits)
777+ unlock (require_lock) # temporarily _unlock_ during these callbacks
778+ try
779+ ccall (:jl_init_restored_modules , Cvoid, (Any,), inits)
780+ finally
781+ lock (require_lock)
766782 end
767783 end
768- isassigned (sv, 2 ) && ccall (:jl_init_restored_modules , Cvoid, (Any,), sv[2 ])
769784 return restored
770785end
771786
@@ -873,7 +888,7 @@ function _require_search_from_serialized(pkg::PkgId, sourcepath::String, depth::
873888end
874889
875890# to synchronize multiple tasks trying to import/using something
876- const package_locks = Dict {PkgId,Condition} ()
891+ const package_locks = Dict {PkgId,Threads. Condition} ()
877892
878893# to notify downstream consumers that a module was successfully loaded
879894# Callbacks take the form (mod::Base.PkgId) -> nothing.
@@ -896,7 +911,9 @@ function _include_dependency(mod::Module, _path::AbstractString)
896911 path = normpath (joinpath (dirname (prev), _path))
897912 end
898913 if _track_dependencies[]
914+ @lock require_lock begin
899915 push! (_require_dependencies, (mod, path, mtime (path)))
916+ end
900917 end
901918 return path, prev
902919end
@@ -968,6 +985,7 @@ For more details regarding code loading, see the manual sections on [modules](@r
968985[parallel computing](@ref code-availability).
969986"""
970987function require (into:: Module , mod:: Symbol )
988+ @lock require_lock begin
971989 LOADING_CACHE[] = LoadingCache ()
972990 try
973991 uuidkey = identify_package (into, String (mod))
@@ -1019,6 +1037,7 @@ function require(into::Module, mod::Symbol)
10191037 finally
10201038 LOADING_CACHE[] = nothing
10211039 end
1040+ end
10221041end
10231042
10241043mutable struct PkgOrigin
@@ -1030,6 +1049,7 @@ PkgOrigin() = PkgOrigin(nothing, nothing)
10301049const pkgorigins = Dict {PkgId,PkgOrigin} ()
10311050
10321051function require (uuidkey:: PkgId )
1052+ @lock require_lock begin
10331053 if ! root_module_exists (uuidkey)
10341054 cachefile = _require (uuidkey)
10351055 if cachefile != = nothing
@@ -1041,15 +1061,19 @@ function require(uuidkey::PkgId)
10411061 end
10421062 end
10431063 return root_module (uuidkey)
1064+ end
10441065end
10451066
10461067const loaded_modules = Dict {PkgId,Module} ()
10471068const module_keys = IdDict {Module,PkgId} () # the reverse
10481069
1049- is_root_module (m:: Module ) = haskey (module_keys, m)
1050- root_module_key (m:: Module ) = module_keys[m]
1070+ is_root_module (m:: Module ) = @lock require_lock haskey (module_keys, m)
1071+ root_module_key (m:: Module ) = @lock require_lock module_keys[m]
10511072
10521073function register_root_module (m:: Module )
1074+ # n.b. This is called from C after creating a new module in `Base.__toplevel__`,
1075+ # instead of adding them to the binding table there.
1076+ @lock require_lock begin
10531077 key = PkgId (m, String (nameof (m)))
10541078 if haskey (loaded_modules, key)
10551079 oldm = loaded_modules[key]
@@ -1059,6 +1083,7 @@ function register_root_module(m::Module)
10591083 end
10601084 loaded_modules[key] = m
10611085 module_keys[m] = key
1086+ end
10621087 nothing
10631088end
10641089
@@ -1074,12 +1099,13 @@ using Base
10741099end
10751100
10761101# get a top-level Module from the given key
1077- root_module (key:: PkgId ) = loaded_modules[key]
1102+ root_module (key:: PkgId ) = @lock require_lock loaded_modules[key]
10781103root_module (where :: Module , name:: Symbol ) =
10791104 root_module (identify_package (where , String (name)))
1105+ maybe_root_module (key:: PkgId ) = @lock require_lock get (loaded_modules, key, nothing )
10801106
1081- root_module_exists (key:: PkgId ) = haskey (loaded_modules, key)
1082- loaded_modules_array () = collect (values (loaded_modules))
1107+ root_module_exists (key:: PkgId ) = @lock require_lock haskey (loaded_modules, key)
1108+ loaded_modules_array () = @lock require_lock collect (values (loaded_modules))
10831109
10841110function unreference_module (key:: PkgId )
10851111 if haskey (loaded_modules, key)
@@ -1098,7 +1124,7 @@ function _require(pkg::PkgId)
10981124 wait (loading)
10991125 return
11001126 end
1101- package_locks[pkg] = Condition ()
1127+ package_locks[pkg] = Threads . Condition (require_lock )
11021128
11031129 last = toplevel_load[]
11041130 try
@@ -1166,10 +1192,12 @@ function _require(pkg::PkgId)
11661192 if uuid != = old_uuid
11671193 ccall (:jl_set_module_uuid , Cvoid, (Any, NTuple{2 , UInt64}), __toplevel__, uuid)
11681194 end
1195+ unlock (require_lock)
11691196 try
11701197 include (__toplevel__, path)
11711198 return
11721199 finally
1200+ lock (require_lock)
11731201 if uuid != = old_uuid
11741202 ccall (:jl_set_module_uuid , Cvoid, (Any, NTuple{2 , UInt64}), __toplevel__, old_uuid)
11751203 end
0 commit comments