Error handling
Table of Contents
-
The QMCkl library implements a robust error handling mechanism to ensure that errors are properly communicated to the calling program without causing unexpected termination. The library adheres to the principle that library code should never make the calling programs abort, nor perform any input/output operations. This decision has to be taken by the developer of the code calling the library, allowing for better integration with diverse software environments and error recovery strategies.
Exit codes
All the functions in the QMCkl library return with an exit code, defined as
typedef int32_t qmckl_exit_code;
The exit code provides a standardized way to return the completion status
of a function to the calling program. When a function call completes
successfully, QMCKL_SUCCESS (value 0) is returned. If one of the functions
of the library fails to complete the requested task, an appropriate error
code is returned to the program.
This approach allows calling programs to check the return value and handle errors appropriately, implementing their own error recovery strategies or logging mechanisms. The error codes are designed to be self-documenting, with specific codes for common error conditions such as invalid arguments, allocation failures, and context-related issues.
Here is the complete list of exit codes:
| Macro | Code | Description |
|---|---|---|
QMCKL_SUCCESS |
0 | 'Success' |
QMCKL_INVALID_ARG_1 |
1 | 'Invalid argument 1' |
QMCKL_INVALID_ARG_2 |
2 | 'Invalid argument 2' |
QMCKL_INVALID_ARG_3 |
3 | 'Invalid argument 3' |
QMCKL_INVALID_ARG_4 |
4 | 'Invalid argument 4' |
QMCKL_INVALID_ARG_5 |
5 | 'Invalid argument 5' |
QMCKL_INVALID_ARG_6 |
6 | 'Invalid argument 6' |
QMCKL_INVALID_ARG_7 |
7 | 'Invalid argument 7' |
QMCKL_INVALID_ARG_8 |
8 | 'Invalid argument 8' |
QMCKL_INVALID_ARG_9 |
9 | 'Invalid argument 9' |
QMCKL_INVALID_ARG_10 |
10 | 'Invalid argument 10' |
QMCKL_INVALID_ARG_11 |
11 | 'Invalid argument 11' |
QMCKL_INVALID_ARG_12 |
12 | 'Invalid argument 12' |
QMCKL_INVALID_ARG_13 |
13 | 'Invalid argument 13' |
QMCKL_INVALID_ARG_14 |
14 | 'Invalid argument 14' |
QMCKL_INVALID_ARG_15 |
15 | 'Invalid argument 15' |
QMCKL_INVALID_ARG_16 |
16 | 'Invalid argument 16' |
QMCKL_INVALID_ARG_17 |
17 | 'Invalid argument 17' |
QMCKL_INVALID_ARG_18 |
18 | 'Invalid argument 18' |
QMCKL_INVALID_ARG_19 |
19 | 'Invalid argument 19' |
QMCKL_INVALID_ARG_20 |
20 | 'Invalid argument 20' |
QMCKL_FAILURE |
101 | 'Failure' |
QMCKL_ERRNO |
102 | strerror(errno) |
QMCKL_INVALID_CONTEXT |
103 | 'Invalid context' |
QMCKL_ALLOCATION_FAILED |
104 | 'Allocation failed' |
QMCKL_DEALLOCATION_FAILED |
105 | 'De-allocation failed' |
QMCKL_NOT_PROVIDED |
106 | 'Not provided' |
QMCKL_OUT_OF_BOUNDS |
107 | 'Index out of bounds' |
QMCKL_ALREADY_SET |
108 | 'Already set' |
QMCKL_INVALID_EXIT_CODE |
109 | 'Invalid exit code' |
String conversion
The qmckl_string_of_error function converts an exit code into a human-readable
string representation. This is useful for logging and error reporting purposes.
The string is assumed to be large enough to contain the error message
(typically 128 characters).
1. Decoding errors
To facilitate debugging and error reporting, QMCkl provides the
qmckl_string_of_error function which converts an error code into
a descriptive string. This allows applications to present meaningful
error messages to users or write detailed logs for troubleshooting.
The function takes an error code as input and returns a constant string describing the error condition. Both C and Fortran interfaces are provided for maximum compatibility.
const char* qmckl_string_of_error (const qmckl_exit_code error);
The text strings returned by this function are extracted from the error codes table defined earlier. This ensures consistency between the error codes and their string representations throughout the library.
2. Data structure in context
The QMCkl context maintains detailed error state information through a dedicated data structure. This structure stores not only the error code, but also the name of the function where the error occurred and a descriptive message explaining the error condition.
The strings are declared internally with a maximum fixed size to avoid dynamic memory allocation, which is important for performance and thread safety. This design choice ensures that error handling itself does not introduce additional failure modes or performance bottlenecks.
3. Updating errors in the context
The error state in the context is updated using the qmckl_set_error
function. This function provides a centralized mechanism for recording
errors that occur during library operations.
When an error is set in the context, it is mandatory to specify
from which function the error is triggered, and a message
explaining the error. The exit code can't be QMCKL_SUCCESS.
This detailed error information enables precise debugging and helps users understand exactly what went wrong and where, making it easier to diagnose and fix issues in code using the QMCkl library.
qmckl_exit_code qmckl_set_error(qmckl_context context, const qmckl_exit_code exit_code, const char* function_name, const char* message);
4. Get the error
Upon error, the calling program can retrieve detailed error information from the
context using qmckl_get_error. This function provides access to the error
code, the name of the function where the error occurred, and a descriptive
message explaining the error condition.
The error message and function name are returned in the variables provided by the caller. Therefore, passing valid pointers for the function name and message is mandatory. The caller must ensure that the provided buffers are large enough to hold the error information.
This retrieval mechanism allows applications to implement sophisticated error handling strategies, such as retry logic, fallback mechanisms, or detailed logging for post-mortem analysis.
qmckl_exit_code qmckl_get_error(qmckl_context context, qmckl_exit_code *exit_code, char* function_name, char* message);
5. Failing
To make a function fail, the qmckl_failwith function should be
called, such that information about the failure is stored in
the context. The desired exit code is given as an argument, as
well as the name of the function and an error message. If the
message is NULL, then the default message obtained by
qmckl_string_of_error is used. The return code of the function is
the desired return code.
Upon failure, a QMCKL_NULL_CONTEXT is returned.
qmckl_exit_code qmckl_failwith(qmckl_context context, const qmckl_exit_code exit_code, const char* function, const char* message) ;
For example, this function can be used as
if (x < 0) { return qmckl_failwith(context, QMCKL_INVALID_ARG_2, "qmckl_function", "Expected x >= 0"); }
6. Last error
Returns a string describing the last error, using qmckl_get_error.
qmckl_exit_code qmckl_last_error(qmckl_context context, char* buffer);
7. Helper functions for debugging
The following function prints to stderr an error message is the return code is
not QMCKL_SUCCESS.
qmckl_exit_code qmckl_check(qmckl_context context, qmckl_exit_code rc);
It should be used as:
rc = qmckl_check(context,
qmckl_...(context, ...)
);
assert (rc == QMCKL_SUCCESS);