Skip to content

release-1.7: Backports for 1.7.1 #43297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 15, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion base/loading.jl
Original file line number Diff line number Diff line change
@@ -1652,7 +1652,8 @@ function srctext_files(f::IO, srctextpos::Int64)
end

# Test to see if this UUID is mentioned in this `Project.toml`; either as
# the top-level UUID (e.g. that of the project itself) or as a dependency.
# the top-level UUID (e.g. that of the project itself), as a dependency,
# or as a extra for Preferences.
function get_uuid_name(project::Dict{String, Any}, uuid::UUID)
uuid_p = get(project, "uuid", nothing)::Union{Nothing, String}
name = get(project, "name", nothing)::Union{Nothing, String}
@@ -1667,6 +1668,16 @@ function get_uuid_name(project::Dict{String, Any}, uuid::UUID)
end
end
end
for subkey in ("deps", "extras")
subsection = get(project, subkey, nothing)::Union{Nothing, Dict{String, Any}}
if subsection !== nothing
for (k, v) in subsection
if uuid == UUID(v::String)
return k
end
end
end
end
return nothing
end

3 changes: 1 addition & 2 deletions base/version_git.sh
Original file line number Diff line number Diff line change
@@ -85,11 +85,10 @@ if [ -z "$fork_master_timestamp" ]; then
fi

build_system_directory="../.buildkite"
if [[ -d "${build_system_directory}/.git" ]]; then
if [ -d "${build_system_directory}/.git" ]; then
build_system_commit=$(git -C "${build_system_directory}" rev-parse HEAD)
build_system_commit_short=$(git -C "${build_system_directory}" rev-parse --short HEAD)
else
echo "Warning: The build system directory does not exist or is not a Git repo: ${build_system_directory}" >&2
build_system_commit=""
build_system_commit_short=""
fi

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9d69e3c7c27dc5254db9e1a928292cb5
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
80851a743a44176a6d10871b928ba8d025591e2fbfc125354904dcfafa7a5175080df216a5de8fd7c49d356a8491c6a5f63010e366a6819551ade352e4a34ab0
184 changes: 92 additions & 92 deletions deps/checksums/openblas

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions deps/gmp.mk
Original file line number Diff line number Diff line change
@@ -39,12 +39,13 @@ $(SRCCACHE)/gmp-$(GMP_VER)/gmp_alloc_overflow_func.patch-applied: $(SRCCACHE)/gm
patch -p1 < $(SRCDIR)/patches/gmp_alloc_overflow_func.patch
echo 1 > $@

$(SRCCACHE)/gmp-$(GMP_VER)/build-patched: \
$(SRCCACHE)/gmp-$(GMP_VER)/source-patched: \
$(SRCCACHE)/gmp-$(GMP_VER)/gmp-HG-changeset.patch-applied \
$(SRCCACHE)/gmp-$(GMP_VER)/gmp-exception.patch-applied \
$(SRCCACHE)/gmp-$(GMP_VER)/gmp_alloc_overflow_func.patch-applied
echo 1 > $@

$(BUILDDIR)/gmp-$(GMP_VER)/build-configured: $(SRCCACHE)/gmp-$(GMP_VER)/source-extracted $(SRCCACHE)/gmp-$(GMP_VER)/build-patched
$(BUILDDIR)/gmp-$(GMP_VER)/build-configured: $(SRCCACHE)/gmp-$(GMP_VER)/source-extracted $(SRCCACHE)/gmp-$(GMP_VER)/source-patched
mkdir -p $(dir $@)
cd $(dir $@) && \
$(dir $<)/configure $(CONFIGURE_COMMON) F77= --enable-cxx --enable-shared --disable-static $(GMP_CONFIGURE_OPTS)
27 changes: 17 additions & 10 deletions doc/Manifest.toml
Original file line number Diff line number Diff line change
@@ -2,6 +2,11 @@

manifest_format = "2.0"

[[deps.ANSIColoredPrinters]]
git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c"
uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9"
version = "0.0.1"

