The HDF5 Library provides an error reporting mechanism for both the library itself and for user application programs. It can trace errors through function stack and error information like file name, function name, line number, and error description.
Section 2 of this chapter discusses the HDF5 error handling programming model.
Section 3 presents summaries of HDF5’s error handling functions.
Section 4 discusses the basic error concepts such as error stack, error record, and error message and describes the related API functions. These concepts and functions are sufficient for application programs to trace errors inside the HDF5 Library.
Section 5 talks about the advanced concepts of error class and error stack handle and talks about the related functions. With these concepts and functions, an application library or program using the HDF5 Library can have its own error report blended with HDF5’s error report.
Starting with Release 1.8, we have a new set of Error Handling API functions.
For the purpose of backward compatibility with version 1.6 and before, we
still keep the old API functions, H5Epush
, H5Eprint
,
H5Ewalk
, H5Eclear
, H5Eget_auto
,
H5Eset_auto
. These functions do not have the error stack as
parameter. The library allows them to operate on the default error stack.
Users do not have to change their code to catch up with the new Error API
but are encouraged to do so.
The old API is similar to functionality discussed in Section 4. The functionality discussed in Section 5, the ability of allowing applications to add their own error records, is the library new design for the Error API.
This section is under construction.
Functions that can be used to handle errors (H5E functions) are listed below.
Function Listing 1. Error handling functions (H5E) | |
C Function Fortran Function |
Purpose |
H5Eauto_is_v2
|
Determines the type of error stack. |
H5Eclear
|
Clears the error stack for the current thread. The C function is a macro: see “API Compatibility Macros in HDF5.” |
H5Eclear_stack
|
Clears the error stack for the current thread. |
H5Eclose_msg
|
Closes an error message identifier. |
H5Eclose_stack
|
Closes object handle for error stack. |
H5Ecreate_msg
|
Add major error message to an error class. |
H5Eget_auto
|
Returns the current settings for the automatic error stack traversal function and its data. The C function is a macro: see “API Compatibility Macros in HDF5.” |
H5Eget_class_name
|
Retrieves error class name. |
H5Eget_current_stack
|
Registers the current error stack. |
H5Eget_msg
|
Retrieves an error message. |
H5Eget_num
|
Retrieves the number of error messages in an error stack. |
H5Epop
|
Deletes specified number of error messages from the error stack. |
H5Eprint
|
Prints the error stack in a default manner. The C function is a macro: see “API Compatibility Macros in HDF5.” |
H5Epush
|
Pushes new error record onto error stack. The C function is a macro: see “API Compatibility Macros in HDF5.” |
H5Eregister_class
|
Registers a client library or application program to the HDF5 error API. |
H5Eset_auto
|
Turns automatic error printing on or off. The C function is a macro: see “API Compatibility Macros in HDF5.” |
H5Eset_current_stack
|
Replaces the current error stack. |
H5Eunregister_class
|
Removes an error class. |
H5Ewalk
|
Walks the error stack for the current thread, calling a specified function. The C function is a macro: see “API Compatibility Macros in HDF5.” |
Let us first try to understand the error stack. An error stack is a collection of error records. Error records can be pushed onto or popped off the error stack. By default, when an error occurs deep within the HDF5 Library, an error record is pushed onto an error stack and that function returns a failure indication. Its caller detects the failure, pushes another record onto the stack, and returns a failure indication. This continues until the API function called by the application returns a failure indication. The next API function being called will reset the error stack. All HDF5 Library error records belong to the same error class (explained in Section 5).
In normal circumstances, an error causes the stack to be printed on the
standard error stream automatically. This automatic error stack is the
library’s default stack. For all the functions in this section,
whenever an error stack ID is needed as a parameter, H5E_DEFAULT
can be used to indicate the library’s default stack. The first
error record of the error stack, number #000
, is produced
by the API function itself and is usually sufficient to indicate to
the application what went wrong.
If an application calls H5Tclose
on a predefined datatype,
then the message in the example below is printed on the standard error
stream.
This is a simple error that has only one component, the API function;
other errors may have many components.
HDF5-DIAG: Error detected in HDF5 (1.6.4) thread 0. #000: H5T.c line 462 in H5Tclose(): predefined datatype major: Function argument minor: Bad value |
Example 1. An error report |
In the example above, we can see that an error record has a major message and a minor message. A major message generally indicates where the error happens. The location can be a dataset or a dataspace, for example. A minor message explains further details of the error. An example is “unable to open file”. Another specific detail about the error can be found at the end of the first line of each error record. This error description is usually added by the library designer to tell what exactly goes wrong. In the example above, the “predefined datatype” is an error description.
Besides the automatic error report, the error stack can also be printed
and cleared by the functions H5Eprint()
and
H5Eclear_stack()
. If an application wishes to make explicit
calls to H5Eprint()
to print the error stack, the
automatic printing should be turned off to prevent error messages from
being displayed twice (see H5Eset_auto()
below).
To print an error stack
herr_t H5Eprint(hid_t
error_stack, FILE * stream)
This function prints the error stack specified by error_stack
on the
specified stream, stream
. If the error stack is empty,
a one-line message will be printed. The following is an example of such a
message. This message would be generated if the error was in the HDF5
Library.
HDF5-DIAG: Error detected in HDF5 Library
version: 1.5.62 thread 0.
To clear an error stack
herr_t H5Eclear_stack(hid_t
error_stack)
The H5Eclear_stack
function shown above clears the error
stack specified by
error_stack
. H5E_DEFAULT
can be passed in to
clear the current error stack. The current stack is also cleared
whenever an API function is called; there are certain exceptions to this
rule such as H5Eprint()
.
Sometimes an application calls a function for the sake of its return value,
fully expecting the function to fail; sometimes the application wants to
call H5Eprint()
explicitly. In these situations, it
would be misleading if an error message were still automatically printed.
Using the H5Eset_auto()
function can control the automatic
printing of error messages.
To enable or disable automatic printing of errors
herr_t H5Eset_auto(hid_t
error_stack, H5E_auto_t func,
void *client_data)
The H5Eset_auto function can be used to turns on or off the automatic
printing of errors for the error stack
specified by error_stack
. When turned on (non-null func
pointer), any API function which returns an error indication will first call
func
, passing it client_data
as an argument.
When the library is first initialized the auto printing function is set to
H5Eprint()
(cast appropriately) and client_data
is
the standard error stream pointer, stderr
.
To see the current settings
herr_t H5Eget_auto(hid_t
error_stack, H5E_auto_t * func,
void **client_data )
The function above returns the current settings for the automatic error
stack traversal
function, func
, and its data, client_data
.
If either or both of the arguments are null, then the value is not
returned.
An application can temporarily turn off error messages while “probing” a function. See the example below.
/* Save old error handler */ herr_t (*old_func)(void*); void *old_client_data; H5Eget_auto(error_stack, &old_func, &old_client_data); /* Turn off error handling */ H5Eset_auto(error_stack, NULL, NULL); /* Probe. Likely to fail, but that’s okay */ status = H5Fopen (......); /* Restore previous error handler */ H5Eset_auto(error_stack, old_func, old_client_data); |
Example 2. Turn off error messages while probing a function |
Or automatic printing can be disabled altogether and error messages can be explicitly printed.
/* Turn off error handling permanently */ H5Eset_auto(error_stack, NULL, NULL); /* If failure, print error message */ if (H5Fopen (....)<0) { H5Eprint(H5E_DEFAULT, stderr); exit (1); } |
Example 3. Disable automatic printing and explicitly print error messages |
Applications are allowed to define an automatic error traversal
function other than the default H5Eprint()
. For
instance, one can define a function that prints a simple, one-line
error message to the standard error stream and then exits. The first
example below defines a such a function. The second example below installs
the function as the error handler.
herr_t my_hdf5_error_handler(void *unused) { fprintf (stderr, “An HDF5 error was detected. Bye.\n”); exit (1); } |
Example 4. Defining a function to print a simple error message |
H5Eset_auto(H5E_DEFAULT, my_hdf5_error_handler, NULL); |
Example 5. The user-defined error handler |
The H5Eprint()
function is actually just a
wrapper around the more complex H5Ewalk()
function which traverses an error stack and calls a user-defined
function for each member of the stack. The example below shows how
H5Ewalk
is used.
herr_t H5Ewalk(hid_t
err_stack, H5E_direction_t
direction, H5E_walk_t func,
void *client_data)
The error stack err_stack
is traversed and
func
is
called for each member of the stack. Its arguments are an integer
sequence number beginning at zero (regardless of direction
)
and the client_data
pointer. If direction
is H5E_WALK_UPWARD
, then traversal begins at the inner-most
function that detected the error and concludes with the API function.
Use H5E_WALK_DOWNWARD
for the opposite order.
An error stack traversal callback function takes three arguments:
n
is a sequence number beginning at zero for each traversal,
eptr
is a pointer to an error stack member, and
client_data
is the same pointer used in the example above
passed to H5Ewalk()
. See the example below.
typedef herr_t (*H5E_walk_t)(unsigned
n, H5E_error2_t *eptr, void *client_data)
The H5E_error2_t
structure is shown below.
typedef struct { hid_t cls_id; hid_t maj_num; hid_t min_num; unsigned line; const char *func_name; const char *file_name; const char *desc; } H5E_error2_t;
The maj_num
and min_num
are major and minor
error IDs, func_name
is the name of the function where the error
was detected, file_name
and line
locate the
error within the HDF5 Library source code, and desc
points
to a description of the error.
The following example shows a user-defined callback function.
#define MSG_SIZE 64 herr_t custom_print_cb(unsigned n, const H5E_error2_t *err_desc, void* client_data) { FILE *stream = (FILE *)client_data; char maj[MSG_SIZE]; char min[MSG_SIZE]; char cls[MSG_SIZE]; const int indent = 4; /* Get descriptions for the major and minor error numbers */ if(H5Eget_class_name(err_desc->cls_id, cls, MSG_SIZE)<0) TEST_ERROR; if(H5Eget_msg(err_desc->maj_num, NULL, maj, MSG_SIZE)<0) TEST_ERROR; if(H5Eget_msg(err_desc->min_num, NULL, min, MSG_SIZE)<0) TEST_ERROR; fprintf (stream, “%*serror #%03d: %s in %s(): line %u\n”, indent, “”, n, err_desc->file_name, err_desc->func_name, err_desc->line); fprintf (stream, “%*sclass: %s\n”, indent*2, “”, cls); fprintf (stream, “%*smajor: %s\n”, indent*2, “”, maj); fprintf (stream, “%*sminor: %s\n”, indent*2, “”, min); return 0; error: return -1; } |
Example 6. A user-defined callback function |
Section 4 discusses the basic error handling operations of the library. In that section, all the error records on the error stack are from the library itself. In this section, we are going to introduce the operations that allow an application program to push its own error records onto the error stack once it declares an error class of its own through the HDF5 Error API.
An error report shows both the library’s error record and the application’s error records. See the example below.
Error Test-DIAG: Error detected in Error Program (1.0) thread 8192: #000: ../../hdf5/test/error_test.c line 468 in main(): Error test failed major: Error in test minor: Error in subroutine #001: ../../hdf5/test/error_test.c line 150 in test_error(): H5Dwrite failed as supposed to major: Error in IO minor: Error in H5Dwrite HDF5-DIAG: Error detected in HDF5 (1.7.5) thread 8192: #002: ../../hdf5/src/H5Dio.c line 420 in H5Dwrite(): not a dataset major: Invalid arguments to routine minor: Inappropriate type |
Example 7. An error report |
In the line above error record #002
in the example above,
the starting phrase is HDF5
. This is the error class name
of the HDF5 Library. All of the library’s error messages
(major and minor) are in this default error class.
The Error Test
in the beginning of the line above error record
#000
is the name of the application’s error class.
The first two error records, #000
and #001
,
are from application’s error class.
By definition, an error class is a group of major and minor error messages for a library (the HDF5 Library or an application library built on top of the HDF5 Library) or an application program. The error class can be registered for a library or program through the HDF5 Error API. Major and minor messages can be defined in an error class. An application will have object handles for the error class and for major and minor messages for further operation. See the example below.
#define MSG_SIZE 64 herr_t custom_print_cb(unsigned n, const H5E_error2_t *err_desc, void* client_data) { FILE *stream = (FILE *)client_data; char maj[MSG_SIZE]; char min[MSG_SIZE]; char cls[MSG_SIZE]; const int indent = 4; /* Get descriptions for the major and minor error numbers */ if(H5Eget_class_name(err_desc->cls_id, cls, MSG_SIZE)<0) TEST_ERROR; if(H5Eget_msg(err_desc->maj_num, NULL, maj, MSG_SIZE)<0) TEST_ERROR; if(H5Eget_msg(err_desc->min_num, NULL, min, MSG_SIZE)<0) TEST_ERROR; fprintf (stream, “%*serror #%03d: %s in %s(): line %u\n”, indent, “”, n, err_desc->file_name, err_desc->func_name, err_desc->line); fprintf (stream, “%*sclass: %s\n”, indent*2, “”, cls); fprintf (stream, “%*smajor: %s\n”, indent*2, “”, maj); fprintf (stream, “%*sminor: %s\n”, indent*2, “”, min); return 0; error: return -1; } |
Example 8. Defining an error class |
The Error API has functions that can be used to register or unregister an error class, to create or close error messages, and to query an error class or error message. These functions are illustrated below.
To register an error class
hid_t H5Eregister_class(const char*
cls_name, const char* lib_name,
const char* version)
This function registers an error class with the HDF5 Library so that the application library or program can report errors together with the HDF5 Library.
To add an error message to an error class
hid_t H5Ecreate_msg(hid_t class,
H5E_type_t msg_type, const char* mesg)
This function adds an error message to an error class defined by an
application library or program. The error message can be either major
or minor which is indicated by parameter msg_type
.
To get the name of an error class
ssize_t H5Eget_class_name(hid_t class_id,
char* name, size_t size)
This function retrieves the name of the error class specified by
the class ID
.
To retrieve an error message
ssize_t H5Eget_msg(hid_t mesg_id,
H5E_type_t* mesg_type, char* mesg,
size_t size)
This function retrieves the error message including its length and type.
To close an error message
herr_t H5Eclose_msg(hid_t
mesg_id)
This function closes an error message.
To remove an error class
herr_t H5Eunregister_class(hid_t
class_id)
This function removes an error class from the Error API.
The example below shows how an application creates an error class and error messages.
/* Create an error class */ class_id = H5Eregister_class(ERR_CLS_NAME, PROG_NAME, PROG_VERS); /* Retrieve class name */ H5Eget_class_name(class_id, cls_name, cls_size); /* Create a major error message in the class */ maj_id = H5Ecreate_msg(class_id, H5E_MAJOR, “... ...”); /* Create a minor error message in the class */ min_id = H5Ecreate_msg(class_id, H5E_MINOR, “... ...”); |
Example 9. Create an error class and error messages |
The example below shows how an application closes error messages and unregisters the error class.
H5Eclose_msg(maj_id); H5Eclose_msg(min_id); H5Eunregister_class(class_id); |
Example 10. Closing error messages and unregistering the error class |
An application can push error records onto or pop error records off of the error stack just as the library does internally. An error stack can be registered, and an object handle can be returned to the application so that the application can manipulate a registered error stack.
To register the current stack
hid_t H5Eget_current_stack(void)
This function registers the current error stack, returns an object handle, and clears the current error stack. An empty error stack will also be assigned an ID.
To replace the current error stack with another
herr_t H5Eset_current_stack(hid_t
error_stack)
This function replaces the current error stack with another error stack
specified by error_stack
and clears the current error stack.
The object handle error_stack
is closed after this function
call.
To push a new error record to the error stack
herr_t H5Epush(hid_t
error_stack, const char* file,
const char* func, unsigned line,
hid_t cls_id, hid_t major_id,
hid_t minor_id, const char* desc,
... )
This function pushes a new error record onto the error stack for the current thread.
To delete some error messages
herr_t H5Epop(hid_t error_stack,
size_t count)
This function deletes some error messages from the error stack.
To retrieve the number of error records
int H5Eget_num(hid_t error_stack)
This function retrieves the number of error records from an error stack.
To clear the error stack
herr_t H5Eclear_stack(hid_t
error_stack)
This function clears the error stack.
To close the object handle for an error stack
herr_t H5Eclose_stack(hid_t
error_stack
)
This function closes the object handle for an error stack and releases its resources.
The example below shows how an application pushes an error record onto the default error stack.
/* Make call to HDF5 I/O routine */ if((dset_id=H5Dopen(file_id, dset_name, access_plist))<0) { /* Push client error onto error stack */ H5Epush(H5E_DEFAULT,__FILE__,FUNC,__LINE__,cls_id,CLIENT_ERR_MAJ_IO, CLIENT_ERR_MINOR_OPEN,“H5Dopen failed”); /* Indicate error occurred in function */ return(0); } |
Example 11. Pushing an error message to an error stack |
The example below shows how an application registers the current error stack and creates an object handle to avoid another HDF5 function from clearing the error stack.
if(H5Dwrite(dset_id, mem_type_id, mem_space_id, file_space_id, dset_xfer_plist_id, buf)<0) { /* Push client error onto error stack */ H5Epush(H5E_DEFAULT,__FILE__,FUNC,__LINE__,cls_id,CLIENT_ERR_MAJ_IO, CLIENT_ERR_MINOR_HDF5,“H5Dwrite failed”); /* Preserve the error stack by assigning an object handle to it */ error_stack = H5Eget_current_stack(); /* Close dataset */ H5Dclose(dset_id); /* Replace the current error stack with the preserved one */ H5Eset_current_stack(error_stack); Return(0); } |
Example 12. Registering the error stack |