1
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2
2
3
3
# Base.require is the implementation for the `import` statement
4
+ const require_lock = ReentrantLock ()
4
5
5
6
# Cross-platform case-sensitive path canonicalization
6
7
129
130
const ns_dummy_uuid = UUID (" fe0723d6-3a44-4c41-8065-ee0f42c8ceab" )
130
131
131
132
function dummy_uuid (project_file:: String )
133
+ @lock require_lock begin
132
134
cache = LOADING_CACHE[]
133
135
if cache != = nothing
134
136
uuid = get (cache. dummy_uuid, project_file, nothing )
@@ -144,6 +146,7 @@ function dummy_uuid(project_file::String)
144
146
cache. dummy_uuid[project_file] = uuid
145
147
end
146
148
return uuid
149
+ end
147
150
end
148
151
149
152
# # package path slugs: turning UUID + SHA1 into a pair of 4-byte "slugs" ##
@@ -236,8 +239,7 @@ struct TOMLCache
236
239
end
237
240
const TOML_CACHE = TOMLCache (TOML. Parser (), Dict {String, Dict{String, Any}} ())
238
241
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)
241
243
function parsed_toml (project_file:: AbstractString , toml_cache:: TOMLCache , toml_lock:: ReentrantLock )
242
244
lock (toml_lock) do
243
245
cache = LOADING_CACHE[]
@@ -337,13 +339,15 @@ Use [`dirname`](@ref) to get the directory part and [`basename`](@ref)
337
339
to get the file name part of the path.
338
340
"""
339
341
function pathof (m:: Module )
340
- pkgid = get (Base. module_keys, m, nothing )
342
+ @lock require_lock begin
343
+ pkgid = get (module_keys, m, nothing )
341
344
pkgid === nothing && return nothing
342
- origin = get (Base . pkgorigins, pkgid, nothing )
345
+ origin = get (pkgorigins, pkgid, nothing )
343
346
origin === nothing && return nothing
344
347
path = origin. path
345
348
path === nothing && return nothing
346
349
return fixup_stdlib_path (path)
350
+ end
347
351
end
348
352
349
353
"""
@@ -366,7 +370,7 @@ julia> pkgdir(Foo, "src", "file.jl")
366
370
The optional argument `paths` requires at least Julia 1.7.
367
371
"""
368
372
function pkgdir (m:: Module , paths:: String... )
369
- rootmodule = Base . moduleroot (m)
373
+ rootmodule = moduleroot (m)
370
374
path = pathof (rootmodule)
371
375
path === nothing && return nothing
372
376
return joinpath (dirname (dirname (path)), paths... )
@@ -383,6 +387,7 @@ const preferences_names = ("JuliaLocalPreferences.toml", "LocalPreferences.toml"
383
387
# - `true`: `env` is an implicit environment
384
388
# - `path`: the path of an explicit project file
385
389
function env_project_file (env:: String ):: Union{Bool,String}
390
+ @lock require_lock begin
386
391
cache = LOADING_CACHE[]
387
392
if cache != = nothing
388
393
project_file = get (cache. env_project_file, env, nothing )
@@ -406,6 +411,7 @@ function env_project_file(env::String)::Union{Bool,String}
406
411
cache. env_project_file[env] = project_file
407
412
end
408
413
return project_file
414
+ end
409
415
end
410
416
411
417
function project_deps_get (env:: String , name:: String ):: Union{Nothing,PkgId}
473
479
474
480
# find project file's corresponding manifest file
475
481
function project_file_manifest_path (project_file:: String ):: Union{Nothing,String}
482
+ @lock require_lock begin
476
483
cache = LOADING_CACHE[]
477
484
if cache != = nothing
478
485
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}
501
508
cache. project_file_manifest_path[project_file] = manifest_path
502
509
end
503
510
return manifest_path
511
+ end
504
512
end
505
513
506
514
# 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
688
696
@assert where . uuid != = nothing
689
697
project_file = entry_point_and_project_file (dir, where . name)[2 ]
690
698
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)
692
700
proj == where || return nothing # verify that this is the correct project file
693
701
# this is the correct project, so stop searching here
694
702
pkg_uuid = explicit_project_deps_get (project_file, name)
@@ -753,19 +761,26 @@ function _include_from_serialized(path::String, depmods::Vector{Any})
753
761
if isa (sv, Exception)
754
762
return sv
755
763
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)
766
782
end
767
783
end
768
- isassigned (sv, 2 ) && ccall (:jl_init_restored_modules , Cvoid, (Any,), sv[2 ])
769
784
return restored
770
785
end
771
786
@@ -873,7 +888,7 @@ function _require_search_from_serialized(pkg::PkgId, sourcepath::String, depth::
873
888
end
874
889
875
890
# to synchronize multiple tasks trying to import/using something
876
- const package_locks = Dict {PkgId,Condition} ()
891
+ const package_locks = Dict {PkgId,Threads. Condition} ()
877
892
878
893
# to notify downstream consumers that a module was successfully loaded
879
894
# Callbacks take the form (mod::Base.PkgId) -> nothing.
@@ -896,7 +911,9 @@ function _include_dependency(mod::Module, _path::AbstractString)
896
911
path = normpath (joinpath (dirname (prev), _path))
897
912
end
898
913
if _track_dependencies[]
914
+ @lock require_lock begin
899
915
push! (_require_dependencies, (mod, path, mtime (path)))
916
+ end
900
917
end
901
918
return path, prev
902
919
end
@@ -968,6 +985,7 @@ For more details regarding code loading, see the manual sections on [modules](@r
968
985
[parallel computing](@ref code-availability).
969
986
"""
970
987
function require (into:: Module , mod:: Symbol )
988
+ @lock require_lock begin
971
989
LOADING_CACHE[] = LoadingCache ()
972
990
try
973
991
uuidkey = identify_package (into, String (mod))
@@ -1019,6 +1037,7 @@ function require(into::Module, mod::Symbol)
1019
1037
finally
1020
1038
LOADING_CACHE[] = nothing
1021
1039
end
1040
+ end
1022
1041
end
1023
1042
1024
1043
mutable struct PkgOrigin
@@ -1030,6 +1049,7 @@ PkgOrigin() = PkgOrigin(nothing, nothing)
1030
1049
const pkgorigins = Dict {PkgId,PkgOrigin} ()
1031
1050
1032
1051
function require (uuidkey:: PkgId )
1052
+ @lock require_lock begin
1033
1053
if ! root_module_exists (uuidkey)
1034
1054
cachefile = _require (uuidkey)
1035
1055
if cachefile != = nothing
@@ -1041,15 +1061,19 @@ function require(uuidkey::PkgId)
1041
1061
end
1042
1062
end
1043
1063
return root_module (uuidkey)
1064
+ end
1044
1065
end
1045
1066
1046
1067
const loaded_modules = Dict {PkgId,Module} ()
1047
1068
const module_keys = IdDict {Module,PkgId} () # the reverse
1048
1069
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]
1051
1072
1052
1073
function 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
1053
1077
key = PkgId (m, String (nameof (m)))
1054
1078
if haskey (loaded_modules, key)
1055
1079
oldm = loaded_modules[key]
@@ -1059,6 +1083,7 @@ function register_root_module(m::Module)
1059
1083
end
1060
1084
loaded_modules[key] = m
1061
1085
module_keys[m] = key
1086
+ end
1062
1087
nothing
1063
1088
end
1064
1089
@@ -1074,12 +1099,13 @@ using Base
1074
1099
end
1075
1100
1076
1101
# 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]
1078
1103
root_module (where :: Module , name:: Symbol ) =
1079
1104
root_module (identify_package (where , String (name)))
1105
+ maybe_root_module (key:: PkgId ) = @lock require_lock get (loaded_modules, key, nothing )
1080
1106
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))
1083
1109
1084
1110
function unreference_module (key:: PkgId )
1085
1111
if haskey (loaded_modules, key)
@@ -1098,7 +1124,7 @@ function _require(pkg::PkgId)
1098
1124
wait (loading)
1099
1125
return
1100
1126
end
1101
- package_locks[pkg] = Condition ()
1127
+ package_locks[pkg] = Threads . Condition (require_lock )
1102
1128
1103
1129
last = toplevel_load[]
1104
1130
try
@@ -1166,10 +1192,12 @@ function _require(pkg::PkgId)
1166
1192
if uuid != = old_uuid
1167
1193
ccall (:jl_set_module_uuid , Cvoid, (Any, NTuple{2 , UInt64}), __toplevel__, uuid)
1168
1194
end
1195
+ unlock (require_lock)
1169
1196
try
1170
1197
include (__toplevel__, path)
1171
1198
return
1172
1199
finally
1200
+ lock (require_lock)
1173
1201
if uuid != = old_uuid
1174
1202
ccall (:jl_set_module_uuid , Cvoid, (Any, NTuple{2 , UInt64}), __toplevel__, old_uuid)
1175
1203
end
0 commit comments