Skip to content
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

add basic error handler functionality #457

Merged
merged 3 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
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
4 changes: 4 additions & 0 deletions deps/consts_microsoftmpi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const MPI_MAXLOC = reinterpret(Cint, 0x5800000c)
const MPI_REPLACE = reinterpret(Cint, 0x5800000d)
const MPI_NO_OP = reinterpret(Cint, 0x5800000e)

const MPI_Errhandler = Cint
const MPI_ERRORS_ARE_FATAL = Cint(0x54000000)
const MPI_ERRORS_RETURN = Cint(0x54000001)

const MPI_Request = Cint
const MPI_REQUEST_NULL = reinterpret(Cint, 0x2c000000)

Expand Down
4 changes: 4 additions & 0 deletions deps/consts_mpich.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const MPI_COMM_NULL = Cint(67108864)
const MPI_COMM_SELF = Cint(1140850689)
const MPI_COMM_WORLD = Cint(1140850688)

const MPI_Errhandler = Cint
const MPI_ERRORS_ARE_FATAL = Cint(0x54000000)
const MPI_ERRORS_RETURN = Cint(0x54000001)

const MPI_Request = Cint
const MPI_REQUEST_NULL = Cint(738197504)

Expand Down
5 changes: 5 additions & 0 deletions deps/consts_openmpi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const MPI_COMM_NULL = Cint(2)
const MPI_COMM_SELF = Cint(1)
const MPI_COMM_WORLD = Cint(0)

const MPI_Errhandler = Ptr{Cvoid}
MPI_Errhandler_f2c(c::Cint) = ccall((:MPI_Errhandler_f2c,libmpi),MPI_Errhandler,(Cint,),c)
const MPI_ERRORS_ARE_FATAL = Cint(1)
const MPI_ERRORS_RETURN = Cint(2)

