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
@@ -862,7 +877,7 @@ function _require_search_from_serialized(pkg::PkgId, sourcepath::String)
862
877
end
863
878
864
879
# to synchronize multiple tasks trying to import/using something
865
- const package_locks = Dict {PkgId,Condition} ()
880
+ const package_locks = Dict {PkgId,Threads. Condition} ()
866
881
867
882
# to notify downstream consumers that a module was successfully loaded
868
883
# Callbacks take the form (mod::Base.PkgId) -> nothing.
@@ -885,7 +900,9 @@ function _include_dependency(mod::Module, _path::AbstractString)
885
900
path = normpath (joinpath (dirname (prev), _path))
886
901
end
887
902
if _track_dependencies[]
903
+ @lock require_lock begin
888
904
push! (_require_dependencies, (mod, path, mtime (path)))
905
+ end
889
906
end
890
907
return path, prev
891
908
end
@@ -957,6 +974,7 @@ For more details regarding code loading, see the manual sections on [modules](@r
957
974
[parallel computing](@ref code-availability).
958
975
"""
959
976
function require (into:: Module , mod:: Symbol )
977
+ @lock require_lock begin
960
978
LOADING_CACHE[] = LoadingCache ()
961
979
try
962
980
uuidkey = identify_package (into, String (mod))
@@ -998,6 +1016,7 @@ function require(into::Module, mod::Symbol)
998
1016
finally
999
1017
LOADING_CACHE[] = nothing
1000
1018
end
1019
+ end
1001
1020
end
1002
1021
1003
1022
mutable struct PkgOrigin
@@ -1009,6 +1028,7 @@ PkgOrigin() = PkgOrigin(nothing, nothing)
1009
1028
const pkgorigins = Dict {PkgId,PkgOrigin} ()
1010
1029
1011
1030
function require (uuidkey:: PkgId )
1031
+ @lock require_lock begin
1012
1032
if ! root_module_exists (uuidkey)
1013
1033
cachefile = _require (uuidkey)
1014
1034
if cachefile != = nothing
@@ -1020,15 +1040,19 @@ function require(uuidkey::PkgId)
1020
1040
end
1021
1041
end
1022
1042
return root_module (uuidkey)
1043
+ end
1023
1044
end
1024
1045
1025
1046
const loaded_modules = Dict {PkgId,Module} ()
1026
1047
const module_keys = IdDict {Module,PkgId} () # the reverse
1027
1048
1028
- is_root_module (m:: Module ) = haskey (module_keys, m)
1029
- root_module_key (m:: Module ) = module_keys[m]
1049
+ is_root_module (m:: Module ) = @lock require_lock haskey (module_keys, m)
1050
+ root_module_key (m:: Module ) = @lock require_lock module_keys[m]
1030
1051
1031
1052
function register_root_module (m:: Module )
1053
+ # n.b. This is called from C after creating a new module in `Base.__toplevel__`,
1054
+ # instead of adding them to the binding table there.
1055
+ @lock require_lock begin
1032
1056
key = PkgId (m, String (nameof (m)))
1033
1057
if haskey (loaded_modules, key)
1034
1058
oldm = loaded_modules[key]
@@ -1038,6 +1062,7 @@ function register_root_module(m::Module)
1038
1062
end
1039
1063
loaded_modules[key] = m
1040
1064
module_keys[m] = key
1065
+ end
1041
1066
nothing
1042
1067
end
1043
1068
@@ -1053,12 +1078,13 @@ using Base
1053
1078
end
1054
1079
1055
1080
# get a top-level Module from the given key
1056
- root_module (key:: PkgId ) = loaded_modules[key]
1081
+ root_module (key:: PkgId ) = @lock require_lock loaded_modules[key]
1057
1082
root_module (where :: Module , name:: Symbol ) =
1058
1083
root_module (identify_package (where , String (name)))
1084
+ maybe_root_module (key:: PkgId ) = @lock require_lock get (loaded_modules, key, nothing )
1059
1085
1060
- root_module_exists (key:: PkgId ) = haskey (loaded_modules, key)
1061
- loaded_modules_array () = collect (values (loaded_modules))
1086
+ root_module_exists (key:: PkgId ) = @lock require_lock haskey (loaded_modules, key)
1087
+ loaded_modules_array () = @lock require_lock collect (values (loaded_modules))
1062
1088
1063
1089
function unreference_module (key:: PkgId )
1064
1090
if haskey (loaded_modules, key)
@@ -1077,7 +1103,7 @@ function _require(pkg::PkgId)
1077
1103
wait (loading)
1078
1104
return
1079
1105
end
1080
- package_locks[pkg] = Condition ()
1106
+ package_locks[pkg] = Threads . Condition (require_lock )
1081
1107
1082
1108
last = toplevel_load[]
1083
1109
try
@@ -1145,10 +1171,12 @@ function _require(pkg::PkgId)
1145
1171
if uuid != = old_uuid
1146
1172
ccall (:jl_set_module_uuid , Cvoid, (Any, NTuple{2 , UInt64}), __toplevel__, uuid)
1147
1173
end
1174
+ unlock (require_lock)
1148
1175
try
1149
1176
include (__toplevel__, path)
1150
1177
return
1151
1178
finally
1179
+ lock (require_lock)
1152
1180
if uuid != = old_uuid
1153
1181
ccall (:jl_set_module_uuid , Cvoid, (Any, NTuple{2 , UInt64}), __toplevel__, old_uuid)
1154
1182
end
0 commit comments