/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Programmer: Quincey Koziol * Saturday, September 12, 2015 * * Purpose: This file contains declarations which define macros for the * H5E package. Including this header means that the source file * is part of the H5E package. */ #ifndef H5Emodule_H #define H5Emodule_H /* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error * reporting macros. */ #define H5E_MODULE #define H5_MY_PKG H5E #define H5_MY_PKG_ERR H5E_ERROR /** \page H5E_UG HDF5 Error Handling * * \section sec_error HDF5 Error Handling * * 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. * * \subsection subsec_error_intro Introduction * 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. * * \ref subsec_error_ops 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. * * \ref subsec_error_adv 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, \ref H5Epush1, * \ref H5Eprint1, \ref H5Ewalk1, \ref H5Eclear1, \ref H5Eget_auto1, \ref H5Eset_auto1. These functions do * not have the error stack as a parameter. The library allows them to operate on the default error stack. * (The H5E compatibility macros will choose the correct function based on the parameters) * * The old API is similar to functionality discussed in \ref subsec_error_ops. The functionality discussed in * \ref subsec_error_adv,the ability of allowing applications to add their own error records, is the new * design for the Error Handling API. * * \subsection subsec_error_H5E Error Handling Function Summaries * @see H5E reference manual * * \subsection subsec_error_program Programming Model for Error Handling * This section is under construction. * * \subsection subsec_error_ops Basic Error Handling Operations * 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. For more information, see \ref subsec_error_adv. * * \subsubsection subsubsec_error_ops_stack Error Stack and Error Message * 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, \ref 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. * * * * * *
Example: An Error Message
*

If an application calls \ref H5Tclose on a * predefined datatype then the following message 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.10.9) thread 0.
 *    #000: H5T.c line ### in H5Tclose(): predefined datatype
 *       major: Function argument
 *       minor: Bad value
 *         
*
* 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. * * \subsubsection subsubsec_error_ops_print Print and Clear an Error Stack * Besides the automatic error report, the error stack can also be printed and cleared by the functions * \ref H5Eprint2 and \ref H5Eclear2. If an application wishes to make explicit * calls to \ref H5Eprint2 to print the error stack, the automatic printing should be turned off * to prevent error messages from being displayed twice (see \ref H5Eset_auto2). * * To print an error stack: * \code * herr_t H5Eprint2(hid_t error_stack, FILE * stream) * \endcode * 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. * \code * HDF5-DIAG: Error detected in HDF5 Library version: 1.10.9 thread 0. * \endcode * * To clear an error stack: * \code * herr_t H5Eclear2(hid_t error_stack) * \endcode * The \ref H5Eclear2 function shown above clears the error stack specified by error_stack. * \ref 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 \ref H5Eprint2. * * \subsubsection subsubsec_error_ops_mute Mute Error Stack * 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 \ref H5Eprint2 explicitly. In these situations, * it would be misleading if an error message were still automatically printed. Using the * \ref H5Eset_auto2 function can control the automatic printing of error messages. * * To enable or disable automatic printing of errors: * \code * herr_t H5Eset_auto2(hid_t error_stack, H5E_auto_t func, void *client_data) * \endcode * The \ref H5Eset_auto2 function can be used to turn 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 \ref H5Eprint2 and client_data * is the standard error stream pointer, stderr. * * To see the current settings: * \code * herr_t H5Eget_auto(hid_t error_stack, H5E_auto_t * func, void **client_data) * \endcode * 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. * * Example: Turn off error messages while probing a function * \code * *** Save old error handler *** * H5E_auto2_t oldfunc; * void *old_client_data; * H5Eget_auto2(error_stack, &old_func, &old_client_data); * *** Turn off error handling *** * H5Eset_auto2(error_stack, NULL, NULL); * *** Probe. Likely to fail, but that’s okay *** * status = H5Fopen (......); * *** Restore previous error handler *** * H5Eset_auto2(error_stack, old_func, old_client_data); * \endcode * * Or automatic printing can be disabled altogether and error messages can be explicitly printed. * * Example: Disable automatic printing and explicitly print error messages * \code * *** Turn off error handling permanently *** * H5Eset_auto2(error_stack, NULL, NULL); * *** If failure, print error message *** * if (H5Fopen (....)<0) { * H5Eprint2(H5E_DEFAULT, stderr); * exit (1); * } * \endcode * * \subsubsection subsubsec_error_ops_custom_print Customized Printing of an Error Stack * Applications are allowed to define an automatic error traversal function other than the default * \ref 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. * * Example: Defining a function to print a simple error message * \code * herr_t * my_hdf5_error_handler(void *unused) * { * fprintf (stderr, “An HDF5 error was detected. Bye.\\n”); * exit (1); * } * \endcode * * Example: The user‐defined error handler * \code * H5Eset_auto2(H5E_DEFAULT, my_hdf5_error_handler, NULL); * \endcode * * \subsubsection subsubsec_error_ops_walk Walk through the Error Stack * The \ref H5Eprint2 function is actually just a wrapper around the more complex \ref H5Ewalk function * which traverses an error stack and calls a user‐defined function for each member of the stack. The example * below shows how \ref H5Ewalk is used. * \code * herr_t H5Ewalk(hid_t err_stack, H5E_direction_t direction, * H5E_walk_t func, void *client_data) * \endcode * 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 \ref H5E_WALK_UPWARD, then traversal begins at the inner‐most function that * detected the error and concludes with the API function. Use \ref H5E_WALK_DOWNWARD for the opposite * order. * * \subsubsection subsubsec_error_ops_travers Traverse an Error Stack with a Callback Function * 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 \ref H5Ewalk. See the example below. * \code * typedef herr_t (*H5E_walk_t)(unsigned n, H5E_error2_t *eptr, void *client_data) * \endcode * The H5E_error2_t structure is shown below. * \code * 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; * \endcode * 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. * * Example: A user‐defined callback function * \code * \#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; * } * \endcode * *