const MPI_Request = Ptr{Cvoid}
MPI_Request_f2c(c::Cint) = ccall((:MPI_Request_f2c,libmpi),MPI_Request,(Cint,),c)
const MPI_REQUEST_NULL = Cint(0)
Expand Down
4 changes: 4 additions & 0 deletions deps/gen_consts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ MPI_handle = [
:MPI_COMM_SELF,
:MPI_COMM_WORLD,
],
:MPI_Errhandler => [
:MPI_ERRORS_ARE_FATAL,
:MPI_ERRORS_RETURN,
],
:MPI_Request => [
:MPI_REQUEST_NULL,
],
Expand Down
8 changes: 8 additions & 0 deletions docs/src/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ MPI.Info
MPI.infoval
```

## Error handler objects

```@docs
MPI.ErrorHandler
MPI.get_errorhandler
MPI.set_errorhandler!
```

1 change: 1 addition & 0 deletions src/MPI.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ include("collective.jl")
include("topology.jl")
include("onesided.jl")
include("io.jl")
include("errorhandler.jl")
include("mpiexec_wrapper.jl")

include("deprecated.jl")
Expand Down
30 changes: 21 additions & 9 deletions src/environment.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ end


"""
Init(;finalize_atexit=true)
Init(;finalize_atexit=true, errors_return=true)

Initialize MPI in the current process, and if `finalize_atexit` is true and adds an
`atexit` hook to call [`MPI.Finalize`](@ref) if it hasn't already been called.
Initialize MPI in the current process. The keyword options:

- `finalize_atexit`: if true, adds an `atexit` hook to call [`MPI.Finalize`](@ref) if it hasn't already been called.
- `errors_return`: if true, will set the default error handlers for [`MPI.COMM_SELF`](@ref) and [`MPI.COMM_WORLD`](@ref) to be `MPI.ERRORS_RETURN`. MPI errors will appear as Julia exceptions.

All MPI programs must contain exactly one call to `MPI.Init` or
[`MPI.Init_thread`](@ref). In particular, note that it is not valid to call `MPI.Init` or
Expand All @@ -80,13 +82,16 @@ The only MPI functions that may be called before `MPI.Init`/`MPI.Init_thread` ar
# External links
$(_doc_external("MPI_Init"))
"""
function Init(;finalize_atexit=true)
function Init(;finalize_atexit=true, errors_return=true)
@mpichk ccall((:MPI_Init, libmpi), Cint, (Ptr{Cint},Ptr{Cint}), C_NULL, C_NULL)
if finalize_atexit
atexit(_finalize)
end

run_init_hooks()
if errors_return
set_default_error_handler_return()
end
_warn_if_wrong_mpi()
end

Expand Down Expand Up @@ -119,13 +124,17 @@ end


"""
Init_thread(required::ThreadLevel; finalize_atexit=true)
Init_thread(required::ThreadLevel; finalize_atexit=true, errors_return=true)

Initialize MPI and the MPI thread environment in the current process, and if
`finalize_atexit` is true and adds an `atexit` hook to call [`MPI.Finalize`](@ref) if it
hasn't already been called. The argument specifies the required level of threading
Initialize MPI and the MPI thread environment in the current process. The argument specifies the required level of threading
support, see [`ThreadLevel`](@ref).

The keyword options are:

- `finalize_atexit`: if true, adds an `atexit` hook to call [`MPI.Finalize`](@ref) if it hasn't already been called.
- `errors_return`: if true, will set the default error handlers for [`MPI.COMM_SELF`](@ref) and [`MPI.COMM_WORLD`](@ref) to be `MPI.ERRORS_RETURN`. MPI errors will appear as Julia exceptions.


The function will return the provided `ThreadLevel`, and values may be compared via
inequalities, i.e.

Expand All @@ -144,7 +153,7 @@ The only MPI functions that may be called before `MPI.Init`/`MPI.Init_thread` ar
# External links
$(_doc_external("MPI_Init_thread"))
"""
function Init_thread(required::ThreadLevel; finalize_atexit=true)
function Init_thread(required::ThreadLevel; finalize_atexit=true, errors_return=true)
r_provided = Ref{ThreadLevel}()
# int MPI_Init_thread(int *argc, char ***argv, int required, int *provided)
@mpichk ccall((:MPI_Init_thread, libmpi), Cint,
Expand All @@ -159,6 +168,9 @@ function Init_thread(required::ThreadLevel; finalize_atexit=true)
atexit(_finalize)
end
run_init_hooks()
if errors_return
set_default_error_handler_return()
end
_warn_if_wrong_mpi()
return provided
end
Expand Down
77 changes: 77 additions & 0 deletions src/errorhandler.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
MPI.Errhandler

An MPI error handler object. Currently only two are supported:

- `ERRORS_ARE_FATAL` (default): program will immediately abort
- `ERRORS_RETURN`: program will throw an `MPIError`.
"""
@mpi_handle ErrorHandler MPI_Errhandler

const ERRORS_ARE_FATAL = _ErrorHandler(MPI_ERRORS_ARE_FATAL)
const ERRORS_RETURN = _ErrorHandler(MPI_ERRORS_RETURN)

function free(errh::ErrorHandler)
if !Finalized()
# int MPI_Errhandler_free(MPI_Errhandler *errhandler)
@mpichk ccall((:MPI_Errhandler_free, libmpi), Cint, (Ptr{MPI_Errhandler},), errh)
end
return nothing
end

function set_default_error_handler_return()
set_errorhandler!(COMM_SELF, ERRORS_RETURN)
set_errorhandler!(COMM_WORLD, ERRORS_RETURN)
end

"""
MPI.get_errorhandler(comm::MPI.Comm)
MPI.get_errorhandler(win::MPI.Win)
MPI.get_errorhandler(file::MPI.File.FileHandle)

Get the current [`ErrorHandler`](@ref) for the relevant MPI object.

# See also
- [`set_errorhandler!`](@ref)
"""
function get_errorhandler(comm::Comm)
errh = ErrorHandler(ERRORS_ARE_FATAL.val)
@mpichk ccall((:MPI_Comm_get_errhandler, libmpi), Cint, (MPI_Comm, Ptr{MPI_Errhandler}), comm, errh)
finalizer(free, errh)
return errh
end
function get_errorhandler(win::Win)
errh = ErrorHandler(ERRORS_ARE_FATAL.val)
@mpichk ccall((:MPI_Win_get_errhandler, libmpi), Cint, (MPI_Win, Ptr{MPI_Errhandler}), win, errh)
return errh
end
function get_errorhandler(file::File.FileHandle)
errh = ErrorHandler(ERRORS_ARE_FATAL.val)
@mpichk ccall((:MPI_File_get_errhandler, libmpi), Cint, (MPI_File, Ptr{MPI_Errhandler}), file, errh)
return errh
end

"""
MPI.set_errorhandler!(comm::MPI.Comm, errh::ErrorHandler)
MPI.set_errorhandler!(win::MPI.Win, errh::ErrorHandler)
MPI.set_errorhandler!(file::MPI.File.FileHandle, errh::ErrorHandler)

Set the [`ErrorHandler`](@ref) for the relevant MPI object.

# See also
- [`get_errorhandler`](@ref)
"""
function set_errorhandler!(comm::Comm, errh::ErrorHandler)
@mpichk ccall((:MPI_Comm_set_errhandler, libmpi), Cint, (MPI_Comm, MPI_Errhandler), comm, errh)
return nothing
end
function set_errorhandler!(win::Win, errh::ErrorHandler)
@mpichk ccall((:MPI_Win_set_errhandler, libmpi), Cint, (MPI_Win, MPI_Errhandler), win, errh)
return nothing
end
function set_errorhandler!(file::File.FileHandle, errh::ErrorHandler)
@mpichk ccall((:MPI_File_set_errhandler, libmpi), Cint, (MPI_File, MPI_Errhandler), file, errh)
return nothing
end


10 changes: 10 additions & 0 deletions test/test_errorhandler.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using MPI, Test
MPI.Init()

@test MPI.ERRORS_ARE_FATAL != MPI.ERRORS_RETURN
@test MPI.get_errorhandler(MPI.COMM_SELF) == MPI.ERRORS_RETURN
@test_throws MPI.MPIError MPI.Send(rand(10), 2, 0, MPI.COMM_SELF)

MPI.set_errorhandler!(MPI.COMM_SELF, MPI.ERRORS_ARE_FATAL)
@test MPI.get_errorhandler(MPI.COMM_SELF) == MPI.ERRORS_ARE_FATAL