diff options
Diffstat (limited to 'src/H5.c')
| -rw-r--r-- | src/H5.c | 1318 |
1 files changed, 813 insertions, 505 deletions
@@ -1,95 +1,127 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * - * Copyright by the Board of Trustees of the University of Illinois. * * 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 files COPYING and Copyright.html. COPYING can be found at the root * - * of the source code distribution tree; Copyright.html can be found at the * - * root level of an installed copy of the electronic HDF5 document set and * - * is linked from the top-level documents page. It can also be found at * - * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * - * access to either file, you may request a copy from help@hdfgroup.org. * + * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /****************/ /* Module Setup */ /****************/ - +#include "H5module.h" /* This source code file is part of the H5 module */ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5ACprivate.h" /* Metadata cache */ -#include "H5Dprivate.h" /* Datasets */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5FLprivate.h" /* Free lists */ -#include "H5Lprivate.h" /* Links */ -#include "H5MMprivate.h" /* Memory management */ -#include "H5Pprivate.h" /* Property lists */ -#include "H5Tprivate.h" /* Datatypes */ -#include "H5SLprivate.h" /* Skip lists */ - +#include "H5private.h" /* Generic Functions */ +#include "H5ACprivate.h" /* Metadata cache */ +#include "H5CXprivate.h" /* API Contexts */ +#include "H5Dprivate.h" /* Datasets */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free lists */ +#include "H5FSprivate.h" /* File free space */ +#include "H5Lprivate.h" /* Links */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Pprivate.h" /* Property lists */ +#include "H5PLprivate.h" /* Plugins */ +#include "H5SLprivate.h" /* Skip lists */ +#include "H5Tprivate.h" /* Datatypes */ + +#include "H5FDsec2.h" /* for H5FD_sec2_init() */ /****************/ /* Local Macros */ /****************/ - /******************/ /* Local Typedefs */ /******************/ - /********************/ /* Package Typedefs */ /********************/ +/* Node for list of 'atclose' routines to invoke at library shutdown */ +typedef struct H5_atclose_node_t { + H5_atclose_func_t func; /* Function to invoke */ + void *ctx; /* Context to pass to function */ + struct H5_atclose_node_t *next; /* Pointer to next node in list */ +} H5_atclose_node_t; /********************/ /* Local Prototypes */ /********************/ -static void H5_debug_mask(const char*); +static void H5__debug_mask(const char *); #ifdef H5_HAVE_PARALLEL -static int H5_mpi_delete_cb(MPI_Comm comm, int keyval, void *attr_val, int *flag); +static int H5__mpi_delete_cb(MPI_Comm comm, int keyval, void *attr_val, int *flag); #endif /*H5_HAVE_PARALLEL*/ /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ -/* HDF5 API Entered variable */ -/* (move to H5.c when new FUNC_ENTER macros in actual use -QAK) */ -hbool_t H5_api_entered_g = FALSE; +/* Library incompatible release versions, develop releases are incompatible by design */ +const unsigned VERS_RELEASE_EXCEPTIONS[] = {0}; +const unsigned VERS_RELEASE_EXCEPTIONS_SIZE = 1; /* statically initialize block for pthread_once call used in initializing */ /* the first global mutex */ #ifdef H5_HAVE_THREADSAFE H5_api_t H5_g; #else -hbool_t H5_libinit_g = FALSE; /* Library hasn't been initialized */ -#endif - -#ifdef H5_HAVE_MPE -hbool_t H5_MPEinit_g = FALSE; /* MPE Library hasn't been initialized */ +hbool_t H5_libinit_g = FALSE; /* Library hasn't been initialized */ +hbool_t H5_libterm_g = FALSE; /* Library isn't being shutdown */ #endif -char H5_lib_vers_info_g[] = H5_VERS_INFO; -static hbool_t H5_dont_atexit_g = FALSE; -H5_debug_t H5_debug_g; /*debugging info */ +hbool_t H5_use_selection_io_g = FALSE; +char H5_lib_vers_info_g[] = H5_VERS_INFO; +static hbool_t H5_dont_atexit_g = FALSE; +H5_debug_t H5_debug_g; /* debugging info */ /*******************/ /* Local Variables */ /*******************/ +/* Linked list of registered 'atclose' functions to invoke at library shutdown */ +static H5_atclose_node_t *H5_atclose_head = NULL; + +/* Declare a free list to manage the H5_atclose_node_t struct */ +H5FL_DEFINE_STATIC(H5_atclose_node_t); + +/*------------------------------------------------------------------------- + * Function: H5_default_vfd_init + * + * Purpose: Initialize the default VFD. + * + * Return: Success: non-negative + * Failure: negative + *------------------------------------------------------------------------- + */ +static herr_t +H5_default_vfd_init(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(FAIL) + /* Load the hid_t for the default VFD for the side effect + * it has of initializing the default VFD. + */ + if (H5FD_sec2_init() == H5I_INVALID_HID) { + HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to load default VFD ID") + } +done: + FUNC_LEAVE_NOAPI(ret_value) +} /*-------------------------------------------------------------------------- * NAME @@ -108,42 +140,45 @@ H5_debug_t H5_debug_g; /*debugging info */ herr_t H5_init_library(void) { - herr_t ret_value = SUCCEED; + size_t i; + char *env_use_select_io = NULL; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(FAIL) + /* Run the library initialization routine, if it hasn't already run */ + if (H5_INIT_GLOBAL || H5_TERM_GLOBAL) + HGOTO_DONE(SUCCEED) + + /* Set the 'library initialized' flag as early as possible, to avoid + * possible re-entrancy. + */ + H5_INIT_GLOBAL = TRUE; + #ifdef H5_HAVE_PARALLEL { - int mpi_initialized; + int mpi_initialized; + int mpi_finalized; int mpi_code; - MPI_Initialized(&mpi_initialized); - -#ifdef H5_HAVE_MPE - /* Initialize MPE instrumentation library. */ - if (!H5_MPEinit_g) - { - int mpe_code; - if (mpi_initialized){ - mpe_code = MPE_Init_log(); - HDassert(mpe_code >=0); - H5_MPEinit_g = TRUE; - } - } -#endif /*H5_HAVE_MPE*/ + MPI_Initialized(&mpi_initialized); + MPI_Finalized(&mpi_finalized); /* add an attribute on MPI_COMM_SELF to call H5_term_library when it is destroyed, i.e. on MPI_Finalize */ - if (mpi_initialized) { + if (mpi_initialized && !mpi_finalized) { int key_val; - if(MPI_SUCCESS != (mpi_code = MPI_Comm_create_keyval(MPI_NULL_COPY_FN, - (MPI_Comm_delete_attr_function *)H5_mpi_delete_cb, - &key_val, NULL))) + if (MPI_SUCCESS != (mpi_code = MPI_Comm_create_keyval( + MPI_COMM_NULL_COPY_FN, (MPI_Comm_delete_attr_function *)H5__mpi_delete_cb, + &key_val, NULL))) HMPI_GOTO_ERROR(FAIL, "MPI_Comm_create_keyval failed", mpi_code) - if(MPI_SUCCESS != (mpi_code = MPI_Comm_set_attr(MPI_COMM_SELF, key_val, NULL))) + if (MPI_SUCCESS != (mpi_code = MPI_Comm_set_attr(MPI_COMM_SELF, key_val, NULL))) HMPI_GOTO_ERROR(FAIL, "MPI_Comm_set_attr failed", mpi_code) + + if (MPI_SUCCESS != (mpi_code = MPI_Comm_free_keyval(&key_val))) + HMPI_GOTO_ERROR(FAIL, "MPI_Comm_free_keyval failed", mpi_code) } } #endif /*H5_HAVE_PARALLEL*/ @@ -152,30 +187,32 @@ H5_init_library(void) * Make sure the package information is updated. */ HDmemset(&H5_debug_g, 0, sizeof H5_debug_g); - H5_debug_g.pkg[H5_PKG_A].name = "a"; + H5_debug_g.pkg[H5_PKG_A].name = "a"; H5_debug_g.pkg[H5_PKG_AC].name = "ac"; - H5_debug_g.pkg[H5_PKG_B].name = "b"; - H5_debug_g.pkg[H5_PKG_D].name = "d"; - H5_debug_g.pkg[H5_PKG_E].name = "e"; - H5_debug_g.pkg[H5_PKG_F].name = "f"; - H5_debug_g.pkg[H5_PKG_G].name = "g"; + H5_debug_g.pkg[H5_PKG_B].name = "b"; + H5_debug_g.pkg[H5_PKG_D].name = "d"; + H5_debug_g.pkg[H5_PKG_E].name = "e"; + H5_debug_g.pkg[H5_PKG_F].name = "f"; + H5_debug_g.pkg[H5_PKG_G].name = "g"; H5_debug_g.pkg[H5_PKG_HG].name = "hg"; H5_debug_g.pkg[H5_PKG_HL].name = "hl"; - H5_debug_g.pkg[H5_PKG_I].name = "i"; + H5_debug_g.pkg[H5_PKG_I].name = "i"; + H5_debug_g.pkg[H5_PKG_M].name = "m"; H5_debug_g.pkg[H5_PKG_MF].name = "mf"; H5_debug_g.pkg[H5_PKG_MM].name = "mm"; - H5_debug_g.pkg[H5_PKG_O].name = "o"; - H5_debug_g.pkg[H5_PKG_P].name = "p"; - H5_debug_g.pkg[H5_PKG_S].name = "s"; - H5_debug_g.pkg[H5_PKG_T].name = "t"; - H5_debug_g.pkg[H5_PKG_V].name = "v"; - H5_debug_g.pkg[H5_PKG_Z].name = "z"; + H5_debug_g.pkg[H5_PKG_O].name = "o"; + H5_debug_g.pkg[H5_PKG_P].name = "p"; + H5_debug_g.pkg[H5_PKG_S].name = "s"; + H5_debug_g.pkg[H5_PKG_T].name = "t"; + H5_debug_g.pkg[H5_PKG_V].name = "v"; + H5_debug_g.pkg[H5_PKG_VL].name = "vl"; + H5_debug_g.pkg[H5_PKG_Z].name = "z"; /* * Install atexit() library cleanup routines unless the H5dont_atexit() * has been called. Once we add something to the atexit() list it stays * there permanently, so we set H5_dont_atexit_g after we add it to prevent - * adding it again later if the library is cosed and reopened. + * adding it again later if the library is closed and reopened. */ if (!H5_dont_atexit_g) { @@ -184,12 +221,13 @@ H5_init_library(void) * This must be entered before the library cleanup code so it's * executed in LIFO order (i.e., last). */ - (void)HDatexit(H5TS_win32_process_exit); + (void)HDatexit(H5TS_win32_process_exit); #endif /* H5_HAVE_THREADSAFE && H5_HAVE_WIN_THREADS */ /* Normal library termination code */ (void)HDatexit(H5_term_library); - H5_dont_atexit_g = TRUE; + + H5_dont_atexit_g = TRUE; } /* end if */ /* @@ -201,51 +239,76 @@ H5_init_library(void) * property classes. * The link interface needs to be initialized so that link property lists * have their properties registered. + * The FS module needs to be initialized as a result of the fix for HDFFV-10160: + * It might not be initialized during normal file open. + * When the application does not close the file, routines in the module might + * be called via H5_term_library() when shutting down the file. + * The dataspace interface needs to be initialized so that future IDs for + * dataspaces work. */ - if(H5E_init() < 0) - HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize error interface") - if(H5P_init() < 0) - HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize property list interface") - if(H5T_init() < 0) - HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize datatype interface") - if(H5D_init() < 0) - HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize dataset interface") - if(H5AC_init() < 0) - HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize metadata caching interface") - if(H5L_init() < 0) - HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize link interface") + /* clang-format off */ + struct { + herr_t (*func)(void); + const char *descr; + } initializer[] = { + {H5E_init, "error"} + , {H5VL_init_phase1, "VOL"} + , {H5SL_init, "skip lists"} + , {H5FD_init, "VFD"} + , {H5_default_vfd_init, "default VFD"} + , {H5P_init_phase1, "property list"} + , {H5AC_init, "metadata caching"} + , {H5L_init, "link"} + , {H5S_init, "dataspace"} + , {H5PL_init, "plugins"} + /* Finish initializing interfaces that depend on the interfaces above */ + , {H5P_init_phase2, "property list"} + , {H5VL_init_phase2, "VOL"} + }; + + for (i = 0; i < NELMTS(initializer); i++) { + if (initializer[i].func() < 0) { + HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, + "unable to initialize %s interface", initializer[i].descr) + } + } + /* clang-format on */ + + /* Check for HDF5_USE_SELECTION_IO env variable */ + env_use_select_io = HDgetenv("HDF5_USE_SELECTION_IO"); + if (NULL != env_use_select_io && HDstrcmp(env_use_select_io, "") && HDstrcmp(env_use_select_io, "0") && + HDstrcmp(env_use_select_io, "no") && HDstrcmp(env_use_select_io, "No") && + HDstrcmp(env_use_select_io, "NO") && HDstrcmp(env_use_select_io, "false") && + HDstrcmp(env_use_select_io, "False") && HDstrcmp(env_use_select_io, "FALSE")) + H5_use_selection_io_g = TRUE; /* Debugging? */ - H5_debug_mask("-all"); - H5_debug_mask(HDgetenv("HDF5_DEBUG")); + H5__debug_mask("-all"); + H5__debug_mask(HDgetenv("HDF5_DEBUG")); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5_init_library() */ - /*------------------------------------------------------------------------- - * Function: H5_term_library - * - * Purpose: Terminate interfaces in a well-defined order due to - * dependencies among the interfaces, then terminate - * library-specific data. - * - * Return: void + * Function: H5_term_library * - * Programmer: Robb Matzke - * Friday, November 20, 1998 + * Purpose: Terminate interfaces in a well-defined order due to + * dependencies among the interfaces, then terminate + * library-specific data. * - * Modifications: + * Return: void * *------------------------------------------------------------------------- */ void H5_term_library(void) { - int pending, ntries = 0, n; - size_t at = 0; - char loop[1024]; + int pending, ntries = 0; + char loop[1024], *next = loop; + size_t i; + size_t nleft = sizeof(loop); + int nprinted; H5E_auto2_t func; #ifdef H5_HAVE_THREADSAFE @@ -255,100 +318,185 @@ H5_term_library(void) #endif /* Don't do anything if the library is already closed */ - if(!(H5_INIT_GLOBAL)) - goto done; + if (!(H5_INIT_GLOBAL)) + goto done; + + /* Indicate that the library is being shut down */ + H5_TERM_GLOBAL = TRUE; + + /* Push the API context without checking for errors */ + H5CX_push_special(); /* Check if we should display error output */ (void)H5Eget_auto2(H5E_DEFAULT, &func, NULL); + /* Iterate over the list of 'atclose' callbacks that have been registered */ + if (H5_atclose_head) { + H5_atclose_node_t *curr_atclose; /* Current 'atclose' node */ + + /* Iterate over all 'atclose' nodes, making callbacks */ + curr_atclose = H5_atclose_head; + while (curr_atclose) { + H5_atclose_node_t *tmp_atclose; /* Temporary pointer to 'atclose' node */ + + /* Invoke callback, providing context */ + (*curr_atclose->func)(curr_atclose->ctx); + + /* Advance to next node and free this one */ + tmp_atclose = curr_atclose; + curr_atclose = curr_atclose->next; + H5FL_FREE(H5_atclose_node_t, tmp_atclose); + } /* end while */ + + /* Reset list head, in case library is re-initialized */ + H5_atclose_head = NULL; + } /* end if */ + + /* clang-format off */ + /* * Terminate each interface. The termination functions return a positive * value if they do something that might affect some other interface in a * way that would necessitate some cleanup work in the other interface. */ -#define DOWN(F) \ - (((n = H5##F##_term_interface()) && (at + 8) < sizeof loop)? \ - (sprintf(loop + at, "%s%s", (at ? "," : ""), #F), \ - at += HDstrlen(loop + at), \ - n): \ - ((n > 0 && (at + 5) < sizeof loop) ? \ - (sprintf(loop + at, "..."), \ - at += HDstrlen(loop + at), \ - n) : n)) - do { - pending = 0; - /* Try to organize these so the "higher" level components get shut - * down before "lower" level components that they might rely on. -QAK +#define TERMINATOR(module, wait) { \ + .func = H5##module##_term_package \ + , .name = #module \ + , .completed = false \ + , .await_prior = wait \ + } + + /* + * Termination is ordered by the `terminator` table so the "higher" level + * packages are shut down before "lower" level packages that they + * rely on: + */ + struct { + int (*func)(void); /* function to terminate the module; returns 0 + * on success, >0 if termination was not + * completed and we should try to terminate + * some dependent modules, first. + */ + const char *name; /* name of the module */ + hbool_t completed; /* true iff this terminator was already + * completed + */ + const hbool_t await_prior; /* true iff all prior terminators in the + * list must complete before this + * terminator is attempted + */ + } terminator[] = { + /* Close the event sets first, so that all asynchronous operations + * complete before anything else attempts to shut down. + */ + TERMINATOR(ES, false) + /* Do not attempt to close down package L until after event sets + * have finished closing down. */ - pending += DOWN(R); - pending += DOWN(D); - pending += DOWN(L); - pending += DOWN(G); - pending += DOWN(A); - pending += DOWN(S); - pending += DOWN(T); + , TERMINATOR(L, true) + /* Close the "top" of various interfaces (IDs, etc) but don't shut + * down the whole interface yet, so that the object header messages + * get serialized correctly for entries in the metadata cache and the + * symbol table entry in the superblock gets serialized correctly, etc. + * all of which is performed in the 'F' shutdown. + * + * The tops of packages A, D, G, M, S, T do not need to wait for L + * or previous packages to finish closing down. + */ + , TERMINATOR(A_top, false) + , TERMINATOR(D_top, false) + , TERMINATOR(G_top, false) + , TERMINATOR(M_top, false) + , TERMINATOR(S_top, false) + , TERMINATOR(T_top, false) /* Don't shut down the file code until objects in files are shut down */ - if(pending == 0) - pending += DOWN(F); - - /* Don't shut down "low-level" components until "high-level" components - * have successfully shut down. This prevents property lists and IDs - * from being closed "out from underneath" of the high-level objects - * that depend on them. -QAK + , TERMINATOR(F, true) + /* Don't shut down the property list code until all objects that might + * use property lists are shut down + */ + , TERMINATOR(P, true) + /* Wait to shut down the "bottom" of various interfaces until the + * files are closed, so pieces of the file can be serialized + * correctly. + * + * Shut down the "bottom" of the attribute, dataset, group, + * reference, dataspace, and datatype interfaces, fully closing + * out the interfaces now. + */ + , TERMINATOR(A, true) + , TERMINATOR(D, false) + , TERMINATOR(G, false) + , TERMINATOR(M, false) + , TERMINATOR(S, false) + , TERMINATOR(T, false) + /* Wait to shut down low-level packages like AC until after + * the preceding high-level packages have shut down. This prevents + * low-level objects from closing "out from underneath" their + * reliant high-level objects. */ - if(pending == 0) { - pending += DOWN(AC); - pending += DOWN(Z); - pending += DOWN(FD); - pending += DOWN(P); - pending += DOWN(PL); - /* Don't shut down the error code until other APIs which use it are shut down */ - if(pending == 0) - pending += DOWN(E); - /* Don't shut down the ID code until other APIs which use them are shut down */ - if(pending == 0) - pending += DOWN(I); - /* Don't shut down the skip list code until everything that uses it is down */ - if(pending == 0) - pending += DOWN(SL); - /* Don't shut down the free list code until _everything_ else is down */ - if(pending == 0) - pending += DOWN(FL); + , TERMINATOR(AC, true) + /* Shut down the "pluggable" interfaces, before the plugin framework */ + , TERMINATOR(Z, false) + , TERMINATOR(FD, false) + , TERMINATOR(VL, false) + /* Don't shut down the plugin code until all "pluggable" interfaces + * (Z, FD, PL) are shut down + */ + , TERMINATOR(PL, true) + /* Shut down the following packages in strictly the order given + * by the table. + */ + , TERMINATOR(E, true) + , TERMINATOR(I, true) + , TERMINATOR(SL, true) + , TERMINATOR(FL, true) + , TERMINATOR(CX, true) + }; + + do { + pending = 0; + for (i = 0; i < NELMTS(terminator); i++) { + if (terminator[i].completed) + continue; + if (pending != 0 && terminator[i].await_prior) + break; + if (terminator[i].func() == 0) { + terminator[i].completed = true; + continue; + } + + /* log a package when its terminator needs to be retried */ + pending++; + nprinted = HDsnprintf(next, nleft, "%s%s", + (next != loop) ? "," : "", terminator[i].name); + if (nprinted < 0) + continue; + if ((size_t)nprinted >= nleft) + nprinted = HDsnprintf(next, nleft, "..."); + if (nprinted < 0 || (size_t)nprinted >= nleft) + continue; + nleft -= (size_t)nprinted; + next += nprinted; } - } while(pending && ntries++ < 100); + } while (pending && ntries++ < 100); - if(pending) { + /* clang-format on */ + + if (pending) { /* Only display the error message if the user is interested in them. */ - if(func) { - fprintf(stderr, "HDF5: infinite loop closing library\n"); - fprintf(stderr, " %s\n", loop); + if (func) { + HDfprintf(stderr, "HDF5: infinite loop closing library\n"); + HDfprintf(stderr, " %s\n", loop); #ifndef NDEBUG HDabort(); -#endif /* NDEBUG */ +#endif /* NDEBUG */ } /* end if */ - } /* end if */ - -#ifdef H5_HAVE_MPE - /* Close MPE instrumentation library. May need to move this - * down if any of the below code involves using the instrumentation code. - */ - if(H5_MPEinit_g) { - int mpe_code; - int mpi_initialized; - - MPI_Initialized(&mpi_initialized); - if(mpi_initialized) { - mpe_code = MPE_Finish_log("h5log"); - HDassert(mpe_code >=0); - } /* end if */ - H5_MPEinit_g = FALSE; /* turn it off no matter what */ - } /* end if */ -#endif + } /* end if */ /* Free open debugging streams */ - while(H5_debug_g.open_stream) { - H5_debug_open_stream_t *tmp_open_stream; + while (H5_debug_g.open_stream) { + H5_debug_open_stream_t *tmp_open_stream; tmp_open_stream = H5_debug_g.open_stream; (void)HDfclose(H5_debug_g.open_stream->stream); @@ -356,50 +504,51 @@ H5_term_library(void) (void)H5MM_free(tmp_open_stream); } /* end while */ + /* Reset flag indicating that the library is being shut down */ + H5_TERM_GLOBAL = FALSE; + /* Mark library as closed */ H5_INIT_GLOBAL = FALSE; + + /* Don't pop the API context (i.e. H5CX_pop), since it's been shut down already */ + done: #ifdef H5_HAVE_THREADSAFE H5_API_UNLOCK #endif /* H5_HAVE_THREADSAFE */ + return; } /* end H5_term_library() */ - /*------------------------------------------------------------------------- - * Function: H5dont_atexit - * - * Purpose: Indicates that the library is not to clean up after itself - * when the application exits by calling exit() or returning - * from main(). This function must be called before any other - * HDF5 function or constant is used or it will have no effect. - * - * If this function is used then certain memory buffers will not - * be de-allocated nor will open files be flushed automatically. - * The application may still call H5close() explicitly to - * accomplish these things. + * Function: H5dont_atexit * - * Return: Success: non-negative + * Purpose: Indicates that the library is not to clean up after itself + * when the application exits by calling exit() or returning + * from main(). This function must be called before any other + * HDF5 function or constant is used or it will have no effect. * - * Failure: negative if this function is called more than - * once or if it is called too late. + * If this function is used then certain memory buffers will not + * be de-allocated nor will open files be flushed automatically. + * The application may still call H5close() explicitly to + * accomplish these things. * - * Programmer: Robb Matzke - * Friday, November 20, 1998 + * Return: Success: non-negative * - * Modifications: + * Failure: negative if this function is called more than + * once or if it is called too late. * *------------------------------------------------------------------------- */ herr_t H5dont_atexit(void) { - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API_NOINIT_NOERR_NOFS - H5TRACE0("e",""); + H5TRACE0("e", ""); - if(H5_dont_atexit_g) + if (H5_dont_atexit_g) ret_value = FAIL; else H5_dont_atexit_g = TRUE; @@ -407,50 +556,43 @@ H5dont_atexit(void) FUNC_LEAVE_API_NOFS(ret_value) } /* end H5dont_atexit() */ - /*------------------------------------------------------------------------- - * Function: H5garbage_collect + * Function: H5garbage_collect * - * Purpose: Walks through all the garbage collection routines for the - * library, which are supposed to free any unused memory they have - * allocated. + * Purpose: Walks through all the garbage collection routines for the + * library, which are supposed to free any unused memory they have + * allocated. * - * These should probably be registered dynamicly in a linked list of + * These should probably be registered dynamically in a linked list of * functions to call, but there aren't that many right now, so we * hard-wire them... * - * Return: Success: non-negative + * Return: Success: non-negative * - * Failure: negative - * - * Programmer: Quincey Koziol - * Saturday, March 11, 2000 - * - * Modifications: + * Failure: negative * *------------------------------------------------------------------------- */ herr_t H5garbage_collect(void) { - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_API(FAIL) - H5TRACE0("e",""); + H5TRACE0("e", ""); /* Call the garbage collection routines in the library */ - if(H5FL_garbage_coll()<0) + if (H5FL_garbage_coll() < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect objects") done: FUNC_LEAVE_API(ret_value) -} /* end H5garbage_collect() */ +} /* end H5garbage_collect() */ - /*------------------------------------------------------------------------- - * Function: H5set_free_list_limits + * Function: H5set_free_list_limits * - * Purpose: Sets limits on the different kinds of free lists. Setting a value + * Purpose: Sets limits on the different kinds of free lists. Setting a value * of -1 for a limit means no limit of that type. These limits are global * for the entire library. Each "global" limit only applies to free lists * of that type, so if an application sets a limit of 1 MB on each of the @@ -468,336 +610,414 @@ done: * int blk_global_lim; IN: The limit on all "block" free list memory used * int blk_list_lim; IN: The limit on memory used in each "block" free list * - * Return: Success: non-negative + * Return: Success: non-negative * - * Failure: negative - * - * Programmer: Quincey Koziol - * Wednesday, August 2, 2000 - * - * Modifications: Neil Fortner - * Wednesday, April 8, 2009 - * Added support for factory free lists + * Failure: negative * *------------------------------------------------------------------------- */ herr_t -H5set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim, - int arr_list_lim, int blk_global_lim, int blk_list_lim) +H5set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim, int arr_list_lim, + int blk_global_lim, int blk_list_lim) { - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_API(FAIL) - H5TRACE6("e", "IsIsIsIsIsIs", reg_global_lim, reg_list_lim, arr_global_lim, - arr_list_lim, blk_global_lim, blk_list_lim); + H5TRACE6("e", "IsIsIsIsIsIs", reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim, blk_global_lim, + blk_list_lim); /* Call the free list function to actually set the limits */ - if(H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim, - blk_global_lim, blk_list_lim, blk_global_lim, blk_list_lim)<0) + if (H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim, blk_global_lim, + blk_list_lim, blk_global_lim, blk_list_lim) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "can't set garbage collection limits") done: FUNC_LEAVE_API(ret_value) -} /* end H5set_free_list_limits() */ +} /* end H5set_free_list_limits() */ - /*------------------------------------------------------------------------- - * Function: H5_debug_mask - * - * Purpose: Set runtime debugging flags according to the string S. The - * string should contain file numbers and package names - * separated by other characters. A file number applies to all - * following package names up to the next file number. The - * initial file number is `2' (the standard error stream). Each - * package name can be preceded by a `+' or `-' to add or remove - * the package from the debugging list (`+' is the default). The - * special name `all' means all packages. - * - * The name `trace' indicates that API tracing is to be turned - * on or off. - * - * Return: void - * - * Programmer: Robb Matzke - * Wednesday, August 19, 1998 - * - * Modifications: - * Robb Matzke, 2002-08-08 - * Accepts the `ttop' word. If enabled then show only the - * top level API calls, otherwise show all API calls. Also - * turns on tracing as if the `trace' word was present. + * Function: H5get_free_list_sizes + * + * Purpose: Gets the current size of the different kinds of free lists that + * the library uses to manage memory. The free list sizes can be set with + * H5set_free_list_limits and garbage collected with H5garbage_collect. + * These lists are global for the entire library. + * + * Parameters: + * size_t *reg_size; OUT: The current size of all "regular" free list memory used + * size_t *arr_size; OUT: The current size of all "array" free list memory used + * size_t *blk_size; OUT: The current size of all "block" free list memory used + * size_t *fac_size; OUT: The current size of all "factory" free list memory used + * + * Return: Success: non-negative + * Failure: negative + * + * Programmer: Quincey Koziol + * Friday, March 6, 2020 + * + *------------------------------------------------------------------------- + */ +herr_t +H5get_free_list_sizes(size_t *reg_size /*out*/, size_t *arr_size /*out*/, size_t *blk_size /*out*/, + size_t *fac_size /*out*/) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE4("e", "xxxx", reg_size, arr_size, blk_size, fac_size); + + /* Call the free list function to actually get the sizes */ + if (H5FL_get_free_list_sizes(reg_size, arr_size, blk_size, fac_size) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get garbage collection sizes") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5get_free_list_sizes() */ + +/*------------------------------------------------------------------------- + * Function: H5__debug_mask + * + * Purpose: Set runtime debugging flags according to the string S. The + * string should contain file numbers and package names + * separated by other characters. A file number applies to all + * following package names up to the next file number. The + * initial file number is `2' (the standard error stream). Each + * package name can be preceded by a `+' or `-' to add or remove + * the package from the debugging list (`+' is the default). The + * special name `all' means all packages. + * + * The name `trace' indicates that API tracing is to be turned + * on or off. + * + * The name 'ttop' indicates that only top-level API calls + * should be shown. This also turns on tracing as if the + * 'trace' word was shown. + * + * Return: void + * *------------------------------------------------------------------------- */ static void -H5_debug_mask(const char *s) +H5__debug_mask(const char *s) { - FILE *stream = stderr; - char pkg_name[32], *rest; - size_t i; - hbool_t clear; + FILE *stream = stderr; + char pkg_name[32], *rest; + size_t i; + hbool_t clear; while (s && *s) { - if (HDisalpha(*s) || '-'==*s || '+'==*s) { - /* Enable or Disable debugging? */ - if ('-'==*s) { - clear = TRUE; - s++; - } else if ('+'==*s) { - clear = FALSE; - s++; - } else { - clear = FALSE; - } - - /* Get the name */ - for (i=0; HDisalpha(*s); i++, s++) - if (i<sizeof pkg_name) + + if (HDisalpha(*s) || '-' == *s || '+' == *s) { + + /* Enable or Disable debugging? */ + if ('-' == *s) { + clear = TRUE; + s++; + } + else if ('+' == *s) { + clear = FALSE; + s++; + } + else { + clear = FALSE; + } /* end if */ + + /* Get the name */ + for (i = 0; HDisalpha(*s); i++, s++) + if (i < sizeof pkg_name) pkg_name[i] = *s; - pkg_name[MIN(sizeof(pkg_name)-1, i)] = '\0'; + pkg_name[MIN(sizeof(pkg_name) - 1, i)] = '\0'; - /* Trace, all, or one? */ - if (!HDstrcmp(pkg_name, "trace")) { - H5_debug_g.trace = clear ? NULL : stream; - } else if (!HDstrcmp(pkg_name, "ttop")) { - H5_debug_g.trace = stream; - H5_debug_g.ttop = (hbool_t)!clear; - } else if (!HDstrcmp(pkg_name, "ttimes")) { + /* Trace, all, or one? */ + if (!HDstrcmp(pkg_name, "trace")) { + H5_debug_g.trace = clear ? NULL : stream; + } + else if (!HDstrcmp(pkg_name, "ttop")) { H5_debug_g.trace = stream; + H5_debug_g.ttop = (hbool_t)!clear; + } + else if (!HDstrcmp(pkg_name, "ttimes")) { + H5_debug_g.trace = stream; H5_debug_g.ttimes = (hbool_t)!clear; - } else if (!HDstrcmp(pkg_name, "all")) { - for (i=0; i<(size_t)H5_NPKGS; i++) - H5_debug_g.pkg[i].stream = clear ? NULL : stream; - } else { - for (i=0; i<(size_t)H5_NPKGS; i++) { - if (!HDstrcmp(H5_debug_g.pkg[i].name, pkg_name)) { - H5_debug_g.pkg[i].stream = clear ? NULL : stream; - break; - } - } - if (i>=(size_t)H5_NPKGS) - fprintf(stderr, "HDF5_DEBUG: ignored %s\n", pkg_name); - } - - } else if (HDisdigit(*s)) { - int fd = (int)HDstrtol(s, &rest, 0); - H5_debug_open_stream_t *open_stream; - - if((stream = HDfdopen(fd, "w")) != NULL) { - (void)HDsetvbuf(stream, NULL, _IOLBF, (size_t)0); - - if(NULL == (open_stream = (H5_debug_open_stream_t *)H5MM_malloc(sizeof(H5_debug_open_stream_t)))) { + } + else if (!HDstrcmp(pkg_name, "all")) { + for (i = 0; i < (size_t)H5_NPKGS; i++) + H5_debug_g.pkg[i].stream = clear ? NULL : stream; + } + else { + for (i = 0; i < (size_t)H5_NPKGS; i++) { + if (!HDstrcmp(H5_debug_g.pkg[i].name, pkg_name)) { + H5_debug_g.pkg[i].stream = clear ? NULL : stream; + break; + } /* end if */ + } /* end for */ + if (i >= (size_t)H5_NPKGS) + HDfprintf(stderr, "HDF5_DEBUG: ignored %s\n", pkg_name); + } /* end if-else */ + } + else if (HDisdigit(*s)) { + int fd = (int)HDstrtol(s, &rest, 0); + H5_debug_open_stream_t *open_stream; + + if ((stream = HDfdopen(fd, "w")) != NULL) { + (void)HDsetvbuf(stream, NULL, _IOLBF, (size_t)0); + + if (NULL == + (open_stream = (H5_debug_open_stream_t *)H5MM_malloc(sizeof(H5_debug_open_stream_t)))) { (void)HDfclose(stream); return; } /* end if */ - open_stream->stream = stream; - open_stream->next = H5_debug_g.open_stream; + open_stream->stream = stream; + open_stream->next = H5_debug_g.open_stream; H5_debug_g.open_stream = open_stream; } /* end if */ - s = rest; - } else { - s++; - } - } -} /* end H5_debug_mask() */ + + s = rest; + } + else { + s++; + } /* end if-else */ + } /* end while */ +} /* end H5__debug_mask() */ #ifdef H5_HAVE_PARALLEL - + /*------------------------------------------------------------------------- - * Function: H5_mpi_delete_cb + * Function: H5__mpi_delete_cb * - * Purpose: Callback attribute on MPI_COMM_SELF to terminate the HDF5 + * Purpose: Callback attribute on MPI_COMM_SELF to terminate the HDF5 * library when the communicator is destroyed, i.e. on MPI_Finalize. * - * Return: MPI_SUCCESS - * - * Programmer: Mohamad Chaarawi, February 2015 + * Return: MPI_SUCCESS * *------------------------------------------------------------------------- */ -static int H5_mpi_delete_cb(MPI_Comm UNUSED comm, int UNUSED keyval, void UNUSED *attr_val, int UNUSED *flag) +static int +H5__mpi_delete_cb(MPI_Comm H5_ATTR_UNUSED comm, int H5_ATTR_UNUSED keyval, void H5_ATTR_UNUSED *attr_val, + int H5_ATTR_UNUSED *flag) { H5_term_library(); return MPI_SUCCESS; } #endif /*H5_HAVE_PARALLEL*/ - /*------------------------------------------------------------------------- - * Function: H5get_libversion + * Function: H5get_libversion * - * Purpose: Returns the library version numbers through arguments. MAJNUM - * will be the major revision number of the library, MINNUM the - * minor revision number, and RELNUM the release revision number. + * Purpose: Returns the library version numbers through arguments. MAJNUM + * will be the major revision number of the library, MINNUM the + * minor revision number, and RELNUM the release revision number. * - * Note: When printing an HDF5 version number it should be printed as + * Note: When printing an HDF5 version number it should be printed as * - * printf("%u.%u.%u", maj, min, rel) or - * printf("version %u.%u release %u", maj, min, rel) + * printf("%u.%u.%u", maj, min, rel) or + * printf("version %u.%u release %u", maj, min, rel) * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Unknown - * - * Modifications: - * Robb Matzke, 4 Mar 1998 - * Now use "normal" data types for the interface. Any of the arguments - * may be null pointers + * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t -H5get_libversion(unsigned *majnum, unsigned *minnum, unsigned *relnum) +H5get_libversion(unsigned *majnum /*out*/, unsigned *minnum /*out*/, unsigned *relnum /*out*/) { - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_API(FAIL) - H5TRACE3("e", "*Iu*Iu*Iu", majnum, minnum, relnum); + H5TRACE3("e", "xxx", majnum, minnum, relnum); /* Set the version information */ - if (majnum) *majnum = H5_VERS_MAJOR; - if (minnum) *minnum = H5_VERS_MINOR; - if (relnum) *relnum = H5_VERS_RELEASE; + if (majnum) + *majnum = H5_VERS_MAJOR; + if (minnum) + *minnum = H5_VERS_MINOR; + if (relnum) + *relnum = H5_VERS_RELEASE; done: FUNC_LEAVE_API(ret_value) } /* end H5get_libversion() */ - /*------------------------------------------------------------------------- - * Function: H5check_version + * Function: H5check_version * - * Purpose: Verifies that the arguments match the version numbers - * compiled into the library. This function is intended to be - * called from user to verify that the versions of header files - * compiled into the application match the version of the hdf5 - * library. + * Purpose: Verifies that the arguments match the version numbers + * compiled into the library. This function is intended to be + * called from user to verify that the versions of header files + * compiled into the application match the version of the hdf5 + * library. + * Within major.minor.release version, the expectation + * is that all release versions are compatible, exceptions to + * this rule must be added to the VERS_RELEASE_EXCEPTIONS list. * - * Return: Success: SUCCEED + * Return: Success: SUCCEED * - * Failure: abort() - * - * Programmer: Robb Matzke - * Tuesday, April 21, 1998 - * - * Modifications: - * Albert Cheng, May 12, 2001 - * Added verification of H5_VERS_INFO. + * Failure: abort() * *------------------------------------------------------------------------- */ -#define VERSION_MISMATCH_WARNING \ - "Warning! ***HDF5 library version mismatched error***\n" \ - "The HDF5 header files used to compile this application do not match\n" \ - "the version used by the HDF5 library to which this application is linked.\n" \ - "Data corruption or segmentation faults may occur if the application continues.\n" \ - "This can happen when an application was compiled by one version of HDF5 but\n" \ - "linked with a different version of static or shared HDF5 library.\n" \ - "You should recompile the application or check your shared library related\n" \ +#define VERSION_MISMATCH_WARNING \ + "Warning! ***HDF5 library version mismatched error***\n" \ + "The HDF5 header files used to compile this application do not match\n" \ + "the version used by the HDF5 library to which this application is linked.\n" \ + "Data corruption or segmentation faults may occur if the application continues.\n" \ + "This can happen when an application was compiled by one version of HDF5 but\n" \ + "linked with a different version of static or shared HDF5 library.\n" \ + "You should recompile the application or check your shared library related\n" \ + "settings such as 'LD_LIBRARY_PATH'.\n" +#define RELEASE_MISMATCH_WARNING \ + "Warning! ***HDF5 library release mismatched error***\n" \ + "The HDF5 header files used to compile this application are not compatible with\n" \ + "the version used by the HDF5 library to which this application is linked.\n" \ + "Data corruption or segmentation faults may occur if the application continues.\n" \ + "This can happen when an application was compiled by one version of HDF5 but\n" \ + "linked with an incompatible version of static or shared HDF5 library.\n" \ + "You should recompile the application or check your shared library related\n" \ "settings such as 'LD_LIBRARY_PATH'.\n" herr_t H5check_version(unsigned majnum, unsigned minnum, unsigned relnum) { - char lib_str[256]; - char substr[] = H5_VERS_SUBRELEASE; - static int checked = 0; /* If we've already checked the version info */ - static unsigned int disable_version_check = 0; /* Set if the version check should be disabled */ - static const char *version_mismatch_warning = VERSION_MISMATCH_WARNING; - herr_t ret_value = SUCCEED; /* Return value */ + char lib_str[256]; + char substr[] = H5_VERS_SUBRELEASE; + static int checked = 0; /* If we've already checked the version info */ + static unsigned int disable_version_check = 0; /* Set if the version check should be disabled */ + static const char *version_mismatch_warning = VERSION_MISMATCH_WARNING; + static const char *release_mismatch_warning = RELEASE_MISMATCH_WARNING; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API_NOINIT_NOERR_NOFS H5TRACE3("e", "IuIuIu", majnum, minnum, relnum); /* Don't check again, if we already have */ if (checked) - HGOTO_DONE(SUCCEED) + HGOTO_DONE(SUCCEED) - { const char *s; /* Environment string for disabling version check */ + { + const char *s; /* Environment string for disabling version check */ /* Allow different versions of the header files and library? */ - s = HDgetenv ("HDF5_DISABLE_VERSION_CHECK"); + s = HDgetenv("HDF5_DISABLE_VERSION_CHECK"); if (s && HDisdigit(*s)) - disable_version_check = (unsigned int)HDstrtol (s, NULL, 0); + disable_version_check = (unsigned int)HDstrtol(s, NULL, 0); } - if (H5_VERS_MAJOR!=majnum || H5_VERS_MINOR!=minnum || - H5_VERS_RELEASE!=relnum) { + /* H5_VERS_MAJOR and H5_VERS_MINOR must match */ + if (H5_VERS_MAJOR != majnum || H5_VERS_MINOR != minnum) { switch (disable_version_check) { - case 0: - HDfprintf(stderr, "%s%s", version_mismatch_warning, - "You can, at your own risk, disable this warning by setting the environment\n" - "variable 'HDF5_DISABLE_VERSION_CHECK' to a value of '1'.\n" - "Setting it to 2 or higher will suppress the warning messages totally.\n"); - /* Mention the versions we are referring to */ - HDfprintf (stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n", - majnum, minnum, relnum, - (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, (unsigned)H5_VERS_RELEASE); - /* Show library settings if available */ - HDfprintf (stderr, "%s", H5libhdf5_settings); - - /* Bail out now. */ - HDfputs ("Bye...\n", stderr); - HDabort (); - case 1: - /* continue with a warning */ - /* Note that the warning message is embedded in the format string.*/ - HDfprintf (stderr, - "%s'HDF5_DISABLE_VERSION_CHECK' " - "environment variable is set to %d, application will\n" - "continue at your own risk.\n", - version_mismatch_warning, disable_version_check); - /* Mention the versions we are referring to */ - HDfprintf (stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n", - majnum, minnum, relnum, - (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, (unsigned)H5_VERS_RELEASE); - /* Show library settings if available */ - HDfprintf (stderr, "%s", H5libhdf5_settings); - break; - default: - /* 2 or higer: continue silently */ - break; + case 0: + HDfprintf(stderr, "%s%s", version_mismatch_warning, + "You can, at your own risk, disable this warning by setting the environment\n" + "variable 'HDF5_DISABLE_VERSION_CHECK' to a value of '1'.\n" + "Setting it to 2 or higher will suppress the warning messages totally.\n"); + /* Mention the versions we are referring to */ + HDfprintf(stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n", majnum, minnum, relnum, + (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, (unsigned)H5_VERS_RELEASE); + /* Show library settings if available */ + HDfprintf(stderr, "%s", H5libhdf5_settings); + + /* Bail out now. */ + HDfputs("Bye...\n", stderr); + HDabort(); + case 1: + /* continue with a warning */ + /* Note that the warning message is embedded in the format string.*/ + HDfprintf(stderr, + "%s'HDF5_DISABLE_VERSION_CHECK' " + "environment variable is set to %d, application will\n" + "continue at your own risk.\n", + version_mismatch_warning, disable_version_check); + /* Mention the versions we are referring to */ + HDfprintf(stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n", majnum, minnum, relnum, + (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, (unsigned)H5_VERS_RELEASE); + /* Show library settings if available */ + HDfprintf(stderr, "%s", H5libhdf5_settings); + break; + default: + /* 2 or higher: continue silently */ + break; } /* end switch */ - } /* end if */ + } /* end if (H5_VERS_MAJOR != majnum || H5_VERS_MINOR != minnum) */ + + /* H5_VERS_RELEASE should be compatible, we will only add checks for exceptions */ + /* Library develop release versions are incompatible by design */ + if (H5_VERS_RELEASE != relnum) { + for (unsigned i = 0; i < VERS_RELEASE_EXCEPTIONS_SIZE; i++) { + /* Check for incompatible headers or incompatible library */ + if (VERS_RELEASE_EXCEPTIONS[i] == relnum || VERS_RELEASE_EXCEPTIONS[i] == H5_VERS_RELEASE) { + switch (disable_version_check) { + case 0: + HDfprintf( + stderr, "%s%s", release_mismatch_warning, + "You can, at your own risk, disable this warning by setting the environment\n" + "variable 'HDF5_DISABLE_VERSION_CHECK' to a value of '1'.\n" + "Setting it to 2 or higher will suppress the warning messages totally.\n"); + /* Mention the versions we are referring to */ + HDfprintf(stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n", majnum, minnum, + relnum, (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, + (unsigned)H5_VERS_RELEASE); + + /* Bail out now. */ + HDfputs("Bye...\n", stderr); + HDabort(); + case 1: + /* continue with a warning */ + /* Note that the warning message is embedded in the format string.*/ + HDfprintf(stderr, + "%s'HDF5_DISABLE_VERSION_CHECK' " + "environment variable is set to %d, application will\n" + "continue at your own risk.\n", + release_mismatch_warning, disable_version_check); + /* Mention the versions we are referring to */ + HDfprintf(stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n", majnum, minnum, + relnum, (unsigned)H5_VERS_MAJOR, (unsigned)H5_VERS_MINOR, + (unsigned)H5_VERS_RELEASE); + break; + default: + /* 2 or higher: continue silently */ + break; + } /* end switch */ + + } /* end if */ + + } /* end for */ + + } /* end if (H5_VERS_RELEASE != relnum) */ /* Indicate that the version check has been performed */ checked = 1; - if (!disable_version_check){ - /* - * Verify if H5_VERS_INFO is consistent with the other version information. - * Check only the first sizeof(lib_str) char. Assume the information - * will fit within this size or enough significance. - */ - HDsnprintf(lib_str, sizeof(lib_str), "HDF5 library version: %d.%d.%d", - H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE); - if(*substr) { - HDstrncat(lib_str, "-", (size_t)1); - HDstrncat(lib_str, substr, (sizeof(lib_str) - HDstrlen(lib_str)) - 1); - } /* end if */ - if (HDstrcmp(lib_str, H5_lib_vers_info_g)){ - HDfputs ("Warning! Library version information error.\n" - "The HDF5 library version information are not " - "consistent in its source code.\nThis is NOT a fatal error " - "but should be corrected. Setting the environment\n" - "variable 'HDF5_DISABLE_VERSION_CHECK' to a value of 1 " - "will suppress\nthis warning.\n", - stderr); - HDfprintf (stderr, "Library version information are:\n" - "H5_VERS_MAJOR=%d, H5_VERS_MINOR=%d, H5_VERS_RELEASE=%d, " - "H5_VERS_SUBRELEASE=%s,\nH5_VERS_INFO=%s\n", - H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE, - H5_VERS_SUBRELEASE, H5_VERS_INFO); - } /* end if */ + if (!disable_version_check) { + /* + * Verify if H5_VERS_INFO is consistent with the other version information. + * Check only the first sizeof(lib_str) char. Assume the information + * will fit within this size or enough significance. + */ + HDsnprintf(lib_str, sizeof(lib_str), "HDF5 library version: %d.%d.%d%s%s", H5_VERS_MAJOR, + H5_VERS_MINOR, H5_VERS_RELEASE, (*substr ? "-" : ""), substr); + + if (HDstrcmp(lib_str, H5_lib_vers_info_g) != 0) { + HDfputs("Warning! Library version information error.\n" + "The HDF5 library version information are not " + "consistent in its source code.\nThis is NOT a fatal error " + "but should be corrected. Setting the environment\n" + "variable 'HDF5_DISABLE_VERSION_CHECK' to a value of 1 " + "will suppress\nthis warning.\n", + stderr); + HDfprintf(stderr, + "Library version information are:\n" + "H5_VERS_MAJOR=%d, H5_VERS_MINOR=%d, H5_VERS_RELEASE=%d, " + "H5_VERS_SUBRELEASE=%s,\nH5_VERS_INFO=%s\n", + H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE, H5_VERS_SUBRELEASE, H5_VERS_INFO); + } /* end if */ } done: FUNC_LEAVE_API_NOFS(ret_value) } /* end H5check_version() */ - /*------------------------------------------------------------------------- * Function: H5open * @@ -806,39 +1026,69 @@ done: * is failing inexplicably, then try calling this function * first. * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Tuesday, December 9, 1997 - * - * Modifications: + * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ herr_t H5open(void) { - herr_t ret_value=SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API_NOPUSH(FAIL) + /*NO TRACE*/ - FUNC_ENTER_API_NOCLEAR(FAIL) - H5TRACE0("e",""); /* all work is done by FUNC_ENTER() */ + done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_NOPUSH(ret_value) } /* end H5open() */ - /*------------------------------------------------------------------------- - * Function: H5close + * Function: H5atclose * - * Purpose: Terminate the library and release all resources. + * Purpose: Register a callback for the library to invoke when it's + * closing. Callbacks are invoked in LIFO order. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Robb Matzke - * Friday, January 30, 1998 + *------------------------------------------------------------------------- + */ +herr_t +H5atclose(H5_atclose_func_t func, void *ctx) +{ + H5_atclose_node_t *new_atclose; /* New 'atclose' node */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "Hc*x", func, ctx); + + /* Check arguments */ + if (NULL == func) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL func pointer") + + /* Allocate space for the 'atclose' node */ + if (NULL == (new_atclose = H5FL_MALLOC(H5_atclose_node_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate 'atclose' node") + + /* Set up 'atclose' node */ + new_atclose->func = func; + new_atclose->ctx = ctx; + + /* Connector to linked-list of 'atclose' nodes */ + new_atclose->next = H5_atclose_head; + H5_atclose_head = new_atclose; + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5atclose() */ + +/*------------------------------------------------------------------------- + * Function: H5close + * + * Purpose: Terminate the library and release all resources. * - * Modifications: + * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ @@ -851,18 +1101,17 @@ H5close(void) * this function for an uninitialized library. */ FUNC_ENTER_API_NOINIT_NOERR_NOFS - H5TRACE0("e",""); + H5TRACE0("e", ""); H5_term_library(); FUNC_LEAVE_API_NOFS(SUCCEED) } /* end H5close() */ - /*------------------------------------------------------------------------- - * Function: H5allocate_memory + * Function: H5allocate_memory * - * Purpose: Allocate a memory buffer with the semantics of malloc(). + * Purpose: Allocate a memory buffer with the semantics of malloc(). * * NOTE: This function is intended for use with filter * plugins so that all allocation and free operations @@ -877,9 +1126,10 @@ H5close(void) * * Return: * - * Success: A pointer to the allocated buffer. - * - * Failure: NULL + * Success: A pointer to the allocated buffer or NULL if the size + * parameter is zero. + * + * Failure: NULL (but may also be NULL w/ size 0!) * *------------------------------------------------------------------------- */ @@ -888,23 +1138,24 @@ H5allocate_memory(size_t size, hbool_t clear) { void *ret_value = NULL; - FUNC_ENTER_API_NOINIT; + FUNC_ENTER_API_NOINIT H5TRACE2("*x", "zb", size, clear); - if(clear) + if (0 == size) + return NULL; + + if (clear) ret_value = H5MM_calloc(size); else ret_value = H5MM_malloc(size); - FUNC_LEAVE_API(ret_value) - + FUNC_LEAVE_API_NOINIT(ret_value) } /* end H5allocate_memory() */ - /*------------------------------------------------------------------------- - * Function: H5resize_memory + * Function: H5resize_memory * - * Purpose: Resize a memory buffer with the semantics of realloc(). + * Purpose: Resize a memory buffer with the semantics of realloc(). * * NOTE: This function is intended for use with filter * plugins so that all allocation and free operations @@ -920,7 +1171,7 @@ H5allocate_memory(size_t size, hbool_t clear) * Return: * * Success: A pointer to the resized buffer. - * + * * Failure: NULL (the input buffer will be unchanged) * *------------------------------------------------------------------------- @@ -930,44 +1181,103 @@ H5resize_memory(void *mem, size_t size) { void *ret_value = NULL; - FUNC_ENTER_API_NOINIT; + FUNC_ENTER_API_NOINIT H5TRACE2("*x", "*xz", mem, size); ret_value = H5MM_realloc(mem, size); - FUNC_LEAVE_API(ret_value) - + FUNC_LEAVE_API_NOINIT(ret_value) } /* end H5resize_memory() */ - /*------------------------------------------------------------------------- - * Function: H5free_memory + * Function: H5free_memory * - * Purpose: Frees memory allocated by the library that it is the user's + * Purpose: Frees memory allocated by the library that it is the user's * responsibility to free. Ensures that the same library * that was used to allocate the memory frees it. Passing * NULL pointers is allowed. * - * Return: SUCCEED/FAIL + * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ herr_t H5free_memory(void *mem) { - FUNC_ENTER_API_NOINIT; + FUNC_ENTER_API_NOINIT H5TRACE1("e", "*x", mem); /* At this time, it is impossible for this to fail. */ - HDfree(mem); - - FUNC_LEAVE_API(SUCCEED) + H5MM_xfree(mem); + FUNC_LEAVE_API_NOINIT(SUCCEED) } /* end H5free_memory() */ - -#if defined(H5_HAVE_THREADSAFE) && defined(H5_BUILT_AS_DYNAMIC_LIB) \ - && defined(H5_HAVE_WIN32_API) && defined(H5_HAVE_WIN_THREADS) +/*------------------------------------------------------------------------- + * Function: H5is_library_threadsafe + * + * Purpose: Checks to see if the library was built with thread-safety + * enabled. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5is_library_threadsafe(hbool_t *is_ts /*out*/) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API_NOINIT + H5TRACE1("e", "x", is_ts); + + if (is_ts) { +#ifdef H5_HAVE_THREADSAFE + *is_ts = TRUE; +#else /* H5_HAVE_THREADSAFE */ + *is_ts = FALSE; +#endif /* H5_HAVE_THREADSAFE */ + } + else + ret_value = FAIL; + + FUNC_LEAVE_API_NOINIT(ret_value) +} /* end H5is_library_threadsafe() */ + +/*------------------------------------------------------------------------- + * Function: H5is_library_terminating + * + * Purpose: Checks to see if the library is shutting down. + * + * Note: Useful for plugins to detect when the library is terminating. + * For example, a VOL connector could check if a "file close" + * callback was the result of the library shutdown process, or + * an API action from the application. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5is_library_terminating(hbool_t *is_terminating /*out*/) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API_NOINIT + H5TRACE1("e", "x", is_terminating); + + HDassert(is_terminating); + + if (is_terminating) + *is_terminating = H5_TERM_GLOBAL; + else + ret_value = FAIL; + + FUNC_LEAVE_API_NOINIT(ret_value) +} /* end H5is_library_terminating() */ + +#if defined(H5_HAVE_THREADSAFE) && defined(H5_BUILT_AS_DYNAMIC_LIB) && defined(H5_HAVE_WIN32_API) && \ + defined(H5_HAVE_WIN_THREADS) /*------------------------------------------------------------------------- * Function: DllMain * @@ -995,35 +1305,33 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) BOOL fOkay = TRUE; - switch(fdwReason) - { - case DLL_PROCESS_ATTACH: - break; + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + break; - case DLL_PROCESS_DETACH: - break; + case DLL_PROCESS_DETACH: + break; - case DLL_THREAD_ATTACH: + case DLL_THREAD_ATTACH: #ifdef H5_HAVE_WIN_THREADS - if(H5TS_win32_thread_enter() < 0) - fOkay = FALSE; + if (H5TS_win32_thread_enter() < 0) + fOkay = FALSE; #endif /* H5_HAVE_WIN_THREADS */ - break; + break; - case DLL_THREAD_DETACH: + case DLL_THREAD_DETACH: #ifdef H5_HAVE_WIN_THREADS - if(H5TS_win32_thread_exit() < 0) - fOkay = FALSE; + if (H5TS_win32_thread_exit() < 0) + fOkay = FALSE; #endif /* H5_HAVE_WIN_THREADS */ - break; + break; - default: - /* Shouldn't get here */ - fOkay = FALSE; - break; + default: + /* Shouldn't get here */ + fOkay = FALSE; + break; } return fOkay; } #endif /* H5_HAVE_WIN32_API && H5_BUILT_AS_DYNAMIC_LIB && H5_HAVE_WIN_THREADS && H5_HAVE_THREADSAFE*/ - |
