@@ -1902,8 +1902,17 @@ function _require(pkg::PkgId, env=nothing)
1902
1902
@goto load_from_cache
1903
1903
end
1904
1904
# spawn off a new incremental pre-compile task for recursive `require` calls
1905
- cachefile = compilecache (pkg, path)
1906
- if isa (cachefile, Exception)
1905
+ cachefile_or_module = maybe_cachefile_lock (pkg, path) do
1906
+ # double-check now that we have lock
1907
+ m = _require_search_from_serialized (pkg, path, UInt128 (0 ))
1908
+ m isa Module && return m
1909
+ compilecache (pkg, path)
1910
+ end
1911
+ cachefile_or_module isa Module && return cachefile_or_module:: Module
1912
+ cachefile = cachefile_or_module
1913
+ if isnothing (cachefile) # maybe_cachefile_lock returns nothing if it had to wait for another process
1914
+ @goto load_from_cache # the new cachefile will have the newest mtime so will come first in the search
1915
+ elseif isa (cachefile, Exception)
1907
1916
if precompilableerror (cachefile)
1908
1917
verbosity = isinteractive () ? CoreLogging. Info : CoreLogging. Debug
1909
1918
@logmsg verbosity " Skipping precompilation since __precompile__(false). Importing $pkg ."
@@ -2805,6 +2814,35 @@ function show(io::IO, cf::CacheFlags)
2805
2814
print (io, " , opt_level = " , cf. opt_level)
2806
2815
end
2807
2816
2817
+ # Set by FileWatching.__init__()
2818
+ global mkpidlock_hook
2819
+ global trymkpidlock_hook
2820
+ global parse_pidfile_hook
2821
+
2822
+ # allows processes to wait if another process is precompiling a given source already
2823
+ function maybe_cachefile_lock (f, pkg:: PkgId , srcpath:: String )
2824
+ if @isdefined (mkpidlock_hook) && @isdefined (trymkpidlock_hook) && @isdefined (parse_pidfile_hook)
2825
+ pidfile = string (srcpath, " .pidlock" )
2826
+ cachefile = invokelatest (trymkpidlock_hook, f, pidfile)
2827
+ if cachefile === false
2828
+ pid, hostname, age = invokelatest (parse_pidfile_hook, pidfile)
2829
+ verbosity = isinteractive () ? CoreLogging. Info : CoreLogging. Debug
2830
+ if isempty (hostname) || hostname == gethostname ()
2831
+ @logmsg verbosity " Waiting for another process (pid: $pid ) to finish precompiling $pkg "
2832
+ else
2833
+ @logmsg verbosity " Waiting for another machine (hostname: $hostname , pid: $pid ) to finish precompiling $pkg "
2834
+ end
2835
+ # wait until the lock is available, but don't actually acquire it
2836
+ # returning nothing indicates a process waited for another
2837
+ return invokelatest (mkpidlock_hook, Returns (nothing ), pidfile)
2838
+ end
2839
+ return cachefile
2840
+ else
2841
+ # for packages loaded before FileWatching.__init__()
2842
+ f ()
2843
+ end
2844
+ end
2845
+
2808
2846
# returns true if it "cachefile.ji" is stale relative to "modpath.jl" and build_id for modkey
2809
2847
# otherwise returns the list of dependencies to also check
2810
2848
@constprop :none function stale_cachefile (modpath:: String , cachefile:: String ; ignore_loaded:: Bool = false )
0 commit comments