diff options
author | Robb Matzke <matzke@llnl.gov> | 1998-02-28 18:19:05 (GMT) |
---|---|---|
committer | Robb Matzke <matzke@llnl.gov> | 1998-02-28 18:19:05 (GMT) |
commit | 808a5e6be1b7f1025c6b1182e160cefbce0f8e68 (patch) | |
tree | 59eabaf3e7991d5791b83dbaa0d5797fc5e44ae9 | |
parent | 0b4d32bb4a12fe0e34026c0f069aa99bf34cd834 (diff) | |
download | hdf5-808a5e6be1b7f1025c6b1182e160cefbce0f8e68.zip hdf5-808a5e6be1b7f1025c6b1182e160cefbce0f8e68.tar.gz hdf5-808a5e6be1b7f1025c6b1182e160cefbce0f8e68.tar.bz2 |
[svn-r302] Changes since 19980227
----------------------
./html/Errors.html [NEW]
./html/H5.user.html
./MANIFEST
Documents the new error handling interface and gives examples.
./src/H5.c
./src/H5private.h
./src/H5Apublic.h
./src/H5E.c
./src/H5Eprivate.h
./src/H5Epublic.h
Rewrote error handling. Got rid of `push' overloading and
added a few API functions. The error stack is statically
allocated and not entered into H5A, simplifying error handling
within the error handler. Rudimentary support for threads.
Changed the names of some errors.
./src/H5G.c
./src/H5Gnode.c
./src/H5H.c
./src/H5O.c
./src/H5T.c
Changed H5ECLEAR to H5E_clear().
./src/Makefile.in
Alphabetized source list.
./test/dsets.c
Turned off error reporting around functions that are expected
to fail. Error messages are sent to stdout.
./test/testhdf5.c
./test/testhdf5.h
Turned off automatic error reporting since this file mostly
calls internal functions and does its own error reporting.
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | src/H5.c | 9 | ||||
-rw-r--r-- | src/H5Apublic.h | 3 | ||||
-rw-r--r-- | src/H5E.c | 941 | ||||
-rw-r--r-- | src/H5Eprivate.h | 169 | ||||
-rw-r--r-- | src/H5Epublic.h | 36 | ||||
-rw-r--r-- | src/H5G.c | 10 | ||||
-rw-r--r-- | src/H5Gnode.c | 2 | ||||
-rw-r--r-- | src/H5H.c | 2 | ||||
-rw-r--r-- | src/H5O.c | 4 | ||||
-rw-r--r-- | src/H5T.c | 14 | ||||
-rw-r--r-- | src/H5private.h | 13 | ||||
-rw-r--r-- | src/Makefile.in | 6 | ||||
-rw-r--r-- | test/dsets.c | 21 | ||||
-rw-r--r-- | test/testhdf5.c | 7 | ||||
-rw-r--r-- | test/testhdf5.h | 88 |
16 files changed, 675 insertions, 651 deletions
@@ -39,6 +39,7 @@ ./html/Datasets.html ./html/Dataspaces.html ./html/Datatypes.html +./html/Errors.html ./html/ExternalFiles.html ./html/Files.html ./html/Groups.html @@ -185,11 +185,6 @@ H5_init_thread(void) { FUNC_ENTER_INIT(H5_init_thread, NULL, FAIL); - /* Create/initialize this thread's error stack */ - if ((H5E_thrdid_g = H5Ecreate(16)) == FAIL) - HRETURN_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, - "unable to create thread error stack"); - /* Add the "thread termination" routine to the exit chain */ if (H5_add_exit(&H5_term_thread) == FAIL) HRETURN_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, @@ -218,9 +213,7 @@ H5_init_thread(void) --------------------------------------------------------------------------*/ void H5_term_thread(void) -{ - H5Eclose(H5E_thrdid_g); -} /* end H5_term_thread() */ +{/*void*/} /*-------------------------------------------------------------------------- NAME diff --git a/src/H5Apublic.h b/src/H5Apublic.h index 9e9966e..7bc14c9 100644 --- a/src/H5Apublic.h +++ b/src/H5Apublic.h @@ -23,8 +23,7 @@ /* Group values allowed */ typedef enum { BADGROUP = (-1),/*invalid Group */ - H5_ERR = 0, /*group ID for Error stack objects */ - H5_FILE, /*group ID for File objects */ + H5_FILE = 0, /*group ID for File objects */ H5_TEMPLATE_0, /*group ID for Template objects */ H5_TEMPLATE_1, /*group ID for Template objects */ H5_TEMPLATE_2, /*group ID for Template objects */ @@ -1,598 +1,583 @@ -/**************************************************************************** -* NCSA HDF * -* Software Development Group * -* National Center for Supercomputing Applications * -* University of Illinois at Urbana-Champaign * -* 605 E. Springfield, Champaign IL 61820 * -* * -* For conditions of distribution and use, see the accompanying * -* hdf/COPYING file. * - * - * Notes: It is safe to call HRETURN_ERROR(), HGOTO_ERROR(), HERROR(), and - * H5ECLEAR within any of these functions except H5E_push() (see - * comments in H5E_push()). However, some of the H5E API functions - * don't call H5ECLEAR the the error stack on which they're operating - * is the thread's global error stack. If the thread's global error - * stack isn't defined yet, then HRETURN_ERROR(), HGOTO_ERROR(), and - * HERROR() don't push an error message and H5ECLEAR just returns - * without doing anything. -* * -****************************************************************************/ - -#ifdef RCSID -static char RcsId[] = "@(#)$Revision$"; -#endif - -/* $Id$ */ - -#include <H5private.h> /* Generic Functions */ -#include <H5Aprivate.h> /* Atoms */ -#include <H5Eprivate.h> /* Private error routines */ -#include <H5MMprivate.h> /* Memory management */ - -#define PABLO_MASK H5E_mask - -/*-------------------- Locally scoped variables -----------------------------*/ - -static const H5E_major_mesg_t H5E_major_mesg_g[] = -{ - {H5E_NONE_MAJOR, "No error"}, - {H5E_ARGS, "Invalid arguments to routine"}, - {H5E_RESOURCE, "Resource unavailable"}, - {H5E_INTERNAL, "Internal HDF5 error"}, - {H5E_FILE, "File Accessability"}, - {H5E_IO, "Low-level I/O"}, - {H5E_FUNC, "Function Entry/Exit"}, - {H5E_ATOM, "Object Atom"}, - {H5E_CACHE, "Object Cache"}, - {H5E_BTREE, "B-Tree Node"}, - {H5E_SYM, "Symbol Table"}, - {H5E_HEAP, "Heap"}, - {H5E_OHDR, "Object Header"}, - {H5E_DATATYPE, "Datatype"}, - {H5E_DATASPACE, "Dataspace"}, - {H5E_DATASET, "Dataset"}, - {H5E_STORAGE, "Data Storage"}, - {H5E_TEMPLATE, "Template"}, +/* + * Copyright (C) 1998 NCSA HDF + * All rights reserved. + * + * Purpose: Provides error handling in the form of a stack. The + * FUNC_ENTER() macro clears the error stack whenever an API + * 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. + * + * Certain API functions in the H5E package (such as H5Eprint()) + * do not clear the error stack. Otherwise, any function which + * doesn't have an underscore immediately after the package name + * will clear the error stack. For instance, H5Fopen() clears + * the error stack while H5F_open() does not. + * + * 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. + * + * 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 H5E package. + * + */ +#include <H5private.h> /* Generic Functions */ +#include <H5Aprivate.h> /* Atoms */ +#include <H5Eprivate.h> /* Private error routines */ +#include <H5MMprivate.h> /* Memory management */ + +#define PABLO_MASK H5E_mask + +static const H5E_major_mesg_t H5E_major_mesg_g[] = { + {H5E_NONE_MAJOR, "No error"}, + {H5E_ARGS, "Function arguments"}, + {H5E_RESOURCE, "Resource unavailable"}, + {H5E_INTERNAL, "Internal HDF5 error"}, + {H5E_FILE, "File interface"}, + {H5E_IO, "Low-level I/O layer"}, + {H5E_FUNC, "Function entry/exit"}, + {H5E_ATOM, "Atom layer"}, + {H5E_CACHE, "Meta data cache layer"}, + {H5E_BTREE, "B-tree layer"}, + {H5E_SYM, "Symbol table layer"}, + {H5E_HEAP, "Heap layer"}, + {H5E_OHDR, "Object header layer"}, + {H5E_DATATYPE, "Datatype interface"}, + {H5E_DATASPACE, "Dataspace interface"}, + {H5E_DATASET, "Dataset interface"}, + {H5E_STORAGE, "Data storage layer"}, + {H5E_TEMPLATE, "Property list interface"}, }; -static const H5E_minor_mesg_t H5E_minor_mesg_g[] = -{ - {H5E_NONE_MINOR, "No error"}, +static const H5E_minor_mesg_t H5E_minor_mesg_g[] = { + {H5E_NONE_MINOR, "No error"}, {H5E_UNINITIALIZED, "Information is uninitialized"}, - {H5E_UNSUPPORTED, "Feature is unsupported"}, - {H5E_BADTYPE, "Incorrect type found"}, - {H5E_BADRANGE, "Argument out of range"}, - {H5E_BADVALUE, "Bad value for argument"}, - {H5E_NOSPACE, "No space available for allocation"}, - {H5E_FILEEXISTS, "File already exists"}, - {H5E_FILEOPEN, "File already open"}, - {H5E_CANTCREATE, "Can't create file"}, - {H5E_CANTOPENFILE, "Can't open file"}, - {H5E_CANTOPENOBJ, "Can't open object"}, - {H5E_NOTHDF5, "Not an HDF5 format file"}, - {H5E_BADFILE, "Bad file ID accessed"}, - {H5E_TRUNCATED, "File has been truncated"}, - {H5E_SEEKERROR, "Seek failed"}, - {H5E_READERROR, "Read failed"}, - {H5E_WRITEERROR, "Write failed"}, - {H5E_CLOSEERROR, "Close failed"}, - {H5E_OVERFLOW, "Address overflowed"}, - {H5E_CANTINIT, "Can't initialize interface"}, - {H5E_ALREADYINIT, "Object already initialized"}, - {H5E_BADATOM, "Can't find atom information"}, - {H5E_CANTREGISTER, "Can't register new atom"}, - {H5E_CANTFLUSH, "Can't flush object from cache"}, - {H5E_CANTLOAD, "Can't load object into cache"}, - {H5E_PROTECT, "Protected object error"}, - {H5E_NOTCACHED, "Object not currently cached"}, - {H5E_NOTFOUND, "Object not found"}, - {H5E_EXISTS, "Object already exists"}, - {H5E_CANTENCODE, "Can't encode value"}, - {H5E_CANTDECODE, "Can't decode value"}, - {H5E_CANTSPLIT, "Can't split node"}, - {H5E_CANTINSERT, "Can't insert object"}, - {H5E_CANTLIST, "Can't list node"}, - {H5E_LINKCOUNT, "Bad object header link count"}, - {H5E_VERSION, "Wrong version number"}, - {H5E_ALIGNMENT, "Alignment error"}, - {H5E_BADMESG, "Unrecognized message"}, - {H5E_COMPLEN, "Name component is too long"}, - {H5E_CWG, "Problem with current working group"}, - {H5E_LINK, "Link count failure"}, + {H5E_UNSUPPORTED, "Feature is unsupported"}, + {H5E_BADTYPE, "Inappropriate type"}, + {H5E_BADRANGE, "Out of range"}, + {H5E_BADVALUE, "Bad value"}, + {H5E_NOSPACE, "No space available for allocation"}, + {H5E_FILEEXISTS, "File already exists"}, + {H5E_FILEOPEN, "File already open"}, + {H5E_CANTCREATE, "Unable to create file"}, + {H5E_CANTOPENFILE, "Unable to open file"}, + {H5E_CANTOPENOBJ, "Unable to open object"}, + {H5E_NOTHDF5, "Not an HDF5 file"}, + {H5E_BADFILE, "Bad file ID accessed"}, + {H5E_TRUNCATED, "File has been truncated"}, + {H5E_SEEKERROR, "Seek failed"}, + {H5E_READERROR, "Read failed"}, + {H5E_WRITEERROR, "Write failed"}, + {H5E_CLOSEERROR, "Close failed"}, + {H5E_OVERFLOW, "Address overflowed"}, + {H5E_CANTINIT, "Unable to initialize"}, + {H5E_ALREADYINIT, "Object already initialized"}, + {H5E_BADATOM, "Unable to find atom information (already closed?)"}, + {H5E_CANTREGISTER, "Unable to register new atom"}, + {H5E_CANTFLUSH, "Unable to flush meta data from cache"}, + {H5E_CANTLOAD, "Unable to load meta data into cache"}, + {H5E_PROTECT, "Protected meta data error"}, + {H5E_NOTCACHED, "Meta data not currently cached"}, + {H5E_NOTFOUND, "Object not found"}, + {H5E_EXISTS, "Object already exists"}, + {H5E_CANTENCODE, "Unable to encode value"}, + {H5E_CANTDECODE, "Unable to decode value"}, + {H5E_CANTSPLIT, "Unable to split node"}, + {H5E_CANTINSERT, "Unable to insert object"}, + {H5E_CANTLIST, "Unable to list node"}, + {H5E_LINKCOUNT, "Bad object header link count"}, + {H5E_VERSION, "Wrong version number"}, + {H5E_ALIGNMENT, "Alignment error"}, + {H5E_BADMESG, "Unrecognized message"}, + {H5E_COMPLEN, "Name component is too long"}, + {H5E_CWG, "Problem with current working group"}, + {H5E_LINK, "Link count failure"}, }; /* Interface initialization? */ -static intn interface_initialize_g = FALSE; -#define INTERFACE_INIT H5E_init_interface -static herr_t H5E_init_interface(void); -static void H5E_term_interface(void); - -const hbool_t H5E_clearable_g = TRUE; -hid_t H5E_thrdid_g = FAIL; /* Thread-specific "global" error-handler ID */ - -/*-------------------------------------------------------------------------- -NAME - H5E_init_interface -- Initialize interface-specific information -USAGE - herr_t H5E_init_interface() - -RETURNS - SUCCEED/FAIL -DESCRIPTION - Initializes any interface-specific data or routines. - -Modifications: - Robb Matzke, 4 Aug 1997 - Changed the pablo mask from H5_mask to H5E_mask - ---------------------------------------------------------------------------*/ -static herr_t -H5E_init_interface(void) -{ - herr_t ret_value = SUCCEED; - - FUNC_ENTER(H5E_init_interface, FAIL); - - /* Initialize the atom group for the error stacks */ - if ((ret_value = H5A_init_group(H5_ERR, H5A_ERRSTACK_HASHSIZE, 0, - (herr_t (*)(void *)) H5E_close)) != FAIL) { - ret_value = H5_add_exit(H5E_term_interface); - } - FUNC_LEAVE(ret_value); -} +static intn interface_initialize_g = FALSE; +#define INTERFACE_INIT NULL +const hbool_t H5E_clearable_g = TRUE; /* DO NOT CHANGE */ + +/* + * The error stack. Eventually we'll have some sort of global table so each + * thread has it's own stack. The stacks will be created on demand when the + * thread first calls H5E_push(). + */ +H5E_t H5E_stack_g[1]; +#define H5E_get_my_stack() (H5E_stack_g+0) + +/* + * Automatic error stack traversal occurs if the traversal callback function + * is non null and an API function is about to return an error. These should + * probably be part of the error stack so they're local to a thread. + * + */ +herr_t (*H5E_auto_g)(void*) = (herr_t(*)(void*))H5Eprint; +void *H5E_auto_data_g = stderr; -/*-------------------------------------------------------------------------- - NAME - H5E_term_interface - PURPOSE - Terminate various H5E objects - USAGE - void H5E_term_interface() - RETURNS - SUCCEED/FAIL - DESCRIPTION - Release the atom group and any other resources allocated. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - Can't report errors... - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static void -H5E_term_interface(void) + +/*------------------------------------------------------------------------- + * Function: H5Eset_auto + * + * Purpose: Turns on or off automatic printing of errors. 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. + * + * The default values before this function is called are + * H5Eprint() with client data being the standard error stream, + * stderr. + * + * Automatic stack traversal is always in the H5E_WALK_DOWNWARD + * direction. + * + * See Also: H5Ewalk() + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, February 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5Eset_auto (herr_t (*func)(void*client_data), void *client_data) { - H5A_destroy_group(H5_ERR); + FUNC_ENTER (H5Eset_auto, FAIL); + + H5E_auto_g = func; + H5E_auto_data_g = client_data; + + FUNC_LEAVE (SUCCEED); } -/*-------------------------------------------------------------------------- -NAME - H5Ecreate -- Create a new error stack -USAGE - hid_t H5Ecreate (initial_stack_size); - uintn initial_stack_size; IN: Starting size of the error stack - -RETURNS - The ID of the error stack created on success, FAIL on failure. - -DESCRIPTION - Dynamically creates a new error stack to push error values onto. - ---------------------------------------------------------------------------*/ -hid_t -H5Ecreate(uintn initial_stack_nelmts) + +/*------------------------------------------------------------------------- + * Function: H5Eget_auto + * + * Purpose: Returns the current settings for the automatic error stack + * traversal function and its data. Either (or both) arguments + * may be null in which case the value is not returned. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Saturday, February 28, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5Eget_auto (herr_t (**func)(void*), void **client_data) { - H5E_t *new_stack = NULL; /* Pointer to the new error stack */ - hid_t ret_value = FAIL; - - FUNC_ENTER(H5Ecreate, FAIL); - - /* Check args */ - initial_stack_nelmts = MAX(10, MIN(initial_stack_nelmts, 1000)); + FUNC_ENTER (H5Eget_auto, FAIL); - /* Allocate the stack header */ - new_stack = H5MM_xmalloc(sizeof(H5E_t)); + if (func) *func = H5E_auto_g; + if (client_data) *client_data = H5E_auto_data_g; - /* Initialize the stack header */ - new_stack->nelmts = initial_stack_nelmts; - new_stack->top = 0; - new_stack->stack = H5MM_xcalloc(initial_stack_nelmts, sizeof(H5E_error_t)); - new_stack->push = H5E_push; /* Set the default error handler */ - - /* Get an atom for the error stack */ - if ((ret_value = H5A_register(H5_ERR, new_stack)) < 0) { - HRETURN_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, - "unable to register error stack"); - } - FUNC_LEAVE(ret_value); + FUNC_LEAVE (SUCCEED); } -/*-------------------------------------------------------------------------- -NAME - H5Eclose -- Destroy an error stack -USAGE - herr_t H5Eclose (err_stack); - hid_t err_stack; IN: Error stack to delete - -RETURNS - SUCCEED/FAIL -DESCRIPTION - Destroys an error stack, releasing memory allocated, etc. - ---------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------- + * Function: H5Eclear + * + * Purpose: Clears the error stack for the current thread. + * + * Return: Success: SUCCEED + * + * Failure: FAIL. This function can fail if there are + * problems initializing the library. + * + * Programmer: Robb Matzke + * Friday, February 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ herr_t -H5Eclose(hid_t estack_id) +H5Eclear (void) { - FUNC_ENTER(H5Eclose, FAIL); - - /* check args */ - if (H5_ERR != H5A_group(estack_id)) { - HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an error stack"); - } - /* - * Decrement the reference count. When it reaches zero the error stack - * will be freed. - */ - H5A_dec_ref(estack_id); - - FUNC_LEAVE(SUCCEED); + FUNC_ENTER (H5Eclear, FAIL); + /* FUNC_ENTER() does all the work */ + FUNC_LEAVE (SUCCEED); } + /*------------------------------------------------------------------------- - * Function: H5Epush - * - * Purpose: Pushes a new error record onto error stack ESTACK_ID. The - * error has major and minor numbers MAJ_NUM and MIN_NUM, the - * name of a function where the error was detected, the name of - * the file where the error was detected, and the line within - * that file. An error description string is also passed to - * this function. + * Function: H5Eprint * - * The FUNCTION_NAME is copied (and possibly truncated) into a - * fixed length character buffer; the FILE_NAME is pointed to - * without copying it (we assume it's statically allocated from - * __FILE__); and the DESC argument is strdup'd. + * Purpose: Prints the error stack in some default way. This is just a + * convenience function for H5Ewalk() with a function that + * prints error messages. Users are encouraged to write there + * own more specific error handlers. * - * It is safe to call this function before the thread global - * error stack is initialized. + * Return: Success: SUCCEED * - * Return: Success: SUCCEED + * Failure: FAIL * - * Failure: FAIL - * - * Programmer: Robb Matzke - * Friday, December 12, 1997 + * Programmer: Robb Matzke + * Friday, February 27, 1998 * * Modifications: * *------------------------------------------------------------------------- */ herr_t -H5Epush(hid_t estack_id, H5E_major_t maj_num, H5E_minor_t min_num, - const char *function_name, const char *file_name, intn line, - const char *desc) +H5Eprint (FILE *stream) { - - H5E_t *estack = NULL; /* Ptr to the stack to put value on */ - - /* - * WARNING WARNING WARNING: We cannot call HERROR() from within this - * function if ESTACK_ID is the thread global error stack or else we may - * enter infinite recursion. Furthermore, we also cannot call any other - * HDF5 macro or function which might call HERROR(). HERROR() is called - * by HRETURN_ERROR() which could be called by FUNC_ENTER(). - */ - - /* - * Clear the thread global error stack only if it isn't the error stack on - * which we're pushing the new error. - */ - if (estack_id != H5E_thrdid_g) - H5ECLEAR; - - /* - * check args, but don't call error functions if ESTACK_ID is the thread - * global error handler. - */ - if (H5_ERR != H5A_group(estack_id) || - NULL == (estack = H5A_object(estack_id))) { - HRETURN(FAIL); - } - if (!function_name || !file_name || !desc) { - HRETURN(FAIL); - } - if (!estack->push) { - HRETURN(FAIL); - } - /* Push the new error. It must be safe to call the push function. */ - if ((estack->push) (estack, maj_num, min_num, function_name, file_name, - line, desc) < 0) { - HRETURN(FAIL); - } - return SUCCEED; /*don't use FUNC_LEAVE() here */ + H5E_t *estack = H5E_get_my_stack (); + hbool_t H5E_clearable_g = FALSE; /*override global*/ + herr_t status = FAIL; + + FUNC_ENTER (H5Eprint, FAIL); + + if (!stream) stream = stderr; + fprintf (stream, "HDF5-DIAG: Error detected in thread 0."); + if (estack && estack->nused>0) fprintf (stream, " Back trace follows."); + fputc ('\n', stream); + status = H5E_walk (H5E_WALK_DOWNWARD, H5Ewalk_cb, (void*)stream); + + FUNC_LEAVE (status); } -/*-------------------------------------------------------------------------- -NAME - H5Eclear -- Clear an error stack for later error entries -USAGE - void H5Eclear(int32 err_hand) - int32 err_hand; IN: The ID of the error stack to push the error onto. - -RETURNS - SUCCEED/FAIL -DESCRIPTION - Clear an error stack to allow errors to be pushed onto it. - ---------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------- + * Function: H5Ewalk + * + * Purpose: Walks the error stack for the current thread and calls some + * function for each error along the way. + * + * Return: Success: SUCCEED + * + * Failure: FAIL. This function can fail if there are + * problems initializing the library. + * + * Programmer: Robb Matzke + * Friday, February 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ herr_t -H5Eclear(hid_t estack_id) +H5Ewalk (H5E_direction_t direction, H5E_walk_t func, void *client_data) { - H5E_t *estack = NULL; - hbool_t H5E_clearable_g = FALSE; /*override global*/ - - FUNC_ENTER(H5Eclear, FAIL); - - /* - * Normally we would clear the thread error stack since we're entering an - * API function, but we have to be careful here to not get into an - * infinite recursion. - */ - if (estack_id != H5E_thrdid_g) - H5ECLEAR; + hbool_t H5E_clearable_g = FALSE; /*override global*/ + herr_t status = FAIL; - /* check args */ - if (H5_ERR != H5A_group(estack_id) || - NULL == (estack = H5A_object(estack_id))) { - HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an error stack"); - } - if (H5E_clear(estack) < 0) { - HRETURN_ERROR(H5E_INTERNAL, H5E_CANTINIT, FAIL, - "unable to clear error stack"); - } - FUNC_LEAVE(SUCCEED); + FUNC_ENTER (H5Ewalk, FAIL); + status = H5E_walk (direction, func, client_data); + FUNC_LEAVE (status); } + /*------------------------------------------------------------------------- - * Function: H5Eprint + * Function: H5Ewalk_cb * - * Purpose: Prints the current contents of error stack ESTACK_ID to the - * stream FILE. + * Purpose: This is a default error stack traversal callback function + * that prints error messages to the specified output stream. + * It is not meant to be called directly but rather as an + * argument to the H5Ewalk() function. This function is called + * also by H5Eprint(). Application writers are encouraged to + * use this function as a model for their own error stack + * walking functions. * - * Return: Success: SUCCEED + * N is a counter for how many times this function has been + * called for this particular traversal of the stack. It always + * begins at zero for the first error on the stack (either the + * top or bottom error, or even both, depending on the traversal + * direction and the size of the stack). * - * Failure: FAIL + * ERR_DESC is an error description. It contains all the + * information about a particular error. * - * Programmer: Robb Matzke - * Friday, December 12, 1997 + * CLIENT_DATA is the same pointer that was passed as the + * CLIENT_DATA argument of H5Ewalk(). It is expected to be a + * file pointer (or stderr if null). + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, December 12, 1997 * * Modifications: * *------------------------------------------------------------------------- */ herr_t -H5Eprint(hid_t estack_id, FILE * file) +H5Ewalk_cb(int n, H5E_error_t *err_desc, void *client_data) { - H5E_t *estack = NULL; - hbool_t H5E_clearable_g = FALSE; /*override global*/ + FILE *stream = (FILE *)client_data; + const char *maj_str = NULL; + const char *min_str = NULL; + const int indent = 2; + + /* Check arguments */ + assert (err_desc); + if (!client_data) client_data = stderr; + + /* Get descriptions for the major and minor error numbers */ + maj_str = H5Eget_major (err_desc->maj_num); + min_str = H5Eget_minor (err_desc->min_num); + + /* Print error message */ + fprintf (stream, "%*s#%03d: %s line %u in %s(): %s\n", + indent, "", n, err_desc->file_name, err_desc->line, + err_desc->func_name, err_desc->desc); + fprintf (stream, "%*smajor(%02d): %s\n", + indent*2, "", err_desc->maj_num, maj_str); + fprintf (stream, "%*sminor(%02d): %s\n", + indent*2, "", err_desc->min_num, min_str); + + return SUCCEED; +} - FUNC_ENTER(H5Eprint, FAIL); + +/*------------------------------------------------------------------------- + * Function: H5Eget_major + * + * Purpose: Given a major error number return a constant character string + * that describes the error. + * + * Return: Success: Ptr to a character string. + * + * Failure: Ptr to "Invalid major error number" + * + * Programmer: Robb Matzke + * Friday, February 27, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +const char * +H5Eget_major (H5E_major_t n) +{ + int i; + /* - * Don't clear the thread error stack if it's the one we're about to - * print. + * WARNING: Do not call the FUNC_ENTER() or FUNC_LEAVE() macros since + * they might interact badly with the error stack. We are + * probably calling this function during an error stack + * traversal and adding/removing entries as the result of an + * error would most likely mess things up. */ - if (estack_id != H5E_thrdid_g) - H5ECLEAR; - - /* check args */ - if (H5_ERR != H5A_group(estack_id) || - NULL == (estack = H5A_object(estack_id))) { - HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an error stack"); + for (i=0; i<NELMTS (H5E_major_mesg_g); i++) { + if (H5E_major_mesg_g[i].error_code==n) { + return H5E_major_mesg_g[i].str; + } } - if (!file) - file = stderr; - /* print it */ - if (H5E_print(estack, file) < 0) { - HRETURN_ERROR(H5E_INTERNAL, H5E_CANTINIT, FAIL, - "can't print error stack"); - } - FUNC_LEAVE(SUCCEED); + return "Invalid major error number"; } + /*------------------------------------------------------------------------- - * Function: H5E_close + * Function: H5Eget_minor * - * Purpose: Frees resources associated with an error stack. + * Purpose: Given a minor error number return a constant character string + * that describes the error. * - * Return: Success: SUCCEED + * Return: Success: Ptr to a character string. * - * Failure: FAIL + * Failure: Ptr to "Invalid minor error number" * - * Programmer: Robb Matzke - * Friday, December 12, 1997 + * Programmer: Robb Matzke + * Friday, February 27, 1998 * * Modifications: * *------------------------------------------------------------------------- */ -herr_t -H5E_close(H5E_t *estack) +const char * +H5Eget_minor (H5E_minor_t n) { - FUNC_ENTER(H5E_close, FAIL); - - /* check args */ - assert(estack); - - /* clear error stack, then free it */ - H5E_clear(estack); - H5MM_xfree(estack->stack); - H5MM_xfree(estack); + int i; + + /* + * WARNING: Do not call the FUNC_ENTER() or FUNC_LEAVE() macros since + * they might interact badly with the error stack. We are + * probably calling this function during an error stack + * traversal and adding/removing entries as the result of an + * error would most likely mess things up. + */ + for (i=0; i<NELMTS (H5E_minor_mesg_g); i++) { + if (H5E_minor_mesg_g[i].error_code==n) { + return H5E_minor_mesg_g[i].str; + } + } - FUNC_LEAVE(SUCCEED); + return "Invalid minor error number"; } + /*------------------------------------------------------------------------- - * Function: H5E_clear + * Function: H5E_push * - * Purpose: Clears an error stack but does not release the stack. + * Purpose: Pushes a new error record onto error stack for the current + * thread. The error has major and minor numbers MAJ_NUM and + * MIN_NUM, the name of a function where the error was detected, + * the name of the file where the error was detected, the + * line within that file, and an error description string. The + * function name, file name, and error description strings must + * be statically allocated (the FUNC_ENTER() macro takes care of + * the function name and file name automatically, but the + * programmer is responsible for the description string). * - * Return: Success: SUCCEED + * Return: Success: SUCCEED * - * Failure: FAIL + * Failure: FAIL * - * Programmer: Robb Matzke - * Friday, December 12, 1997 + * Programmer: Robb Matzke + * Friday, December 12, 1997 * * Modifications: * *------------------------------------------------------------------------- */ herr_t -H5E_clear(H5E_t *estack) +H5E_push(H5E_major_t maj_num, H5E_minor_t min_num, const char *function_name, + const char *file_name, unsigned line, const char *desc) { - int i; - - FUNC_ENTER(H5E_clear, FAIL); + H5E_t *estack = H5E_get_my_stack (); + + /* + * WARNING: We cannot call HERROR() from within this function or else we + * could enter infinite recursion. Furthermore, we also cannot + * call any other HDF5 macro or function which might call + * HERROR(). HERROR() is called by HRETURN_ERROR() which could + * be called by FUNC_ENTER(). + */ - /* check args */ - assert(estack); + /* + * Don't fail if arguments are bad. Instead, substitute some default + * value. + */ + if (!function_name) function_name = "Unknown_Function"; + if (!file_name) file_name = "Unknown_File"; + if (!desc) desc = "No description given"; - /* Clear the error descriptions and reset the stack top */ - for (i = 0; i < estack->top; i++) { - H5MM_xfree(estack->stack[i].desc); - estack->stack[i].desc = NULL; + /* + * Push the error if there's room. Otherwise just forget it. + */ + assert (estack); + if (estack->nused<H5E_NSLOTS) { + estack->slot[estack->nused].maj_num = maj_num; + estack->slot[estack->nused].min_num = min_num; + estack->slot[estack->nused].func_name = function_name; + estack->slot[estack->nused].file_name = file_name; + estack->slot[estack->nused].line = line; + estack->slot[estack->nused].desc = desc; + estack->nused++; } - estack->top = 0; - - FUNC_LEAVE(SUCCEED); + + return SUCCEED; /*don't use FUNC_LEAVE() here */ } + /*------------------------------------------------------------------------- - * Function: H5E_push - * - * Purpose: Push an error onto an error stack. The FUNCTION_NAME is - * copied (and possibly truncated) into the error record. The - * FILE_NAME pointer is used directly since we assume it came - * from the __FILE__ construct and is thus static data. The - * description, DESC, is strdup'd into the error record. + * Function: H5E_clear * - * Note: Warning: to prevent infinite recursivion this function must - * not call any other HDF5 function and especially not - * the HDF5 error handling macros. + * Purpose: Clears the error stack for the current thread. * - * Return: Success: SUCCEED + * Return: Success: SUCCEED * - * Failure: FAIL + * Failure: FAIL. This function can fail if there are + * problems initializing the library. * - * Programmer: Robb Matzke - * Friday, December 12, 1997 + * Programmer: Robb Matzke + * Friday, February 27, 1998 * * Modifications: * *------------------------------------------------------------------------- */ herr_t -H5E_push(H5E_t *estack, H5E_major_t maj_num, H5E_minor_t min_num, - const char *function_name, const char *file_name, intn line, - const char *desc) +H5E_clear(void) { + H5E_t *estack = H5E_get_my_stack (); - /* FUNC_ENTER (H5E_push, FAIL); -- can't do this here! */ - - /* check args */ - assert(estack); - assert(function_name); - assert(file_name); - - /* Check if we need to expand the stack */ - if (estack->top >= estack->nelmts) { - /* - * Ask for new stack that's twice as large. Do not use hdf5 functions - * to allocate the memory! - */ - estack->nelmts *= 2; - estack->stack = realloc(estack->stack, - estack->nelmts * sizeof(H5E_error_t)); - assert(estack->stack); - } - /* Push the error onto the error stack */ - estack->stack[estack->top].maj_num = maj_num; - estack->stack[estack->top].min_num = min_num; - HDstrncpy(estack->stack[estack->top].func_name, function_name, - MAX_FUNC_NAME); - estack->stack[estack->top].func_name[MAX_FUNC_NAME - 1] = '\0'; - estack->stack[estack->top].file_name = file_name; - estack->stack[estack->top].line = line; - - /* strdup the description but don't use H5MM_xstrdup() */ - estack->stack[estack->top].desc = malloc(strlen(desc) + 1); - assert(estack->stack[estack->top].desc); - strcpy(estack->stack[estack->top].desc, desc); - - /* Increment the top of the error stack */ - estack->top++; - - return SUCCEED; /*don't use FUNC_LEAVE() here */ + FUNC_ENTER(H5E_clear, FAIL); + if (estack) estack->nused = 0; + FUNC_LEAVE(SUCCEED); } + /*------------------------------------------------------------------------- - * Function: H5E_print + * Function: H5E_walk + * + * Purpose: Walks the error stack, calling the specified function for + * each error on the stack. The DIRECTION argument determines + * whether the stack is walked from the inside out or the + * outside in. The value H5E_WALK_UPWARD means begin with the + * most specific error and end at the API; H5E_WALK_DOWNWARD + * means to start at the API and end at the inner-most function + * where the error was first detected. * - * Purpose: Prints an error stack ESTACK to the stream FILE. + * The function pointed to by FUNC will be called for each error + * in the error stack. It's arguments will include an index + * number (beginning at zero regardless of stack traversal + * direction), an error stack entry, and the CLIENT_DATA pointer + * passed to H5E_print. * - * Return: Success: SUCCEED + * Return: Success: SUCCEED * - * Failure: FAIL + * Failure: FAIL. This function can fail if there are + * problems initializing the library. * - * Programmer: Robb Matzke - * Friday, December 12, 1997 + * Programmer: Robb Matzke + * Friday, December 12, 1997 * * Modifications: * *------------------------------------------------------------------------- */ herr_t -H5E_print(H5E_t *estack, FILE * file) +H5E_walk (H5E_direction_t direction, H5E_walk_t func, void *client_data) { - intn i, j; - const char *maj_str = NULL; - const char *min_str = NULL; - - FUNC_ENTER(H5E_print, FAIL); - - /* check args */ - assert(estack); - assert(file); - - if (0 == estack->top) - HRETURN(SUCCEED); - - fprintf(file, "HDF5-DIAG: error stack:\n"); - for (i = 0; i < estack->top; i++) { - - /* Find major and minor error strings */ - for (j = 0, maj_str = "??"; j < NELMTS(H5E_major_mesg_g); j++) { - if (H5E_major_mesg_g[j].error_code == estack->stack[i].maj_num) { - maj_str = H5E_major_mesg_g[j].str; - break; - } - } - for (j = 0, min_str = "??"; j < NELMTS(H5E_minor_mesg_g); j++) { - if (H5E_minor_mesg_g[j].error_code == estack->stack[i].min_num) { - min_str = H5E_minor_mesg_g[j].str; - break; - } - } - - /* Print error message */ - fprintf(file, " #%03d: %s:%d in %s() error %02d/%02d: %s\n", - i, estack->stack[i].file_name, estack->stack[i].line, - estack->stack[i].func_name, estack->stack[i].maj_num, - estack->stack[i].min_num, estack->stack[i].desc); - fprintf(file, " %s (%s)\n", maj_str, min_str); + H5E_t *estack = H5E_get_my_stack (); + int i; + herr_t status; + + FUNC_ENTER(H5E_walk, FAIL); + + /* check args, but rather than failing use some default value */ + if (direction!=H5E_WALK_UPWARD && direction!=H5E_WALK_DOWNWARD) { + direction = H5E_WALK_UPWARD; } + /* walk the stack */ + assert (estack); + if (func && H5E_WALK_UPWARD==direction) { + for (i=0, status=SUCCEED; i<estack->nused && status>=0; i++) { + status = (func)(i, estack->slot+i, client_data); + } + } else if (func && H5E_WALK_DOWNWARD==direction) { + for (i=estack->nused-1, status=SUCCEED; i>=0 && status>=0; --i) { + status = (func)(estack->nused-(i+1), estack->slot+i, client_data); + } + } + FUNC_LEAVE(SUCCEED); } + diff --git a/src/H5Eprivate.h b/src/H5Eprivate.h index 8b59828..885ad44 100644 --- a/src/H5Eprivate.h +++ b/src/H5Eprivate.h @@ -1,13 +1,13 @@ /**************************************************************************** - * NCSA HDF * - * Software Development Group * - * National Center for Supercomputing Applications * - * University of Illinois at Urbana-Champaign * - * 605 E. Springfield, Champaign IL 61820 * - * * - * For conditions of distribution and use, see the accompanying * - * hdf/COPYING file. * - * * + * NCSA HDF * + * Software Development Group * + * National Center for Supercomputing Applications * + * University of Illinois at Urbana-Champaign * + * 605 E. Springfield, Champaign IL 61820 * + * * + * For conditions of distribution and use, see the accompanying * + * hdf/COPYING file. * + * * ****************************************************************************/ /* @@ -21,113 +21,94 @@ /* Private headers needed by this file */ #include <H5private.h> -/* - ====================================================================== - Error codes +#define H5E_NSLOTS 32 /*number of slots in an error stack */ - NOTE: Remember to update the error_messages[] structure later in this file - whenever errors are added/deleted from this list. - ====================================================================== +/* + * HERROR macro, used to facilitate error reporting between a FUNC_ENTER() + * and a FUNC_LEAVE() within a function body. The arguments are the major + * error number, the minor error number, and a description of the error. */ +#define HERROR(maj, min, str) H5E_push(maj, min, FUNC, __FILE__, __LINE__, str) -/* HERROR macro, used to facilitate error reporting. Assumes that - there's a variable called FUNC which holds the function name. - Assume that func and file are both stored in static space, or at - least be not corrupted in the meanwhile. */ -#define HERROR(maj, min, str) H5Epush (H5E_thrdid_g, maj, min, \ - FUNC, __FILE__, __LINE__, str) - -/* HRETURN_ERROR macro, used to facilitate error reporting. Makes - same assumptions as HERROR. IN ADDITION, this macro causes - a return from the calling routine */ -#define HRETURN_ERROR(maj, min, ret_val, str) { \ - HERROR (maj, min, str); \ - PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \ - return (ret_val); \ +/* + * HRETURN_ERROR macro, used to facilitate error reporting between a + * FUNC_ENTER() and a FUNC_LEAVE() within a function body. The arguments are + * the major error number, the minor error number, a return value, and a + * description of the error. + */ +#define HRETURN_ERROR(maj, min, ret_val, str) { \ + HERROR (maj, min, str); \ + if (H5_IS_API(FUNC) && H5E_auto_g) { \ + (H5E_auto_g)(H5E_auto_data_g); \ + } \ + PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \ + return (ret_val); \ } -/* HRETURN macro, similar to HRETURN_ERROR() except for success */ -#define HRETURN(ret_val) { \ - PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \ - return (ret_val); \ +/* + * HRETURN macro, used to facilitate returning from a function between a + * FUNC_ENTER() and a FUNC_LEAVE() within a function body. The argument is + * the return value. + */ +#define HRETURN(ret_val) { \ + PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \ + return (ret_val); \ } -/* HGOTO_ERROR macro, used to facilitate error reporting. Makes - same assumptions as HERROR. IN ADDITION, this macro causes - a jump to the label 'done' which should be in every fucntion - Also there is an assumption of a variable 'ret_value' */ -#define HGOTO_ERROR(maj, min, ret_val, str) { \ - HERROR (maj, min, str); \ - ret_value = ret_val; \ - goto done; \ +/* + * HGOTO_ERROR macro, used to facilitate error reporting between a + * FUNC_ENTER() and a FUNC_LEAVE() within a function body. The arguments are + * the major error number, the minor error number, the return value, and an + * error string. The return value is assigned to a variable `ret_value' and + * control branches to the `done' label. + */ +#define HGOTO_ERROR(maj, min, ret_val, str) { \ + HERROR (maj, min, str); \ + if (H5_IS_API(FUNC) && H5E_auto_g) { \ + (H5E_auto_g)(H5E_auto_data_g); \ + } \ + ret_value = ret_val; \ + goto done; \ } -/* HGOTO_DONE macro, used to facilitate the new error reporting model. - This macro is just a wrapper to set the return value and jump to the 'done' - label. Also assumption of a variable 'ret_value' */ +/* + * HGOTO_DONE macro, used to facilitate normal return between a FUNC_ENTER() + * and a FUNC_LEAVE() within a function body. The argument is the return + * value which is assigned to the `ret_value' variable. Control branches to + * the `done' label. + */ #define HGOTO_DONE(ret_val) {ret_value = ret_val; goto done;} -/* H5ECLEAR macro, used to facilitate the new error reporting model. - This macro is just a wrapper to clear the error stack with the thread - error ID */ -#define H5ECLEAR H5Eclear(H5E_thrdid_g) - -/* Maximum length of function name to push onto error stack */ -#define MAX_FUNC_NAME 32 - /* - * error_messages is the list of error messages in the system, kept as - * error_code-message pairs. + * The list of error messages in the system is kept as an array of + * error_code/message pairs, one for major error numbers and another for + * minor error numbers. */ typedef struct H5E_major_mesg_t { H5E_major_t error_code; - const char *str; + const char *str; } H5E_major_mesg_t; typedef struct H5E_minor_mesg_t { H5E_minor_t error_code; - const char *str; + const char *str; } H5E_minor_mesg_t; -/* Function pointer to report errors through */ -struct H5E_t; /*forward decl */ -typedef herr_t (*H5E_push_t)(struct H5E_t *estack, H5E_major_t maj_num, - H5E_minor_t min_num, const char *function_name, - const char *file_name, intn line, - const char *desc); - -/* - * We use a stack to hold the errors plus we keep track of the function, file - * and line where the error occurs. - */ - -/* the structure of the error stack element */ -typedef struct H5E_error_t { - H5E_major_t maj_num; /*major error number */ - H5E_minor_t min_num; /*minor error number */ - char func_name[MAX_FUNC_NAME]; /*function where error occur */ - const char *file_name; /*file where error occur */ - intn line; /*line in file where error occurs */ - char *desc; /*optional supplied description */ -} H5E_error_t; - -/* Structure to store error information for a thread */ +/* An error stack */ typedef struct H5E_t { - uintn nelmts; /*num elements allocated in the stack */ - uintn top; /*index of the next open stack element */ - H5E_error_t *stack; /*pointer to the error stack */ - H5E_push_t push; /*func that pushes new error on stack */ + uintn nused; /*num slots currently used in stack */ + H5E_error_t slot[H5E_NSLOTS]; /*array of error records */ } H5E_t; -/* Private global variables in H5E.c */ -extern hid_t H5E_thrdid_g; /* Thread-specific "global" error-handler ID */ -extern hbool_t install_atexit; /* Whether to install the atexit routine */ -extern const hbool_t H5E_clearable_g; /* Safe to call H5Eclear() on enter?*/ - -herr_t H5E_close (H5E_t *estack); -herr_t H5E_clear (H5E_t *estack); -herr_t H5E_print (H5E_t *estack, FILE * file); -herr_t H5E_push (H5E_t *estack, H5E_major_t maj_num, H5E_minor_t min_num, - const char *function_name, const char *file_name, intn line, - const char *desc); +extern const hbool_t H5E_clearable_g; /*safe to call H5E_clear() on enter? */ +extern herr_t (*H5E_auto_g)(void *client_data); +extern void *H5E_auto_data_g; + +herr_t H5E_push (H5E_major_t maj_num, H5E_minor_t min_num, + const char *func_name, const char *file_name, unsigned line, + const char *desc); +herr_t H5E_clear (void); +herr_t H5E_walk (H5E_direction_t dir, H5E_walk_t func, void *client_data); + + #endif diff --git a/src/H5Epublic.h b/src/H5Epublic.h index c71bd3a..2ceb9a3 100644 --- a/src/H5Epublic.h +++ b/src/H5Epublic.h @@ -79,7 +79,7 @@ typedef enum H5E_minor_t { H5E_OVERFLOW, /*address overflowed */ /* Function entry/exit interface errors */ - H5E_CANTINIT, /*Can't initialize interface */ + H5E_CANTINIT, /*Can't initialize */ H5E_ALREADYINIT, /*object already initialized */ /* Object atom related errors */ @@ -114,17 +114,37 @@ typedef enum H5E_minor_t { H5E_LINK /*link count failure */ } H5E_minor_t; +/* Information about an error */ +typedef struct H5E_error_t { + H5E_major_t maj_num; /*major error number */ + H5E_minor_t min_num; /*minor error number */ + const char *func_name; /*function in which error occurred */ + const char *file_name; /*file in which error occurred */ + unsigned line; /*line in file where error occurs */ + const char *desc; /*optional supplied description */ +} H5E_error_t; + +/* Error stack traversal direction */ +typedef enum H5E_direction_t { + H5E_WALK_UPWARD = 0, /*begin deep, end at API function */ + H5E_WALK_DOWNWARD = 1 /*begin at API function, end deep */ +} H5E_direction_t; + +/* Error stack traversal callback function */ +typedef herr_t (*H5E_walk_t)(int n, H5E_error_t *err_desc, void *client_data); + #ifdef __cplusplus extern "C" { #endif -hid_t H5Ecreate (uintn initial_stack_nelmts); -herr_t H5Eclose (hid_t estack_id); -herr_t H5Epush (hid_t estack_id, H5E_major_t maj_num, H5E_minor_t min_num, - const char *function_name, const char *file_name, intn line, - const char *desc); -herr_t H5Eclear (hid_t estack_id); -herr_t H5Eprint (hid_t estack_id, FILE * file); +herr_t H5Eset_auto (herr_t (*func)(void*client_data), void *client_data); +herr_t H5Eget_auto (herr_t (**func)(void*client_data), void **client_data); +herr_t H5Eclear (void); +herr_t H5Eprint (FILE *stream); +herr_t H5Ewalk (H5E_direction_t direction, H5E_walk_t func, void *client_data); +herr_t H5Ewalk_cb (int n, H5E_error_t *err_desc, void *client_data); +const char *H5Eget_major (H5E_major_t major_number); +const char *H5Eget_minor (H5E_minor_t minor_number); #ifdef __cplusplus } @@ -710,7 +710,7 @@ H5G_mkroot(H5F_t *f, size_t size_hint) * but the old root object is no longer the root object. */ H5O_remove(f->shared->root_ent, H5O_NAME, H5O_ALL); - H5ECLEAR; /*who really cares? */ + H5E_clear(); /*who really cares? */ *(f->shared->root_ent) = new_root; @@ -777,13 +777,13 @@ H5G_create(H5F_t *f, const char *name, size_t size_hint) if ((status = H5G_mkroot(f, H5G_SIZE_HINT)) < 0 && -2 != status) { HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, NULL, "can't create root group"); } - H5ECLEAR; + H5E_clear(); /* lookup name */ if (0 == H5G_namei(f, NULL, name, &rest, &grp_ent, NULL)) { HRETURN_ERROR(H5E_SYM, H5E_EXISTS, NULL, "already exists"); } - H5ECLEAR; /*it's OK that we didn't find it */ + H5E_clear(); /*it's OK that we didn't find it */ assert(H5F_addr_defined(&(grp_ent.header))); /* should be one null-terminated component left */ @@ -1155,7 +1155,7 @@ H5G_insert(const char *name, H5G_entry_t *ent) if (H5G_namei(ent->file, NULL, name, &rest, &grp, NULL) >= 0) { HRETURN_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "already exists"); } - H5ECLEAR; /*it's OK that we didn't find it */ + H5E_clear(); /*it's OK that we didn't find it */ rest = H5G_component(rest, &nchars); if (!rest || !*rest) { @@ -1217,7 +1217,7 @@ H5G_insert(const char *name, H5G_entry_t *ent) if ((status = H5G_mkroot(ent->file, H5G_SIZE_HINT)) < 0 && -2 != status) { HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create root group"); } - H5ECLEAR; + H5E_clear(); if (update_grp==TRUE) grp = *(ent->file->shared->root_ent); diff --git a/src/H5Gnode.c b/src/H5Gnode.c index d309d97..390ea7d 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -957,7 +957,7 @@ H5G_node_debug(H5F_t *f, const haddr_t *addr, FILE * stream, intn indent, * B-tree node. */ if (NULL == (sn = H5AC_protect(f, H5AC_SNODE, addr, NULL, NULL))) { - H5ECLEAR; /*discard that error */ + H5E_clear(); /*discard that error */ status = H5B_debug(f, addr, stream, indent, fwidth, H5B_SNODE, NULL); if (status < 0) { HRETURN_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, @@ -310,7 +310,7 @@ H5H_flush(H5F_t *f, hbool_t destroy, const haddr_t *addr, H5H_t *heap) } heap->addr = new_addr; H5MF_free(f, &old_addr, heap->disk_alloc); - H5ECLEAR; /*don't really care if the free failed */ + H5E_clear(); /*don't really care if the free failed */ heap->disk_alloc = heap->mem_alloc; } @@ -755,7 +755,7 @@ H5O_read(H5G_entry_t *ent, const H5O_class_t *type, intn sequence, void *mesg) retval = (H5O_fast_g[cache_type]) (cache, type, mesg); if (retval) HRETURN(retval); - H5ECLEAR; /*don't care, try reading from header */ + H5E_clear(); /*don't care, try reading from header */ } /* can we get it from the object header? */ @@ -1393,7 +1393,7 @@ H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_class_t *type, size_t size) if ((idx = H5O_alloc_extend_chunk(oh, chunkno, size)) >= 0) { break; } - H5ECLEAR; + H5E_clear(); } /* @@ -289,7 +289,7 @@ H5T_term_interface(void) fprintf (stderr, "HDF5-DIAG: conversion function failed " "to free private data\n"); #endif - H5ECLEAR; /*ignore the error*/ + H5E_clear(); /*ignore the error*/ } } } @@ -2221,7 +2221,7 @@ H5Tregister_soft(H5T_class_t src_cls, H5T_class_t dst_cls, H5T_conv_t func) fprintf (stderr, "HDF5-DIAG: conversion function failed " "to free private data.\n"); #endif - H5ECLEAR; + H5E_clear(); } } path->func = func; @@ -2231,7 +2231,7 @@ H5Tregister_soft(H5T_class_t src_cls, H5T_class_t dst_cls, H5T_conv_t func) /* Release temporary atoms */ H5A_dec_ref(src_id); H5A_dec_ref(dst_id); - H5ECLEAR; + H5E_clear(); } FUNC_LEAVE(SUCCEED); @@ -2293,7 +2293,7 @@ H5Tunregister(H5T_conv_t func) fprintf (stderr, "HDF5-DIAG: conversion function failed to " "free private data.\n"); #endif - H5ECLEAR; + H5E_clear(); } HDmemset (&(path->cdata), 0, sizeof(H5T_cdata_t)); @@ -2324,7 +2324,7 @@ H5Tunregister(H5T_conv_t func) 0, NULL, NULL) >= 0) { path->func = H5T_soft_g[j].func; } else { - H5ECLEAR; + H5E_clear(); HDmemset (&(path->cdata), 0, sizeof(H5T_cdata_t)); } H5A_dec_ref(src_id); @@ -3157,7 +3157,7 @@ H5T_path_find(const H5T_t *src, const H5T_t *dst, hbool_t create, fprintf (stderr, "HDF5-DIAG: conversion function init " "failed\n"); #endif - H5ECLEAR; /*ignore the failure*/ + H5E_clear(); /*ignore the failure*/ } H5A_dec_ref(src_id); H5A_dec_ref(dst_id); @@ -3179,7 +3179,7 @@ H5T_path_find(const H5T_t *src, const H5T_t *dst, hbool_t create, if ((H5T_soft_g[i].func) (src_id, dst_id, &(path->cdata), H5T_CONV_INIT, NULL, NULL) < 0) { HDmemset (&(path->cdata), 0, sizeof(H5T_cdata_t)); - H5ECLEAR; /*ignore the error*/ + H5E_clear(); /*ignore the error*/ } else { path->func = H5T_soft_g[i].func; } diff --git a/src/H5private.h b/src/H5private.h index 1fc944b..49437cc 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -421,11 +421,15 @@ extern char *strdup(const char *s); extern hbool_t library_initialize_g; /*good thing C's lazy about extern! */ extern hbool_t thread_initialize_g; /*don't decl interface_initialize_g */ -#define PRINT(N,S) { \ +/* Print S on file N followed by a newline */ +#define H5_PRINT(N,S) { \ write ((N), (S), strlen((S))); \ write ((N), "\n", 1); \ } +/* Is `S' the name of an API function? */ +#define H5_IS_API(S) ('_'!=S[2] && '_'!=S[3] && (!S[4] || '_'!=S[4])) + #define FUNC_ENTER(func_name,err) FUNC_ENTER_INIT(func_name,INTERFACE_INIT,err) #define FUNC_ENTER_INIT(func_name,interface_init_func,err) { \ @@ -463,10 +467,9 @@ extern hbool_t thread_initialize_g; /*don't decl interface_initialize_g */ } \ \ /* Clear thread error stack entering public functions */ \ - if (H5E_clearable_g && '_'!=FUNC[2] && '_'!=FUNC[3] && \ - (!FUNC[4] || '_'!=FUNC[4])) { \ - PRINT (55, #func_name); \ - H5Eclear (H5E_thrdid_g); \ + if (H5E_clearable_g && H5_IS_API (FUNC)) { \ + H5_PRINT (55, #func_name); \ + H5E_clear (); \ } \ { diff --git a/src/Makefile.in b/src/Makefile.in index c9e4f55..e15b98e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -16,12 +16,12 @@ PROGS=debug # Source and object files for the library (lexicographically)... PARALLEL_SRC=H5Fmpio.c -LIB_SRC=H5.c H5A.c H5AC.c H5B.c H5P.c H5D.c H5E.c H5F.c H5Farray.c H5Fcore.c \ +LIB_SRC=H5.c H5A.c H5AC.c H5B.c H5D.c H5E.c H5F.c H5Farray.c H5Fcore.c \ H5Ffamily.c H5Fistore.c H5Flow.c H5Fsec2.c H5Fsplit.c H5Fstdio.c \ H5G.c H5Gent.c H5Gnode.c H5Gstab.c H5H.c H5M.c H5MF.c H5MM.c H5O.c \ H5Ocont.c H5Odtype.c H5Oefl.c H5Olayout.c H5Oname.c H5Onull.c \ - H5Osdspace.c H5Ostab.c H5S.c H5Ssimp.c H5T.c H5Tconv.c H5Tinit.c \ - H5V.c @PARALLEL_SRC@ + H5Osdspace.c H5Ostab.c H5P.c H5S.c H5Ssimp.c H5T.c H5Tconv.c \ + H5Tinit.c H5V.c @PARALLEL_SRC@ LIB_OBJ=$(LIB_SRC:.c=.o) diff --git a/test/dsets.c b/test/dsets.c index 5d05288..8b373b0 100644 --- a/test/dsets.c +++ b/test/dsets.c @@ -11,11 +11,9 @@ #include <hdf5.h> #include <math.h> #include <stdio.h> +#include <stdlib.h> #include <unistd.h> -#include <H5Eprivate.h> - - #ifndef HAVE_FUNCTION #undef __FUNCTION__ #define __FUNCTION__ "" @@ -83,12 +81,16 @@ test_create(hid_t file) } goto error; } + /* * Try creating a dataset that already exists. This should fail since a - * dataset can only be created once. + * dataset can only be created once. Temporarily turn off error + * reporting. */ + H5Eset_auto (NULL, NULL); dataset = H5Dcreate(file, DSET_DEFAULT_NAME, H5T_NATIVE_DOUBLE, space, H5P_DEFAULT); + H5Eset_auto ((herr_t(*)(void*))H5Eprint, stdout); if (dataset >= 0) { puts("*FAILED*"); if (!isatty(1)) { @@ -97,6 +99,7 @@ test_create(hid_t file) } goto error; } + /* * Open the dataset we created above and then close it. This is how * existing datasets are accessed. @@ -118,11 +121,15 @@ test_create(hid_t file) } goto error; } + /* * Try opening a non-existent dataset. This should fail since new datasets - * cannot be created with this function. + * cannot be created with this function. Temporarily turn off error + * reporting. */ + H5Eset_auto (NULL, NULL); dataset = H5Dopen(file, "does_not_exist"); + H5Eset_auto ((herr_t(*)(void*))H5Eprint, stdout); if (dataset >= 0) { puts("*FAILED*"); if (!isatty(1)) { @@ -312,7 +319,6 @@ test_tconv(hid_t file) /* Write the data to the dataset */ status = H5Dwrite(dataset, H5T_NATIVE_INT32, H5S_ALL, H5S_ALL, H5P_DEFAULT, out); - if (status<0) H5Eprint (H5E_thrdid_g, stdout); assert(status >= 0); /* Create a new type with the opposite byte order */ @@ -374,6 +380,9 @@ main(void) status = H5open (); assert (status>=0); + /* Automatic error reporting to standard output */ + H5Eset_auto ((herr_t(*)(void*))H5Eprint, stdout); + unlink("dataset.h5"); file = H5Fcreate("dataset.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); assert(file >= 0); diff --git a/test/testhdf5.c b/test/testhdf5.c index b122606..40abfb5 100644 --- a/test/testhdf5.c +++ b/test/testhdf5.c @@ -152,6 +152,13 @@ main(int argc, char *argv[]) setbuf(stdout, NULL); #endif + /* + * Turn off automatic error reporting since we do it ourselves. Besides, + * half the functions this test calls are private, so automatic error + * reporting wouldn't do much good since it's triggered at the API layer. + */ + H5Eset_auto (NULL, NULL); + /* Tests are generally arranged from least to most complexity... */ InitTest("metadata", test_metadata, "Encode/decode metadata code"); InitTest("file", test_file, "Low-Level File I/O"); diff --git a/test/testhdf5.h b/test/testhdf5.h index ed9e0a3..0288880 100644 --- a/test/testhdf5.h +++ b/test/testhdf5.h @@ -31,51 +31,77 @@ extern int Verbosity; /* Use %ld to print the value because long should cover most cases. */ /* Used to make certain a return value _is_not_ a value */ -#define CHECK(ret, val, where) \ -do {if (Verbosity>9) print_func(" Call to routine: %15s at line %4d in %s returned %ld \n",where,(int)__LINE__,__FILE__,(long)ret);\ -if(ret == val) {print_func("*** UNEXPECTED RETURN from %s is %ld at line %4d in %s\n", where, (long)ret, (int)__LINE__,__FILE__); num_errs++;H5Eprint (H5E_thrdid_g, stdout);} H5Eclear(H5E_thrdid_g);\ +#define CHECK(ret, val, where) do { \ + if (Verbosity>9) print_func(" Call to routine: %15s at line %4d " \ + "in %s returned %ld \n", \ + where, (int)__LINE__, __FILE__, \ + (long)ret); \ + if (ret == val) { \ + print_func("*** UNEXPECTED RETURN from %s is %ld at line %4d " \ + "in %s\n", where, (long)ret, (int)__LINE__, __FILE__); \ + num_errs++; \ + H5Eprint (stdout); \ + } \ + H5Eclear(); \ } while(0) -#define CHECK_I(ret,where) { \ - if (Verbosity>9) { \ +#define CHECK_I(ret,where) { \ + if (Verbosity>9) { \ print_func(" Call to routine: %15s at line %4d in %s returned %ld\n", \ - (where), (int)__LINE__, __FILE__, (long)(ret)); \ - } \ - if ((ret)<0) { \ + (where), (int)__LINE__, __FILE__, (long)(ret)); \ + } \ + if ((ret)<0) { \ print_func ("*** UNEXPECTED RETURN from %s is %ld line %4d in %s\n", \ - (where), (long)(ret), (int)__LINE__, __FILE__); \ - H5Eprint (H5E_thrdid_g, stdout); \ - num_errs++; \ - } \ - H5Eclear (H5E_thrdid_g); \ + (where), (long)(ret), (int)__LINE__, __FILE__); \ + H5Eprint (stdout); \ + num_errs++; \ + } \ + H5Eclear (); \ } -#define CHECK_PTR(ret,where) { \ - if (Verbosity>9) { \ +#define CHECK_PTR(ret,where) { \ + if (Verbosity>9) { \ print_func(" Call to routine: %15s at line %4d in %s returned %p\n", \ - (where), (int)__LINE__, __FILE__, (ret)); \ - } \ - if (!(ret)) { \ + (where), (int)__LINE__, __FILE__, (ret)); \ + } \ + if (!(ret)) { \ print_func ("*** UNEXPECTED RETURN from %s is NULL line %4d in %s\n", \ - (where), (int)__LINE__, __FILE__); \ - H5Eprint (H5E_thrdid_g, stdout); \ - num_errs++; \ - } \ - H5Eclear (H5E_thrdid_g); \ + (where), (int)__LINE__, __FILE__); \ + H5Eprint (stdout); \ + num_errs++; \ + } \ + H5Eclear (); \ } /* Used to make certain a return value _is_ a value */ -#define VERIFY(x, val, where) \ -do {if (Verbosity>9) print_func(" Call to routine: %15s at line %4d in %s had value %ld \n",where,(int)__LINE__,__FILE__,(long)x);\ -if(x != val) {print_func("*** UNEXPECTED VALUE from %s is %ld at line %4d in %s\n", where, (long)x,(int)__LINE__,__FILE__); H5Eprint (H5E_thrdid_g, stdout);num_errs++;}H5Eclear(H5E_thrdid_g); \ +#define VERIFY(x, val, where) do { \ + if (Verbosity>9) { \ + print_func(" Call to routine: %15s at line %4d in %s had value " \ + "%ld \n", where, (int)__LINE__, __FILE__, (long)x); \ + } \ + if (x != val) { \ + print_func("*** UNEXPECTED VALUE from %s is %ld at line %4d " \ + "in %s\n", where, (long)x, (int)__LINE__, __FILE__); \ + H5Eprint (stdout); \ + num_errs++; \ + } \ + H5Eclear(); \ } while(0) /* Used to document process through a test and to check for errors */ -#define RESULT(ret,func) \ -do { \ -if (Verbosity>8) print_func(" Call to routine: %15s at line %4d in %s returned %ld \n",func,(int)__LINE__,__FILE__,(long)ret); \ -if (Verbosity>9) HEprint(stdout,0); \ -if(ret == FAIL) {print_func("*** UNEXPECTED RETURN from %s is %ld at line %4d in %s\n", func, (long)ret,(int)__LINE__,__FILE__); H5Eprint (H5E_thrdid_g, stdout); num_errs++;} H5Eclear(H5E_thrdid_g);\ +#define RESULT(ret,func) do { \ + if (Verbosity>8) { \ + print_func(" Call to routine: %15s at line %4d in %s returned " \ + "%ld\n", func, (int)__LINE__, __FILE__, (long)ret); \ + } \ + if (Verbosity>9) HEprint(stdout, 0); \ + if (ret == FAIL) { \ + print_func("*** UNEXPECTED RETURN from %s is %ld at line %4d " \ + "in %s\n", func, (long)ret, (int)__LINE__, __FILE__); \ + H5Eprint (stdout); \ + num_errs++; \ + } \ + H5Eclear(); \ } while(0) /* Used to document process through a test */ |