diff --git a/src/deprecated.jl b/src/deprecated.jl index a6fdbc4c5..c22d6ab44 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -240,6 +240,11 @@ import Base: @deprecate (flag, stat) = Iprobe(src, tag, comm) flag || return (false, nothing, nothing) count = Get_count(stat, UInt8) + if isnothing(count) + # As in `recv`: counting in `UInt8` can only fail by overflowing the + # `Cint` that `MPI_Get_count` reports through. + error("`MPI.irecv`: the message is larger than $(typemax(Cint)) bytes, which `MPI_Get_count` cannot report") + end buf = Array{UInt8}(undef, count) stat = Recv!(buf, Get_source(stat), Get_tag(stat), comm) (true, MPI.deserialize(buf), stat) diff --git a/src/group.jl b/src/group.jl index 9dae360ef..fef07139b 100644 --- a/src/group.jl +++ b/src/group.jl @@ -49,7 +49,8 @@ end The rank of the process in the particular group. -Returns an integer in the range `0:MPI.Group_size()-1`. +Returns an integer in the range `0:MPI.Group_size()-1`, or `nothing` if the calling process +is not a member of `group`. # External links $(_doc_external("MPI_Group_rank")) @@ -57,6 +58,9 @@ $(_doc_external("MPI_Group_rank")) function Group_rank(group::Group) rank = Ref{Cint}() API.MPI_Group_rank(group, rank) + # `MPI_UNDEFINED` is not a rank; return `nothing` rather than let the + # sentinel escape as an ordinary integer. + rank[] == API.MPI_UNDEFINED[] && return nothing Int(rank[]) end diff --git a/src/nonblocking.jl b/src/nonblocking.jl index da19460f6..64bddd422 100644 --- a/src/nonblocking.jl +++ b/src/nonblocking.jl @@ -415,7 +415,9 @@ end The number of entries received. `T` should match the argument provided by the receive call that set the status variable. -If the number of entries received exceeds the limits of the count parameter, then it returns `MPI_UNDEFINED`. +Returns `nothing` if there is no meaningful count to report, which MPI signals as +`MPI_UNDEFINED`: either the number of entries received exceeds the limits of the count +parameter, or the number of bytes received is not a whole multiple of the size of `T`. # External links $(_doc_external("MPI_Get_count")) @@ -423,6 +425,9 @@ $(_doc_external("MPI_Get_count")) function Get_count(stat::Status, datatype::Datatype) count = Ref{Cint}() API.MPI_Get_count(Ref(stat), datatype, count) + # `MPI_UNDEFINED` is not a count; return `nothing` rather than let the + # sentinel escape as an ordinary integer (as `Waitany` and friends do). + count[] == API.MPI_UNDEFINED[] && return nothing Int(count[]) end Get_count(stat::Status, ::Type{T}) where {T} = Get_count(stat, Datatype(T)) diff --git a/src/pointtopoint.jl b/src/pointtopoint.jl index 76712f656..110ac5f9f 100644 --- a/src/pointtopoint.jl +++ b/src/pointtopoint.jl @@ -169,6 +169,12 @@ recv(comm::Comm, status=nothing; source::Integer=API.MPI_ANY_SOURCE[], tag::Inte function recv(source::Integer, tag::Integer, comm::Comm, status::Union{Ref{Status}, Nothing}) msg, stat = Mprobe(comm, Status; source=source, tag=tag) count = Get_count(stat, UInt8) + if isnothing(count) + # Counting in `UInt8` can only fail by overflowing the `Cint` that + # `MPI_Get_count` reports through; a byte count is necessarily a whole + # multiple of `sizeof(UInt8)`, so that cause cannot arise here. + error("`MPI.recv`: the message is larger than $(typemax(Cint)) bytes, which `MPI_Get_count` cannot report") + end buf = Array{UInt8}(undef, count) Mrecv!(buf, msg, status) return MPI.deserialize(buf) diff --git a/test/test_group.jl b/test/test_group.jl index 5f20729b1..0f024223c 100644 --- a/test/test_group.jl +++ b/test/test_group.jl @@ -19,6 +19,17 @@ grp5 = MPI.Group_excl(grp, Int32[0]) grp6 = MPI.Group_incl(grp, Int32[0]) @test MPI.Group_size(grp6) == 1 +# `Group_rank` must report a non-member as `nothing` rather than let MPI's +# `MPI_UNDEFINED` sentinel escape as an ordinary integer. Rank 0 is not a +# member of grp5, and every other rank is not a member of grp6. +if MPI.Comm_rank(comm) == 0 + @test MPI.Group_rank(grp5) === nothing + @test MPI.Group_rank(grp6) == 0 +else + @test MPI.Group_rank(grp5) == MPI.Comm_rank(comm) - 1 + @test MPI.Group_rank(grp6) === nothing +end + # Don't free the other groups MPI.free(grp) diff --git a/test/test_sendrecv.jl b/test/test_sendrecv.jl index d9cd3c51c..e7d70dac0 100644 --- a/test/test_sendrecv.jl +++ b/test/test_sendrecv.jl @@ -32,6 +32,18 @@ stats = MPI.Waitall(reqs, MPI.Status) @test MPI.Get_count(stats[2], Float64) == N @test recv_mesg == recv_mesg_expected +# `Get_count` must report `MPI_UNDEFINED` as `nothing` rather than let the +# sentinel escape as an ordinary integer. The message is N Float64s, and that +# many bytes is not a whole multiple of the size of a three-byte struct, so +# there is no integral count to report. +struct ThreeBytes + a::UInt8 + b::UInt8 + c::UInt8 +end +@test sizeof(Float64) * N % sizeof(ThreeBytes) != 0 # the premise of the test below +@test MPI.Get_count(stats[2], ThreeBytes) === nothing + @test MPI.Testall(reqs)