Skip to content

Commit bc55f44

Browse files
authored
[release-1.9] Backports for Julia 1.9 (#50977)
Backported PRs: - [x] #49357 <!-- Fix unclosed code fence in src/manual/methods.md --> - [x] #50842 <!-- Avoid race conditions with recursive rm --> - [x] #50858 <!-- Add a `threadpool` parameter to `Channel` constructor --> - [x] #50730 <!-- Fix integer overflow in `isapprox` --> - [x] #50823 <!-- Make ranges more robust with unsigned indexes. --> - [x] #50915 <!-- Add note the `Task` about sticky bit --> - [x] #50989 <!-- fix incorrect results in `expm1(::Union{Float16, Float32})` --> - [x] #50912 <!-- Separate foreign threads into a :foreign threadpool --> - [x] #51019 <!-- fix a case of potentially use of undefined variable when handling error in distributed message processing --> - [x] #51222 <!-- Check again if the tty is open inside the IO lock --> - [x] #51254 <!-- Ryu: make sure adding zeros does not overwrite trailing dot --> - [x] #51284 <!-- Avoid infinite loop when doing SIGTRAP in arm64-apple --> - [x] #51491 <!-- Throw clearer ArgumentError for strip with two string args --> - [x] #51531 <!-- fix `_tryonce_download_from_cache` (busybox.exe download error) -->
2 parents bed2cd5 + 518eb7f commit bc55f44

File tree

63 files changed

+436
-239
lines changed

Some content is hidden

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

63 files changed

+436
-239
lines changed

Make.inc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -581,15 +581,15 @@ endif
581581

582582
ifeq ($(OS),WINNT)
583583
define versioned_libname
584-
$$(if $(2),$(1)-$(2).$(SHLIB_EXT),$(1).$(SHLIB_EXT))
584+
$(if $(2),$(1)-$(2).$(SHLIB_EXT),$(1).$(SHLIB_EXT))
585585
endef
586586
else ifeq ($(OS),Darwin)
587587
define versioned_libname
588-
$$(if $(2),$(1).$(2).$(SHLIB_EXT),$(1).$(SHLIB_EXT))
588+
$(if $(2),$(1).$(2).$(SHLIB_EXT),$(1).$(SHLIB_EXT))
589589
endef
590590
else
591591
define versioned_libname
592-
$$(if $(2),$(1).$(SHLIB_EXT).$(2),$(1).$(SHLIB_EXT))
592+
$(if $(2),$(1).$(SHLIB_EXT).$(2),$(1).$(SHLIB_EXT))
593593
endef
594594
endif
595595

base/channels.jl

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Channel(sz=0) = Channel{Any}(sz)
5959

6060
# special constructors
6161
"""
62-
Channel{T=Any}(func::Function, size=0; taskref=nothing, spawn=false)
62+
Channel{T=Any}(func::Function, size=0; taskref=nothing, spawn=false, threadpool=nothing)
6363
6464
Create a new task from `func`, bind it to a new channel of type
6565
`T` and size `size`, and schedule the task, all in a single call.
@@ -70,9 +70,14 @@ The channel is automatically closed when the task terminates.
7070
If you need a reference to the created task, pass a `Ref{Task}` object via
7171
the keyword argument `taskref`.
7272
73-
If `spawn = true`, the Task created for `func` may be scheduled on another thread
73+
If `spawn=true`, the `Task` created for `func` may be scheduled on another thread
7474
in parallel, equivalent to creating a task via [`Threads.@spawn`](@ref).
7575
76+
If `spawn=true` and the `threadpool` argument is not set, it defaults to `:default`.
77+
78+
If the `threadpool` argument is set (to `:default` or `:interactive`), this implies
79+
that `spawn=true` and the new Task is spawned to the specified threadpool.
80+
7681
Return a `Channel`.
7782
7883
# Examples
@@ -117,6 +122,9 @@ true
117122
In earlier versions of Julia, Channel used keyword arguments to set `size` and `T`, but
118123
those constructors are deprecated.
119124
125+
!!! compat "Julia 1.9"
126+
The `threadpool=` argument was added in Julia 1.9.
127+
120128
```jldoctest
121129
julia> chnl = Channel{Char}(1, spawn=true) do ch
122130
for c in "hello world"
@@ -129,12 +137,18 @@ julia> String(collect(chnl))
129137
"hello world"
130138
```
131139
"""
132-
function Channel{T}(func::Function, size=0; taskref=nothing, spawn=false) where T
140+
function Channel{T}(func::Function, size=0; taskref=nothing, spawn=false, threadpool=nothing) where T
133141
chnl = Channel{T}(size)
134142
task = Task(() -> func(chnl))
143+
if threadpool === nothing
144+
threadpool = :default
145+
else
146+
spawn = true
147+
end
135148
task.sticky = !spawn
136149
bind(chnl, task)
137150
if spawn
151+
Threads._spawn_set_thrpool(task, threadpool)
138152
schedule(task) # start it on (potentially) another thread
139153
else
140154
yield(task) # immediately start it, yielding the current thread
@@ -149,17 +163,17 @@ Channel(func::Function, args...; kwargs...) = Channel{Any}(func, args...; kwargs
149163
# of course not deprecated.)
150164
# We use `nothing` default values to check which arguments were set in order to throw the
151165
# deprecation warning if users try to use `spawn=` with `ctype=` or `csize=`.
152-
function Channel(func::Function; ctype=nothing, csize=nothing, taskref=nothing, spawn=nothing)
166+
function Channel(func::Function; ctype=nothing, csize=nothing, taskref=nothing, spawn=nothing, threadpool=nothing)
153167
# The spawn= keyword argument was added in Julia v1.3, and cannot be used with the
154168
# deprecated keyword arguments `ctype=` or `csize=`.
155-
if (ctype !== nothing || csize !== nothing) && spawn !== nothing
156-
throw(ArgumentError("Cannot set `spawn=` in the deprecated constructor `Channel(f; ctype=Any, csize=0)`. Please use `Channel{T=Any}(f, size=0; taskref=nothing, spawn=false)` instead!"))
169+
if (ctype !== nothing || csize !== nothing) && (spawn !== nothing || threadpool !== nothing)
170+
throw(ArgumentError("Cannot set `spawn=` or `threadpool=` in the deprecated constructor `Channel(f; ctype=Any, csize=0)`. Please use `Channel{T=Any}(f, size=0; taskref=nothing, spawn=false, threadpool=nothing)` instead!"))
157171
end
158172
# Set the actual default values for the arguments.
159173
ctype === nothing && (ctype = Any)
160174
csize === nothing && (csize = 0)
161175
spawn === nothing && (spawn = false)
162-
return Channel{ctype}(func, csize; taskref=taskref, spawn=spawn)
176+
return Channel{ctype}(func, csize; taskref=taskref, spawn=spawn, threadpool=threadpool)
163177
end
164178

165179
closed_exception() = InvalidStateException("Channel is closed.", :closed)

base/docs/basedocs.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,12 @@ Create a `Task` (i.e. coroutine) to execute the given function `func` (which
16921692
must be callable with no arguments). The task exits when this function returns.
16931693
The task will run in the "world age" from the parent at construction when [`schedule`](@ref)d.
16941694
1695+
!!! warning
1696+
By default tasks will have the sticky bit set to true `t.sticky`. This models the
1697+
historic default for [`@async`](@ref). Sticky tasks can only be run on the worker thread
1698+
they are first scheduled on. To obtain the behavior of [`Threads.@spawn`](@ref) set the sticky
1699+
bit manually to `false`.
1700+
16951701
# Examples
16961702
```jldoctest
16971703
julia> a() = sum(i for i in 1:1000);

base/file.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,9 @@ function rm(path::AbstractString; force::Bool=false, recursive::Bool=false)
303303
try
304304
ret = ccall(:uv_fs_rmdir, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Cstring, Ptr{Cvoid}), C_NULL, req, path, C_NULL)
305305
uv_fs_req_cleanup(req)
306-
ret < 0 && uv_error("rm($(repr(path)))", ret)
306+
if ret < 0 && !(force && ret == Base.UV_ENOENT)
307+
uv_error("rm($(repr(path)))", ret)
308+
end
307309
nothing
308310
finally
309311
Libc.free(req)

base/floatfuncs.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,20 @@ true
304304
function isapprox(x::Number, y::Number;
305305
atol::Real=0, rtol::Real=rtoldefault(x,y,atol),
306306
nans::Bool=false, norm::Function=abs)
307-
x == y || (isfinite(x) && isfinite(y) && norm(x-y) <= max(atol, rtol*max(norm(x), norm(y)))) || (nans && isnan(x) && isnan(y))
307+
x′, y′ = promote(x, y) # to avoid integer overflow
308+
x == y ||
309+
(isfinite(x) && isfinite(y) && norm(x-y) <= max(atol, rtol*max(norm(x′), norm(y′)))) ||
310+
(nans && isnan(x) && isnan(y))
311+
end
312+
313+
function isapprox(x::Integer, y::Integer;
314+
atol::Real=0, rtol::Real=rtoldefault(x,y,atol),
315+
nans::Bool=false, norm::Function=abs)
316+
if norm === abs && atol < 1 && rtol == 0
317+
return x == y
318+
else
319+
return norm(x - y) <= max(atol, rtol*max(norm(x), norm(y)))
320+
end
308321
end
309322

310323
"""

base/loading.jl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,12 +2231,6 @@ function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, in
22312231

22322232
# inherit permission from the source file (and make them writable)
22332233
chmod(tmppath, filemode(path) & 0o777 | 0o200)
2234-
if cache_objects
2235-
# Ensure that the user can execute the `.so` we're generating
2236-
# Note that on windows, `filemode(path)` typically returns `0o666`, so this
2237-
# addition of the execute bit for the user is doubly needed.
2238-
chmod(tmppath_so, filemode(path) & 0o777 | 0o333)
2239-
end
22402234

22412235
# prune the directory with cache files
22422236
if pkg.uuid !== nothing

base/partr.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ end
9595

9696
function multiq_insert(task::Task, priority::UInt16)
9797
tpid = ccall(:jl_get_task_threadpoolid, Int8, (Any,), task)
98+
@assert tpid > -1
9899
heap_p = multiq_size(tpid)
99100
tp = tpid + 1
100101

@@ -131,6 +132,9 @@ function multiq_deletemin()
131132

132133
tid = Threads.threadid()
133134
tp = ccall(:jl_threadpoolid, Int8, (Int16,), tid-1) + 1
135+
if tp == 0 # Foreign thread
136+
return nothing
137+
end
134138
tpheaps = heaps[tp]
135139

136140
@label retry
@@ -182,6 +186,9 @@ end
182186
function multiq_check_empty()
183187
tid = Threads.threadid()
184188
tp = ccall(:jl_threadpoolid, Int8, (Int16,), tid-1) + 1
189+
if tp == 0 # Foreign thread
190+
return true
191+
end
185192
for i = UInt32(1):length(heaps[tp])
186193
if heaps[tp][i].ntasks != 0
187194
return false

base/range.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -944,13 +944,13 @@ end
944944
# This is separate to make it useful even when running with --check-bounds=yes
945945
function unsafe_getindex(r::StepRangeLen{T}, i::Integer) where T
946946
i isa Bool && throw(ArgumentError("invalid index: $i of type Bool"))
947-
u = i - r.offset
947+
u = oftype(r.offset, i) - r.offset
948948
T(r.ref + u*r.step)
949949
end
950950

951951
function _getindex_hiprec(r::StepRangeLen, i::Integer) # without rounding by T
952952
i isa Bool && throw(ArgumentError("invalid index: $i of type Bool"))
953-
u = i - r.offset
953+
u = oftype(r.offset, i) - r.offset
954954
r.ref + u*r.step
955955
end
956956

base/ryu/exp.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ function writeexp(buf, pos, v::T,
147147
end
148148
roundUp = 0
149149
if lastDigit != 5
150-
roundUp = lastDigit > 5
150+
roundUp = lastDigit > 5 ? 1 : 0
151151
else
152152
rexp = precision - e
153153
requiredTwos = -e2 - rexp

base/ryu/fixed.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function writefixed(buf, pos, v::T,
3838
mant = bits & MANTISSA_MASK
3939
exp = Int((bits >> 52) & EXP_MASK)
4040

41-
if exp == 0
41+
if exp == 0 # subnormal
4242
e2 = 1 - 1023 - 52
4343
m2 = mant
4444
else
@@ -53,7 +53,7 @@ function writefixed(buf, pos, v::T,
5353
i = len - 1
5454
while i >= 0
5555
j = p10bits - e2
56-
#=@inbounds=# mula, mulb, mulc = POW10_SPLIT[POW10_OFFSET[idx + 1] + i + 1]
56+
mula, mulb, mulc = POW10_SPLIT[POW10_OFFSET[idx + 1] + i + 1]
5757
digits = mulshiftmod1e9(m2 << 8, mula, mulb, mulc, j + 8)
5858
if nonzero
5959
pos = append_nine_digits(digits, buf, pos)
@@ -103,7 +103,7 @@ function writefixed(buf, pos, v::T,
103103
end
104104
break
105105
end
106-
#=@inbounds=# mula, mulb, mulc = POW10_SPLIT_2[p + 1]
106+
mula, mulb, mulc = POW10_SPLIT_2[p + 1]
107107
digits = mulshiftmod1e9(m2 << 8, mula, mulb, mulc, j + 8)
108108
if i < blocks - 1
109109
pos = append_nine_digits(digits, buf, pos)
@@ -118,11 +118,11 @@ function writefixed(buf, pos, v::T,
118118
k += 1
119119
end
120120
if lastDigit != 5
121-
roundUp = lastDigit > 5
121+
roundUp = lastDigit > 5 ? 1 : 0
122122
else
123123
requiredTwos = -e2 - precision - 1
124124
trailingZeros = requiredTwos <= 0 || (requiredTwos < 60 && pow2(m2, requiredTwos))
125-
roundUp = trailingZeros ? 2 : 1
125+
roundUp = trailingZeros ? 2 : 1 # 2 means round only if odd
126126
end
127127
if maximum > 0
128128
pos = append_c_digits(maximum, digits, buf, pos)
@@ -137,13 +137,13 @@ function writefixed(buf, pos, v::T,
137137
while true
138138
roundPos -= 1
139139
if roundPos == (startpos - 1) || (buf[roundPos] == UInt8('-')) || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' '))
140+
buf[pos] = UInt8('0')
140141
buf[roundPos + 1] = UInt8('1')
141142
if dotPos > 1
142143
buf[dotPos] = UInt8('0')
143144
buf[dotPos + 1] = decchar
144145
hasfractional = true
145146
end
146-
buf[pos] = UInt8('0')
147147
pos += 1
148148
break
149149
end

0 commit comments

Comments
 (0)