Programming Note for C++ Developers Using C Functions

* If a C routine that takes a function pointer as an argument is called from within C++ code, the C routine * should be returned from normally. * * Examples of this kind of routine include callbacks such as \ref H5Pset_elink_cb and * \ref H5Pset_type_conv_cb and * functions such as \ref H5Tconvert and \ref H5Ewalk2. * * Exiting the routine in its normal fashion allows the HDF5 C Library to clean up its work properly. In other * words, if the C++ application jumps out of the routine back to the C++ “catch” statement, the library is * not given the opportunity to close any temporary data structures that were set up when the routine was * called. The C++ application should save some state as the routine is started so that any problem that * occurs might be diagnosed. * * \subsection subsec_error_adv Advanced Error Handling Operations * The section above, see \ref subsec_error_ops, 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. * * * * * * *
Example: An Error Report
*

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 ### in main():
 *         Error test failed
 *       major: Error in test
 *       minor: Error in subroutine
 *     #001: ../../hdf5/test/error_test.c line ### in
 *         test_error(): H5Dwrite failed as supposed to
 *       major: Error in IO
 *       minor: Error in H5Dwrite
 *   HDF5-DIAG: Error detected in HDF5 (1.10.9) thread #####:
 *     #002: ../../hdf5/src/H5Dio.c line ### in H5Dwrite():
 *         not a dataset
 *       major: Invalid arguments to routine
 *       minor: Inappropriate type
 *       
*
* 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. * * Example: The user‐defined error handler * \code * \#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; * } * \endcode * * \subsubsection subsubsec_error_adv_more More Error API Functions * 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: * \code * hid_t H5Eregister_class(const char* cls_name, const char* lib_name, const char* version) * \endcode * 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: * \code * hid_t H5Ecreate_msg(hid_t class, H5E_type_t msg_type, const char* mesg) * \endcode * 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: * \code * ssize_t H5Eget_class_name(hid_t class_id, char* name, size_t size) * \endcode * This function retrieves the name of the error class specified by the class ID. * * To retrieve an error message: * \code * ssize_t H5Eget_msg(hid_t mesg_id, H5E_type_t* mesg_type, char* mesg, size_t size) * \endcode * This function retrieves the error message including its length and type. * * To close an error message: * \code * herr_t H5Eclose_msg(hid_t mesg_id) * \endcode * This function closes an error message. * * To remove an error class: * \code * herr_t H5Eunregister_class(hid_t class_id) * \endcode * This function removes an error class from the Error API. * * The example below shows how an application creates an error class and error messages. * * Example: Create an error class and error messages * \code * *** 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, “... ...”); * \endcode * * The example below shows how an application closes error messages and unregisters the error class. * * Example: Closing error messages and unregistering the error class * \code * H5Eclose_msg(maj_id); * H5Eclose_msg(min_id); * H5Eunregister_class(class_id); * \endcode * * \subsubsection subsubsec_error_adv_app Pushing an Application Error Message onto Error Stack * 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: * \code * hid_t H5Eget_current_stack(void) * \endcode * 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: * \code * herr_t H5Eset_current_stack(hid_t error_stack) * \endcode * 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: * \code * 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, ... ) * \endcode * This function pushes a new error record onto the error stack for the current thread. * * To delete some error messages: * \code * herr_t H5Epop(hid_t error_stack, size_t count) * \endcode * This function deletes some error messages from the error stack. * * To retrieve the number of error records: * \code * int H5Eget_num(hid_t error_stack) * \endcode * This function retrieves the number of error records from an error stack. * * To clear the error stack: * \code * herr_t H5Eclear_stack(hid_t error_stack) * \endcode * This function clears the error stack. * * To close the object handle for an error stack: * \code * herr_t H5Eclose_stack(hid_t error_stack) * \endcode * 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. * * Example: Pushing an error message to an error stack * \code * *** 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; * \endcode * * 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. * * Example: Registering the error stack * \code * 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 *** * H5Epush2(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; * \endcode * * Previous Chapter \ref sec_attribute - Next Chapter \ref sec_plist * * \defgroup H5E Error Handling (H5E) * * \internal The \c FUNC_ENTER macro clears the error stack whenever an * interface function is entered. When an error is detected, an entry * is pushed onto the stack. As the functions unwind, additional * entries are pushed onto the stack. The API function will return * some indication that an error occurred and the application can * print the error stack. * * \internal Certain API functions in the \ref H5E package, such as H5Eprint(), * do not clear the error stack. Otherwise, any function which does * not have an underscore immediately after the package name will * clear the error stack. For instance, H5Fopen() clears the error * stack while \Code{H5F_open} does not. * * \internal An error stack has a fixed maximum size. If this size is exceeded * then the stack will be truncated and only the inner-most functions * will have entries on the stack. This is expected to be a rare * condition. * * \internal Each thread has its own error stack, but since multi-threading has * not been added to the library yet, this package maintains a single * error stack. The error stack is statically allocated to reduce the * complexity of handling errors within the \ref H5E package. * * @see sec_error * */ #endif /* H5Emodule_H */