Skip to content

Commit 3d195c0

Browse files
authored
Merge pull request #49302 from JuliaLang/backports-release-1.9
Backports for 1.9.0-rc3
2 parents 72aec42 + ad9b54f commit 3d195c0

File tree

61 files changed

+902
-647
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+902
-647
lines changed

NEWS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ Standard library changes
139139
* The contextual module which is active in the REPL can be changed (it is `Main` by default),
140140
via the `REPL.activate(::Module)` function or via typing the module in the REPL and pressing
141141
the keybinding Alt-m ([#33872]).
142-
* An "IPython mode" which mimics the behaviour of the prompts and storing the evaluated result in `Out` can be
143-
activated with `REPL.ipython_mode!()`. See the manual for how to enable this at startup ([#46474]).
142+
* A "numbered prompt" mode which prints numbers for each input and output and stores evaluated results in `Out` can be
143+
activated with `REPL.numbered_prompt!()`. See the manual for how to enable this at startup ([#46474]).
144144
* Tab completion displays available keyword arguments ([#43536]).
145145

146146
#### SuiteSparse

base/array.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ end
267267
"""
268268
unsafe_copyto!(dest::Array, do, src::Array, so, N)
269269
270-
Copy `N` elements from a source array to a destination, starting at offset `so` in the
270+
Copy `N` elements from a source array to a destination, starting at the linear index `so` in the
271271
source and `do` in the destination (1-indexed).
272272
273273
The `unsafe` prefix on this function indicates that no validation is performed to ensure
@@ -307,8 +307,8 @@ unsafe_copyto!(dest::Array, doffs, src::Array, soffs, n) =
307307
"""
308308
copyto!(dest, do, src, so, N)
309309
310-
Copy `N` elements from collection `src` starting at offset `so`, to array `dest` starting at
311-
offset `do`. Return `dest`.
310+
Copy `N` elements from collection `src` starting at the linear index `so`, to array `dest` starting at
311+
the index `do`. Return `dest`.
312312
"""
313313
function copyto!(dest::Array, doffs::Integer, src::Array, soffs::Integer, n::Integer)
314314
return _copyto_impl!(dest, doffs, src, soffs, n)

base/binaryplatforms.jl

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,12 +1066,20 @@ function select_platform(download_info::Dict, platform::AbstractPlatform = HostP
10661066
return nothing
10671067
end
10681068

1069-
# At this point, we may have multiple possibilities. E.g. if, in the future,
1070-
# Julia can be built without a direct dependency on libgfortran, we may match
1071-
# multiple tarballs that vary only within their libgfortran ABI. To narrow it
1072-
# down, we just sort by triplet, then pick the last one. This has the effect
1073-
# of generally choosing the latest release (e.g. a `libgfortran5` tarball
1074-
# rather than a `libgfortran3` tarball)
1069+
# At this point, we may have multiple possibilities. We now engage a multi-
1070+
# stage selection algorithm, where we first choose simpler matches over more
1071+
# complex matches. We define a simpler match as one that has fewer tags
1072+
# overall. As these candidate matches have already been filtered to match
1073+
# the given platform, the only other tags that exist are ones that are in
1074+
# addition to the tags declared by the platform. Hence, selecting the
1075+
# minimum in number of tags is equivalent to selecting the closest match.
1076+
min_tag_count = minimum(length(tags(p)) for p in ps)
1077+
filter!(p -> length(tags(p)) == min_tag_count, ps)
1078+
1079+
# Now we _still_ may continue to have multiple matches, so we now simply sort
1080+
# the candidate matches by their triplets and take the last one, so as to
1081+
# generally choose the latest release (e.g. a `libgfortran5` tarball over a
1082+
# `libgfortran3` tarball).
10751083
p = last(sort(ps, by = p -> triplet(p)))
10761084
return download_info[p]
10771085
end

base/file.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ if Sys.iswindows()
105105
end
106106
else
107107
function cd(f::Function, dir::AbstractString)
108-
fd = ccall(:open, Int32, (Cstring, Int32), :., 0)
108+
fd = ccall(:open, Int32, (Cstring, Int32, UInt32...), :., 0)
109109
systemerror(:open, fd == -1)
110110
try
111111
cd(dir)

base/loading.jl

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,7 @@ function register_restored_modules(sv::SimpleVector, pkg::PkgId, path::String)
10801080
end
10811081

10821082
function run_package_callbacks(modkey::PkgId)
1083+
run_extension_callbacks(modkey)
10831084
assert_havelock(require_lock)
10841085
unlock(require_lock)
10851086
try
@@ -1188,9 +1189,12 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, <:An
11881189
end
11891190
end
11901191

1192+
loading_extension::Bool = false
11911193
function run_extension_callbacks(extid::ExtensionId)
11921194
assert_havelock(require_lock)
11931195
succeeded = try
1196+
# Used by Distributed to now load extensions in the package callback
1197+
global loading_extension = true
11941198
_require_prelocked(extid.id)
11951199
@debug "Extension $(extid.id.name) of $(extid.parentid.name) loaded"
11961200
true
@@ -1200,59 +1204,57 @@ function run_extension_callbacks(extid::ExtensionId)
12001204
@error "Error during loading of extension $(extid.id.name) of $(extid.parentid.name), \
12011205
use `Base.retry_load_extensions()` to retry." exception=errs
12021206
false
1207+
finally
1208+
global loading_extension = false
12031209
end
12041210
return succeeded
12051211
end
12061212

1207-
function run_extension_callbacks()
1213+
function run_extension_callbacks(pkgid::PkgId)
12081214
assert_havelock(require_lock)
1209-
loaded_triggers = collect(intersect(keys(Base.loaded_modules), keys(Base.EXT_DORMITORY)))
1210-
sort!(loaded_triggers; by=x->x.uuid)
1211-
for pkgid in loaded_triggers
1212-
# take ownership of extids that depend on this pkgid
1213-
extids = pop!(EXT_DORMITORY, pkgid, nothing)
1214-
extids === nothing && continue
1215-
for extid in extids
1216-
if extid.ntriggers > 0
1217-
# It is possible that pkgid was loaded in an environment
1218-
# below the one of the parent. This will cause a load failure when the
1219-
# pkg ext tries to load the triggers. Therefore, check this first
1220-
# before loading the pkg ext.
1221-
pkgenv = Base.identify_package_env(extid.id, pkgid.name)
1222-
ext_not_allowed_load = false
1223-
if pkgenv === nothing
1215+
# take ownership of extids that depend on this pkgid
1216+
extids = pop!(EXT_DORMITORY, pkgid, nothing)
1217+
extids === nothing && return
1218+
for extid in extids
1219+
if extid.ntriggers > 0
1220+
# It is possible that pkgid was loaded in an environment
1221+
# below the one of the parent. This will cause a load failure when the
1222+
# pkg ext tries to load the triggers. Therefore, check this first
1223+
# before loading the pkg ext.
1224+
pkgenv = identify_package_env(extid.id, pkgid.name)
1225+
ext_not_allowed_load = false
1226+
if pkgenv === nothing
1227+
ext_not_allowed_load = true
1228+
else
1229+
pkg, env = pkgenv
1230+
path = locate_package(pkg, env)
1231+
if path === nothing
12241232
ext_not_allowed_load = true
1225-
else
1226-
pkg, env = pkgenv
1227-
path = Base.locate_package(pkg, env)
1228-
if path === nothing
1229-
ext_not_allowed_load = true
1230-
end
1231-
end
1232-
if ext_not_allowed_load
1233-
@debug "Extension $(extid.id.name) of $(extid.parentid.name) will not be loaded \
1234-
since $(pkgid.name) loaded in environment lower in load path"
1235-
# indicate extid is expected to fail
1236-
extid.ntriggers *= -1
1237-
else
1238-
# indicate pkgid is loaded
1239-
extid.ntriggers -= 1
12401233
end
12411234
end
1242-
if extid.ntriggers < 0
1243-
# indicate pkgid is loaded
1244-
extid.ntriggers += 1
1245-
succeeded = false
1235+
if ext_not_allowed_load
1236+
@debug "Extension $(extid.id.name) of $(extid.parentid.name) will not be loaded \
1237+
since $(pkgid.name) loaded in environment lower in load path"
1238+
# indicate extid is expected to fail
1239+
extid.ntriggers *= -1
12461240
else
1247-
succeeded = true
1248-
end
1249-
if extid.ntriggers == 0
1250-
# actually load extid, now that all dependencies are met,
1251-
# and record the result
1252-
succeeded = succeeded && run_extension_callbacks(extid)
1253-
succeeded || push!(EXT_DORMITORY_FAILED, extid)
1241+
# indicate pkgid is loaded
1242+
extid.ntriggers -= 1
12541243
end
12551244
end
1245+
if extid.ntriggers < 0
1246+
# indicate pkgid is loaded
1247+
extid.ntriggers += 1
1248+
succeeded = false
1249+
else
1250+
succeeded = true
1251+
end
1252+
if extid.ntriggers == 0
1253+
# actually load extid, now that all dependencies are met,
1254+
# and record the result
1255+
succeeded = succeeded && run_extension_callbacks(extid)
1256+
succeeded || push!(EXT_DORMITORY_FAILED, extid)
1257+
end
12561258
end
12571259
return
12581260
end
@@ -1276,7 +1278,7 @@ function retry_load_extensions()
12761278
end
12771279
prepend!(EXT_DORMITORY_FAILED, failed)
12781280
end
1279-
nothing
1281+
return
12801282
end
12811283

12821284
"""
@@ -1510,11 +1512,11 @@ end
15101512
"""
15111513
include_dependency(path::AbstractString)
15121514
1513-
In a module, declare that the file specified by `path` (relative or absolute) is a
1514-
dependency for precompilation; that is, the module will need to be recompiled if this file
1515-
changes.
1515+
In a module, declare that the file, directory, or symbolic link specified by `path`
1516+
(relative or absolute) is a dependency for precompilation; that is, the module will need
1517+
to be recompiled if the modification time of `path` changes.
15161518
1517-
This is only needed if your module depends on a file that is not used via [`include`](@ref). It has
1519+
This is only needed if your module depends on a path that is not used via [`include`](@ref). It has
15181520
no effect outside of compilation.
15191521
"""
15201522
function include_dependency(path::AbstractString)
@@ -1631,10 +1633,6 @@ function _require_prelocked(uuidkey::PkgId, env=nothing)
16311633
else
16321634
newm = root_module(uuidkey)
16331635
end
1634-
# Load extensions when not precompiling and not in a nested package load
1635-
if JLOptions().incremental == 0 && isempty(package_locks)
1636-
run_extension_callbacks()
1637-
end
16381636
return newm
16391637
end
16401638

@@ -2790,7 +2788,7 @@ end
27902788
end
27912789
for chi in includes
27922790
f, ftime_req = chi.filename, chi.mtime
2793-
if !isfile(f)
2791+
if !ispath(f)
27942792
_f = fixup_stdlib_path(f)
27952793
if isfile(_f) && startswith(_f, Sys.STDLIB)
27962794
# mtime is changed by extraction

base/strings/lazy.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ macro lazy_str(text)
6767
parts = Any[]
6868
lastidx = idx = 1
6969
while (idx = findnext('$', text, idx)) !== nothing
70-
lastidx < idx && push!(parts, text[lastidx:idx-1])
70+
lastidx < idx && push!(parts, text[lastidx:prevind(text, idx)])
7171
idx += 1
7272
expr, idx = Meta.parseatom(text, idx; filename=string(__source__.file))
7373
push!(parts, esc(expr))

base/task.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ istaskfailed(t::Task) = (load_state_acquire(t) === task_state_failed)
253253
Threads.threadid(t::Task) = Int(ccall(:jl_get_task_tid, Int16, (Any,), t)+1)
254254
function Threads.threadpool(t::Task)
255255
tpid = ccall(:jl_get_task_threadpoolid, Int8, (Any,), t)
256-
return tpid == 0 ? :default : :interactive
256+
return Threads._tpid_to_sym(tpid)
257257
end
258258

259259
task_result(t::Task) = t.result
@@ -786,7 +786,7 @@ function enq_work(t::Task)
786786
if Threads.threadpoolsize(tp) == 1
787787
# There's only one thread in the task's assigned thread pool;
788788
# use its work queue.
789-
tid = (tp === :default) ? 1 : Threads.threadpoolsize(:default)+1
789+
tid = (tp === :interactive) ? 1 : Threads.threadpoolsize(:interactive)+1
790790
ccall(:jl_set_task_tid, Cint, (Any, Cint), t, tid-1)
791791
push!(workqueue_for(tid), t)
792792
else

base/threadingconstructs.jl

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,22 @@ function _nthreads_in_pool(tpid::Int8)
3939
return Int(unsafe_load(p, tpid + 1))
4040
end
4141

42+
function _tpid_to_sym(tpid::Int8)
43+
return tpid == 0 ? :interactive : :default
44+
end
45+
46+
function _sym_to_tpid(tp::Symbol)
47+
return tp === :interactive ? Int8(0) : Int8(1)
48+
end
49+
4250
"""
4351
Threads.threadpool(tid = threadid()) -> Symbol
4452
4553
Returns the specified thread's threadpool; either `:default` or `:interactive`.
4654
"""
4755
function threadpool(tid = threadid())
4856
tpid = ccall(:jl_threadpoolid, Int8, (Int16,), tid-1)
49-
return tpid == 0 ? :default : :interactive
57+
return _tpid_to_sym(tpid)
5058
end
5159

5260
"""
@@ -67,24 +75,39 @@ See also: `BLAS.get_num_threads` and `BLAS.set_num_threads` in the
6775
[`Distributed`](@ref man-distributed) standard library.
6876
"""
6977
function threadpoolsize(pool::Symbol = :default)
70-
if pool === :default
71-
tpid = Int8(0)
72-
elseif pool === :interactive
73-
tpid = Int8(1)
78+
if pool === :default || pool === :interactive
79+
tpid = _sym_to_tpid(pool)
7480
else
7581
error("invalid threadpool specified")
7682
end
7783
return _nthreads_in_pool(tpid)
7884
end
7985

86+
"""
87+
threadpooltids(pool::Symbol)
88+
89+
Returns a vector of IDs of threads in the given pool.
90+
"""
91+
function threadpooltids(pool::Symbol)
92+
ni = _nthreads_in_pool(Int8(0))
93+
if pool === :interactive
94+
return collect(1:ni)
95+
elseif pool === :default
96+
return collect(ni+1:ni+_nthreads_in_pool(Int8(1)))
97+
else
98+
error("invalid threadpool specified")
99+
end
100+
end
101+
80102
function threading_run(fun, static)
81103
ccall(:jl_enter_threaded_region, Cvoid, ())
82104
n = threadpoolsize()
105+
tid_offset = threadpoolsize(:interactive)
83106
tasks = Vector{Task}(undef, n)
84107
for i = 1:n
85108
t = Task(() -> fun(i)) # pass in tid
86109
t.sticky = static
87-
static && ccall(:jl_set_task_tid, Cint, (Any, Cint), t, i-1)
110+
static && ccall(:jl_set_task_tid, Cint, (Any, Cint), t, tid_offset + i-1)
88111
tasks[i] = t
89112
schedule(t)
90113
end
@@ -287,6 +310,15 @@ macro threads(args...)
287310
return _threadsfor(ex.args[1], ex.args[2], sched)
288311
end
289312

313+
function _spawn_set_thrpool(t::Task, tp::Symbol)
314+
tpid = _sym_to_tpid(tp)
315+
if _nthreads_in_pool(tpid) == 0
316+
tpid = _sym_to_tpid(:default)
317+
end
318+
ccall(:jl_set_task_threadpoolid, Cint, (Any, Int8), t, tpid)
319+
nothing
320+
end
321+
290322
"""
291323
Threads.@spawn [:default|:interactive] expr
292324
@@ -315,7 +347,7 @@ the variable's value in the current task.
315347
A threadpool may be specified as of Julia 1.9.
316348
"""
317349
macro spawn(args...)
318-
tpid = Int8(0)
350+
tp = :default
319351
na = length(args)
320352
if na == 2
321353
ttype, ex = args
@@ -325,9 +357,9 @@ macro spawn(args...)
325357
# TODO: allow unquoted symbols
326358
ttype = nothing
327359
end
328-
if ttype === :interactive
329-
tpid = Int8(1)
330-
elseif ttype !== :default
360+
if ttype === :interactive || ttype === :default
361+
tp = ttype
362+
else
331363
throw(ArgumentError("unsupported threadpool in @spawn: $ttype"))
332364
end
333365
elseif na == 1
@@ -344,11 +376,7 @@ macro spawn(args...)
344376
let $(letargs...)
345377
local task = Task($thunk)
346378
task.sticky = false
347-
local tpid_actual = $tpid
348-
if _nthreads_in_pool(tpid_actual) == 0
349-
tpid_actual = Int8(0)
350-
end
351-
ccall(:jl_set_task_threadpoolid, Cint, (Any, Int8), task, tpid_actual)
379+
_spawn_set_thrpool(task, $(QuoteNode(tp)))
352380
if $(Expr(:islocal, var))
353381
put!($var, task)
354382
end

0 commit comments

Comments
 (0)