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}