[[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

@@ -11,15 +16,15 @@ uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[deps.DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f"
git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.5"
version = "0.8.6"

[[deps.Documenter]]
deps = ["Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"]
git-tree-sha1 = "5acbebf1be22db43589bc5aa1bb5fcc378b17780"
deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"]
git-tree-sha1 = "f425293f7e0acaf9144de6d731772de156676233"
uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
version = "0.27.0"
version = "0.27.10"

[[deps.IOCapture]]
deps = ["Logging", "Random"]
@@ -33,9 +38,9 @@ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[deps.JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4"
git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.1"
version = "0.21.2"

[[deps.LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
@@ -53,12 +58,13 @@ uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[deps.NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
version = "1.2.0"

[[deps.Parsers]]
deps = ["Dates"]
git-tree-sha1 = "c8abc88faa3f7a3950832ac5d6e690881590d6dc"
git-tree-sha1 = "ae4bbcadb2906ccc085cf52ac286dc1377dceccc"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "1.1.0"
version = "2.1.2"

[[deps.Printf]]
deps = ["Unicode"]
@@ -69,11 +75,12 @@ deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[deps.Random]]
deps = ["Serialization"]
deps = ["SHA", "Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[deps.SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
version = "0.7.0"

[[deps.Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
1 change: 1 addition & 0 deletions doc/make.jl
Original file line number Diff line number Diff line change
@@ -303,6 +303,7 @@ makedocs(
# Update URLs to external stdlibs (JuliaLang/julia#43199)
for (root, _, files) in walkdir(output_path), file in joinpath.(root, files)
endswith(file, ".html") || continue
local str
str = read(file, String)
# Index page links, update
# https://github.com/JuliaLang/julia/blob/master/stdlib/${STDLIB_NAME}-${STDLIB_COMMIT}/path/to.md
2 changes: 1 addition & 1 deletion doc/src/manual/functions.md
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ and the `::Integer` specification means that it will only be callable when `n` i

Argument-type declarations **normally have no impact on performance**: regardless of what argument types (if any) are declared, Julia compiles a specialized version of the function for the actual argument types passed by the caller. For example, calling `fib(1)` will trigger the compilation of specialized version of `fib` optimized specifically for `Int` arguments, which is then re-used if `fib(7)` or `fib(15)` are called. (There are rare exceptions when an argument-type declaration can trigger additional compiler specializations; see: [Be aware of when Julia avoids specializing](@ref).) The most common reasons to declare argument types in Julia are, instead:

* **Dispatch:** As explained in [Methods](@ref), you can have different versions ("methods") of a function for different argument types, in which case the argument types are used to determine which implementation is called for which arguments. For example, you might implement a completely different algorithm `fib(x::Number) = ...` that works for any `Number` type by using [Binet's formula](https://en.wikipedia.org/wiki/Fibonacci_number#Binet's_formula) to extend it to non-integer values.
* **Dispatch:** As explained in [Methods](@ref), you can have different versions ("methods") of a function for different argument types, in which case the argument types are used to determine which implementation is called for which arguments. For example, you might implement a completely different algorithm `fib(x::Number) = ...` that works for any `Number` type by using [Binet's formula](https://en.wikipedia.org/wiki/Fibonacci_number#Binet%27s_formula) to extend it to non-integer values.
* **Correctness:** Type declarations can be useful if your function only returns correct results for certain argument types. For example, if we omitted argument types and wrote `fib(n) = n ≤ 2 ? one(n) : fib(n-1) + fib(n-2)`, then `fib(1.5)` would silently give us the nonsensical answer `1.0`.
* **Clarity:** Type declarations can serve as a form of documentation about the expected arguments.

39 changes: 8 additions & 31 deletions src/array.c
Original file line number Diff line number Diff line change
@@ -219,51 +219,28 @@ JL_DLLEXPORT jl_array_t *jl_reshape_array(jl_value_t *atype, jl_array_t *data,
jl_value_t *_dims)
{
jl_task_t *ct = jl_current_task;
jl_array_t *a;
assert(jl_types_equal(jl_tparam0(jl_typeof(data)), jl_tparam0(atype)));

size_t ndims = jl_nfields(_dims);
assert(is_ntuple_long(_dims));
size_t *dims = (size_t*)_dims;
assert(jl_types_equal(jl_tparam0(jl_typeof(data)), jl_tparam0(atype)));

int ndimwords = jl_array_ndimwords(ndims);
int tsz = sizeof(jl_array_t) + ndimwords * sizeof(size_t) + sizeof(void*);
a = (jl_array_t*)jl_gc_alloc(ct->ptls, tsz, atype);
jl_array_t *a = (jl_array_t*)jl_gc_alloc(ct->ptls, tsz, atype);
// No allocation or safepoint allowed after this
// copy data (except dims) from the old object
a->flags.pooled = tsz <= GC_MAX_SZCLASS;
a->flags.ndims = ndims;
a->offset = 0;
a->data = NULL;
a->flags.isaligned = data->flags.isaligned;
jl_array_t *owner = (jl_array_t*)jl_array_owner(data);
jl_value_t *eltype = jl_tparam0(atype);
size_t elsz = 0, align = 0;
int isboxed = !jl_islayout_inline(eltype, &elsz, &align);
assert(isboxed == data->flags.ptrarray);
if (!isboxed) {
a->elsize = LLT_ALIGN(elsz, align);
jl_value_t *ownerty = jl_typeof(owner);
size_t oldelsz = 0, oldalign = 0;
if (ownerty == (jl_value_t*)jl_string_type) {
oldalign = 1;
}
else {
jl_islayout_inline(jl_tparam0(ownerty), &oldelsz, &oldalign);
}
if (oldalign < align)
jl_exceptionf(jl_argumenterror_type,
"reinterpret from alignment %d bytes to alignment %d bytes not allowed",
(int) oldalign, (int) align);
a->flags.ptrarray = 0;
a->flags.hasptr = data->flags.hasptr;
}
else {
a->elsize = sizeof(void*);
a->flags.ptrarray = 1;
a->flags.hasptr = 0;
}
a->elsize = data->elsize;
a->flags.ptrarray = data->flags.ptrarray;
a->flags.hasptr = data->flags.hasptr;

// if data is itself a shared wrapper,
// owner should point back to the original array
jl_array_t *owner = (jl_array_t*)jl_array_owner(data);
jl_array_data_owner(a) = (jl_value_t*)owner;

a->flags.how = 3;
12 changes: 6 additions & 6 deletions src/datatype.c
Original file line number Diff line number Diff line change
@@ -248,9 +248,9 @@ int jl_struct_try_layout(jl_datatype_t *dt)
return 1;
}

int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree) JL_NOTSAFEPOINT
int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree)
{
if (ty->name->mayinlinealloc && (ty->isconcretetype || ((jl_datatype_t*)jl_unwrap_unionall(ty->name->wrapper))->layout)) { // TODO: use jl_struct_try_layout(dt) (but it is a safepoint)
if (ty->name->mayinlinealloc && jl_struct_try_layout(ty)) {
if (ty->layout->npointers > 0) {
if (pointerfree)
return 0;
@@ -264,7 +264,7 @@ int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree) JL_NOTSAFEPOIN
return 0;
}

static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbytes, size_t *align, int asfield) JL_NOTSAFEPOINT
static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbytes, size_t *align, int asfield)
{
if (jl_is_uniontype(ty)) {
unsigned na = union_isinlinable(((jl_uniontype_t*)ty)->a, 1, nbytes, align, asfield);
@@ -290,19 +290,19 @@ static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbyte
return 0;
}

int jl_uniontype_size(jl_value_t *ty, size_t *sz) JL_NOTSAFEPOINT
int jl_uniontype_size(jl_value_t *ty, size_t *sz)
{
size_t al = 0;
return union_isinlinable(ty, 0, sz, &al, 0) != 0;
}

JL_DLLEXPORT int jl_islayout_inline(jl_value_t *eltype, size_t *fsz, size_t *al) JL_NOTSAFEPOINT
JL_DLLEXPORT int jl_islayout_inline(jl_value_t *eltype, size_t *fsz, size_t *al)
{
unsigned countbits = union_isinlinable(eltype, 0, fsz, al, 1);
return (countbits > 0 && countbits < 127) ? countbits : 0;
}

JL_DLLEXPORT int jl_stored_inline(jl_value_t *eltype) JL_NOTSAFEPOINT
JL_DLLEXPORT int jl_stored_inline(jl_value_t *eltype)
{
size_t fsz = 0, al = 0;
return jl_islayout_inline(eltype, &fsz, &al);
10 changes: 4 additions & 6 deletions src/jltypes.c
Original file line number Diff line number Diff line change
@@ -46,12 +46,10 @@ static int layout_uses_free_typevars(jl_value_t *v, jl_typeenv_t *env)
layout_uses_free_typevars(((jl_uniontype_t*)v)->b, env);
if (jl_is_vararg(v)) {
jl_vararg_t *vm = (jl_vararg_t*)v;
if (vm->T) {
if (layout_uses_free_typevars(vm->T, env))
return 1;
if (vm->N && layout_uses_free_typevars(vm->N, env))
return 1;
}
if (vm->T && layout_uses_free_typevars(vm->T, env))
return 1;
if (vm->N && layout_uses_free_typevars(vm->N, env))
return 1;
return 0;
}
if (jl_is_unionall(v)) {
4 changes: 2 additions & 2 deletions src/julia.h
Original file line number Diff line number Diff line change
@@ -1495,8 +1495,8 @@ JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t i, jl_value_t *r
JL_DLLEXPORT int jl_field_isdefined(jl_value_t *v, size_t i) JL_NOTSAFEPOINT;
JL_DLLEXPORT jl_value_t *jl_get_field(jl_value_t *o, const char *fld);
JL_DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a);
int jl_uniontype_size(jl_value_t *ty, size_t *sz) JL_NOTSAFEPOINT;
JL_DLLEXPORT int jl_islayout_inline(jl_value_t *eltype, size_t *fsz, size_t *al) JL_NOTSAFEPOINT;
int jl_uniontype_size(jl_value_t *ty, size_t *sz);
JL_DLLEXPORT int jl_islayout_inline(jl_value_t *eltype, size_t *fsz, size_t *al);

// arrays
JL_DLLEXPORT jl_array_t *jl_new_array(jl_value_t *atype, jl_value_t *dims);
6 changes: 3 additions & 3 deletions src/signals-unix.c
Original file line number Diff line number Diff line change
@@ -817,10 +817,10 @@ static void *signal_listener(void *arg)
bt_data_prof[bt_size_cur++].uintptr = 0;
bt_data_prof[bt_size_cur++].uintptr = 0;
}

// notify thread to resume
jl_thread_resume(i, sig);
}

// notify thread to resume
jl_thread_resume(i, sig);
}
jl_unlock_profile();
}
129 changes: 101 additions & 28 deletions stdlib/Distributed/src/remotecall.jl
Original file line number Diff line number Diff line change
@@ -26,12 +26,13 @@ mutable struct Future <: AbstractRemoteRef
where::Int
whence::Int
id::Int
v::Union{Some{Any}, Nothing}
lock::ReentrantLock
@atomic v::Union{Some{Any}, Nothing}

Future(w::Int, rrid::RRID, v::Union{Some, Nothing}=nothing) =
(r = new(w,rrid.whence,rrid.id,v); return test_existing_ref(r))
(r = new(w,rrid.whence,rrid.id,ReentrantLock(),v); return test_existing_ref(r))

Future(t::NTuple{4, Any}) = new(t[1],t[2],t[3],t[4]) # Useful for creating dummy, zeroed-out instances
Future(t::NTuple{4, Any}) = new(t[1],t[2],t[3],ReentrantLock(),t[4]) # Useful for creating dummy, zeroed-out instances
end

"""
@@ -69,10 +70,17 @@ function test_existing_ref(r::AbstractRemoteRef)
found = getkey(client_refs, r, nothing)
if found !== nothing
@assert r.where > 0
if isa(r, Future) && found.v === nothing && r.v !== nothing
# we have recd the value from another source, probably a deserialized ref, send a del_client message
send_del_client(r)
found.v = r.v
if isa(r, Future)
# this is only for copying the reference from Future to RemoteRef (just created)
fv_cache = @atomic :acquire found.v
rv_cache = @atomic :monotonic r.v
if fv_cache === nothing && rv_cache !== nothing
# we have recd the value from another source, probably a deserialized ref, send a del_client message
send_del_client(r)
@lock found.lock begin
@atomicreplace found.v nothing => rv_cache
end
end
end
return found::typeof(r)
end
@@ -91,8 +99,9 @@ function finalize_ref(r::AbstractRemoteRef)
send_del_client_no_lock(r)
else
# send_del_client only if the reference has not been set
r.v === nothing && send_del_client_no_lock(r)
r.v = nothing
v_cache = @atomic :monotonic r.v
v_cache === nothing && send_del_client_no_lock(r)
@atomic :monotonic r.v = nothing
end
r.where = 0
finally
@@ -201,7 +210,8 @@ isready(f) # will not block
```
"""
function isready(rr::Future)
rr.v === nothing || return true
v_cache = @atomic rr.v
v_cache === nothing || return true

rid = remoteref_id(rr)
return if rr.where == myid()
@@ -354,26 +364,33 @@ end

channel_type(rr::RemoteChannel{T}) where {T} = T

serialize(s::ClusterSerializer, f::Future) = serialize(s, f, f.v === nothing)
serialize(s::ClusterSerializer, rr::RemoteChannel) = serialize(s, rr, true)
function serialize(s::ClusterSerializer, rr::AbstractRemoteRef, addclient)
if addclient
function serialize(s::ClusterSerializer, f::Future)
v_cache = @atomic f.v
if v_cache === nothing
p = worker_id_from_socket(s.io)
(p !== rr.where) && send_add_client(rr, p)
(p !== f.where) && send_add_client(f, p)
end
fc = Future((f.where, f.whence, f.id, v_cache)) # copy to be used for serialization (contains a reset lock)
invoke(serialize, Tuple{ClusterSerializer, Any}, s, fc)
end

function serialize(s::ClusterSerializer, rr::RemoteChannel)
p = worker_id_from_socket(s.io)
(p !== rr.where) && send_add_client(rr, p)
invoke(serialize, Tuple{ClusterSerializer, Any}, s, rr)
end

function deserialize(s::ClusterSerializer, t::Type{<:Future})
f = invoke(deserialize, Tuple{ClusterSerializer, DataType}, s, t)
f2 = Future(f.where, RRID(f.whence, f.id), f.v) # ctor adds to client_refs table
fc = invoke(deserialize, Tuple{ClusterSerializer, DataType}, s, t) # deserialized copy
f2 = Future(fc.where, RRID(fc.whence, fc.id), fc.v) # ctor adds to client_refs table

# 1) send_add_client() is not executed when the ref is being serialized
# to where it exists, hence do it here.
# 2) If we have received a 'fetch'ed Future or if the Future ctor found an
# already 'fetch'ed instance in client_refs (Issue #25847), we should not
# track it in the backing RemoteValue store.
if f2.where == myid() && f2.v === nothing
f2v_cache = @atomic f2.v
if f2.where == myid() && f2v_cache === nothing
add_client(remoteref_id(f2), myid())
end
f2
@@ -570,7 +587,7 @@ end
Wait for a value to become available for the specified [`Future`](@ref).
"""
wait(r::Future) = (r.v !== nothing && return r; call_on_owner(wait_ref, r, myid()); r)
wait(r::Future) = (v_cache = @atomic r.v; v_cache !== nothing && return r; call_on_owner(wait_ref, r, myid()); r)

"""
wait(r::RemoteChannel, args...)
@@ -587,11 +604,49 @@ Further calls to `fetch` on the same reference return the cached value. If the r
is an exception, throws a [`RemoteException`](@ref) which captures the remote exception and backtrace.
"""
function fetch(r::Future)
r.v !== nothing && return something(r.v)
v = call_on_owner(fetch_ref, r)
r.v = Some(v)
v_cache = @atomic r.v
v_cache !== nothing && return something(v_cache)

if r.where == myid()
rv, v_cache = @lock r.lock begin
v_cache = @atomic :monotonic r.v
rv = v_cache === nothing ? lookup_ref(remoteref_id(r)) : nothing
rv, v_cache
end

if v_cache !== nothing
return something(v_cache)
else
v_local = fetch(rv.c)
end
else
v_local = call_on_owner(fetch_ref, r)
end

v_cache = @atomic r.v

if v_cache === nothing # call_on_owner case
v_old, status = @lock r.lock begin
@atomicreplace r.v nothing => Some(v_local)
end
# status == true - when value obtained through call_on_owner
# status == false - any other situation: atomicreplace fails, because by the time the lock is obtained cache will be populated
# why? local put! performs caching and putting into channel under r.lock

# for local put! use the cached value, for call_on_owner cases just take the v_local as it was just cached in r.v

# remote calls getting the value from `call_on_owner` used to return the value directly without wrapping it in `Some(x)`
# so we're doing the same thing here
if status
send_del_client(r)
return v_local
else # this `v_cache` is returned at the end of the function
v_cache = v_old
end
end

send_del_client(r)
v
something(v_cache)
end

fetch_ref(rid, args...) = fetch(lookup_ref(rid).c, args...)
@@ -615,12 +670,30 @@ A `put!` on an already set `Future` throws an `Exception`.
All asynchronous remote calls return `Future`s and set the
value to the return value of the call upon completion.
"""
function put!(rr::Future, v)
rr.v !== nothing && error("Future can be set only once")
call_on_owner(put_future, rr, v, myid())
rr.v = Some(v)
rr
function put!(r::Future, v)
if r.where == myid()
rid = remoteref_id(r)
rv = lookup_ref(rid)
isready(rv) && error("Future can be set only once")
@lock r.lock begin
put!(rv, v) # this notifies the tasks waiting on the channel in fetch
set_future_cache(r, v) # set the cache before leaving the lock, so that the notified tasks already see it cached
end
del_client(rid, myid())
else
@lock r.lock begin # same idea as above if there were any local tasks fetching on this Future
call_on_owner(put_future, r, v, myid())
set_future_cache(r, v)
end
end
r
end

function set_future_cache(r::Future, v)
_, ok = @atomicreplace r.v nothing => Some(v)
ok || error("internal consistency error detected for Future")
end

function put_future(rid, v, caller)
rv = lookup_ref(rid)
isready(rv) && error("Future can be set only once")
13 changes: 13 additions & 0 deletions stdlib/Distributed/test/distributed_exec.jl
Original file line number Diff line number Diff line change
@@ -350,6 +350,9 @@ function test_regular_io_ser(ref::Distributed.AbstractRemoteRef)
v = getfield(ref2, fld)
if isa(v, Number)
@test v === zero(typeof(v))
elseif fld == :lock
@test v isa ReentrantLock
@test !islocked(v)
elseif v !== nothing
error(string("Add test for field ", fld))
end
@@ -838,6 +841,16 @@ v15406 = remotecall_wait(() -> 1, id_other)
fetch(v15406)
remotecall_wait(fetch, id_other, v15406)


# issue #43396
# Covers the remote fetch where the value returned is `nothing`
# May be caused by attempting to unwrap a non-`Some` type with `something`
# `call_on_owner` ref fetches return values not wrapped in `Some`
# and have to be returned directly
@test nothing === fetch(remotecall(() -> nothing, workers()[1]))
@test 10 === fetch(remotecall(() -> 10, workers()[1]))


# Test various forms of remotecall* invocations

@everywhere f_args(v1, v2=0; kw1=0, kw2=0) = v1+v2+kw1+kw2
2 changes: 1 addition & 1 deletion stdlib/OpenBLAS_jll/Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "OpenBLAS_jll"
uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
version = "0.3.13+9"
version = "0.3.13+11"

[deps]
CompilerSupportLibraries_jll = "e66e0078-7015-5450-92f7-15fbd957f2ae"
2 changes: 1 addition & 1 deletion stdlib/Pkg.version
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PKG_BRANCH = release-1.7
PKG_SHA1 = 0779de5302e03bf768f9167fa4aad4d78ba3af96
PKG_SHA1 = 0fae7809dbaa400d99cbe3a5b39c82332a1381d1
PKG_GIT_URL := git://github.com/JuliaLang/Pkg.jl.git
PKG_TAR_URL = https://github.com/api/repos/JuliaLang/Pkg.jl/tarball/$1
4 changes: 2 additions & 2 deletions stdlib/Test/src/Test.jl
Original file line number Diff line number Diff line change
@@ -1056,8 +1056,8 @@ end
function get_alignment(ts::DefaultTestSet, depth::Int)
# The minimum width at this depth is
ts_width = 2*depth + length(ts.description)
# If all passing, no need to look at children
!ts.anynonpass && return ts_width
# If not verbose and all passing, no need to look at children
!ts.verbose && !ts.anynonpass && return ts_width
# Return the maximum of this width and the minimum width
# for all children (if they exist)
isempty(ts.results) && return ts_width
24 changes: 12 additions & 12 deletions stdlib/Test/test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1025,17 +1025,17 @@ end

@testset "verbose option" begin
expected = """
Test Summary: | Pass Total
Parent | 9 9
Child 1 | 3 3
Child 1.1 | 1 1
Child 1.2 | 1 1
Child 1.3 | 1 1
Child 2 | 3 3
Child 3 | 3 3
Child 3.1 | 1 1
Child 3.2 | 1 1
Child 3.3 | 1 1
Test Summary: | Pass Total
Parent | 9 9
Child 1 | 3 3
Child 1.1 (long name) | 1 1
Child 1.2 | 1 1
Child 1.3 | 1 1
Child 2 | 3 3
Child 3 | 3 3
Child 3.1 | 1 1
Child 3.2 | 1 1
Child 3.3 | 1 1
"""

mktemp() do f, _
@@ -1045,7 +1045,7 @@ end
@testset "Parent" verbose = true begin
@testset "Child 1" verbose = true begin
@testset "Child 1.1" begin
@testset "Child 1.1 (long name)" begin
@test 1 == 1
end
9 changes: 9 additions & 0 deletions test/compiler/codegen.jl
Original file line number Diff line number Diff line change
@@ -602,6 +602,15 @@ get_llvm(g41438, ()); # cause allocation of layout
@test S41438{Int}.layout != C_NULL
@test !Base.datatype_pointerfree(S41438{Int})


# issue #43303
struct A43303{T}
x::Pair{Ptr{T},Ptr{T}}
end
@test A43303.body.layout != C_NULL
@test isbitstype(A43303{Int})
@test A43303.body.types[1].layout != C_NULL

# issue #41157
f41157(a, b) = a[1] = b[1]
@test_throws BoundsError f41157(Tuple{Int}[], Tuple{Union{}}[])
36 changes: 36 additions & 0 deletions test/loading.jl
Original file line number Diff line number Diff line change
@@ -189,6 +189,42 @@ end
end
end

# extras
@testset "extras" begin
mktempdir() do dir
project_file = joinpath(dir, "Project.toml")
touch(project_file) # dummy_uuid calls realpath
# various UUIDs to work with
proj_uuid = dummy_uuid(project_file)
root_uuid = uuid4()
this_uuid = uuid4()

old_load_path = copy(LOAD_PATH)
try
copy!(LOAD_PATH, [project_file])
write(project_file, """
name = "Root"
uuid = "$root_uuid"
[extras]
This = "$this_uuid"
""")
# look up various packages by name
root = Base.identify_package("Root")
this = Base.identify_package("This")
that = Base.identify_package("That")

@test root.uuid == root_uuid
@test this == nothing
@test that == nothing

@test Base.get_uuid_name(project_file, this_uuid) == "This"
finally
copy!(LOAD_PATH, old_load_path)
end
end
end


## functional testing of package identification, location & loading ##

saved_load_path = copy(LOAD_PATH)