Skip to main content

mpi/
error.rs

1//! Error classes and error handlers (`MPI_Errhandler`, `MPI_ERR_*`).
2//!
3//! Communicators carry an error handler; the two predefined handlers are
4//! [`ErrorHandler::Fatal`] (abort the job on error, the MPI default) and
5//! [`ErrorHandler::Return`] (return the error code to the caller). Because the
6//! rest of this implementation reports failures by panicking or via `Result`,
7//! the handler is primarily informational, but the full class vocabulary and
8//! `set`/`get` API are provided.
9
10use std::collections::HashMap;
11use std::sync::Mutex;
12
13use crate::topology::Communicator;
14
15/// Error classes, mirroring the standard `MPI_ERR_*` constants.
16pub mod class {
17    /// No error (`MPI_SUCCESS`).
18    pub const SUCCESS: i32 = 0;
19    /// Invalid buffer pointer (`MPI_ERR_BUFFER`).
20    pub const BUFFER: i32 = 1;
21    /// Invalid count argument (`MPI_ERR_COUNT`).
22    pub const COUNT: i32 = 2;
23    /// Invalid datatype argument (`MPI_ERR_TYPE`).
24    pub const TYPE: i32 = 3;
25    /// Invalid tag argument (`MPI_ERR_TAG`).
26    pub const TAG: i32 = 4;
27    /// Invalid communicator (`MPI_ERR_COMM`).
28    pub const COMM: i32 = 5;
29    /// Invalid rank (`MPI_ERR_RANK`).
30    pub const RANK: i32 = 6;
31    /// Invalid request (`MPI_ERR_REQUEST`).
32    pub const REQUEST: i32 = 7;
33    /// Invalid root (`MPI_ERR_ROOT`).
34    pub const ROOT: i32 = 8;
35    /// Invalid group (`MPI_ERR_GROUP`).
36    pub const GROUP: i32 = 9;
37    /// Invalid operation (`MPI_ERR_OP`).
38    pub const OP: i32 = 10;
39    /// Invalid topology (`MPI_ERR_TOPOLOGY`).
40    pub const TOPOLOGY: i32 = 11;
41    /// Invalid dimension argument (`MPI_ERR_DIMS`).
42    pub const DIMS: i32 = 12;
43    /// Invalid argument (`MPI_ERR_ARG`).
44    pub const ARG: i32 = 13;
45    /// Unknown error (`MPI_ERR_UNKNOWN`).
46    pub const UNKNOWN: i32 = 14;
47    /// Message truncated on receive (`MPI_ERR_TRUNCATE`).
48    pub const TRUNCATE: i32 = 15;
49    /// Other known error (`MPI_ERR_OTHER`).
50    pub const OTHER: i32 = 16;
51    /// Internal implementation error (`MPI_ERR_INTERN`).
52    pub const INTERN: i32 = 17;
53    /// Pending request (`MPI_ERR_PENDING`).
54    pub const PENDING: i32 = 18;
55    /// Error in an I/O operation (`MPI_ERR_IO`).
56    pub const IO: i32 = 32;
57    /// The last standard error class (`MPI_ERR_LASTCODE`).
58    pub const LASTCODE: i32 = 64;
59}
60
61/// A human-readable description of an error class (`MPI_Error_string`).
62pub fn error_string(code: i32) -> String {
63    let s = match code {
64        class::SUCCESS => "no error",
65        class::BUFFER => "invalid buffer pointer",
66        class::COUNT => "invalid count argument",
67        class::TYPE => "invalid datatype argument",
68        class::TAG => "invalid tag argument",
69        class::COMM => "invalid communicator",
70        class::RANK => "invalid rank",
71        class::REQUEST => "invalid request",
72        class::ROOT => "invalid root",
73        class::GROUP => "invalid group",
74        class::OP => "invalid operation",
75        class::TOPOLOGY => "invalid topology",
76        class::DIMS => "invalid dimension argument",
77        class::ARG => "invalid argument",
78        class::TRUNCATE => "message truncated on receive",
79        class::OTHER => "known error not in this list",
80        class::INTERN => "internal MPI error",
81        class::PENDING => "pending request",
82        class::IO => "I/O error",
83        _ => "unknown error",
84    };
85    s.to_string()
86}
87
88/// The error class of an error code (`MPI_Error_class`). Here codes are their
89/// own class.
90pub fn error_class(code: i32) -> i32 {
91    code
92}
93
94/// A communicator error handler (`MPI_Errhandler`).
95#[derive(Copy, Clone, Debug, PartialEq, Eq)]
96pub enum ErrorHandler {
97    /// Abort the job when an error is raised (`MPI_ERRORS_ARE_FATAL`, default).
98    Fatal,
99    /// Return the error code to the caller (`MPI_ERRORS_RETURN`).
100    Return,
101}
102
103static HANDLERS: Mutex<Option<HashMap<u32, ErrorHandler>>> = Mutex::new(None);
104
105fn with_handlers<R>(f: impl FnOnce(&mut HashMap<u32, ErrorHandler>) -> R) -> R {
106    let mut guard = HANDLERS.lock().unwrap();
107    f(guard.get_or_insert_with(HashMap::new))
108}
109
110/// Error-handler operations on communicators. Blanket-implemented for every
111/// [`Communicator`].
112pub trait CommunicatorErrorHandler: Communicator {
113    /// Set this communicator's error handler (`MPI_Comm_set_errhandler`).
114    fn set_error_handler(&self, handler: ErrorHandler) {
115        let ctx = self.comm_data().context;
116        with_handlers(|h| {
117            h.insert(ctx, handler);
118        });
119    }
120
121    /// Get this communicator's error handler (`MPI_Comm_get_errhandler`).
122    /// Defaults to [`ErrorHandler::Fatal`].
123    fn error_handler(&self) -> ErrorHandler {
124        let ctx = self.comm_data().context;
125        with_handlers(|h| *h.get(&ctx).unwrap_or(&ErrorHandler::Fatal))
126    }
127}
128
129impl<C: Communicator + ?Sized> CommunicatorErrorHandler for C {}
130
131/// Re-exports for `use mpi::error::traits::*;`.
132pub mod traits {
133    pub use super::CommunicatorErrorHandler;
134}