/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /****************/ /* Module Setup */ /****************/ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5AC1private.h" /* Metadata cache */ #include "H5Dprivate.h" /* Datasets */ #include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free lists */ #include "H5Lprivate.h" /* Links */ #include "H5Pprivate.h" /* Property lists */ #include "H5Tprivate.h" /* Datatypes */ /****************/ /* Local Macros */ /****************/ /******************/ /* Local Typedefs */ /******************/ /********************/ /* Package Typedefs */ /********************/ /********************/ /* Local Prototypes */ /********************/ static void H5_debug_mask(const char*); /*********************/ /* Package Variables */ /*********************/ /*****************************/ /* Library Private Variables */ /*****************************/ /* 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 */ #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 */ /*******************/ /* Local Variables */ /*******************/ /*-------------------------------------------------------------------------- * NAME * H5_init_library -- Initialize library-global information * USAGE * herr_t H5_init_library() * * RETURNS * Non-negative on success/Negative on failure * * DESCRIPTION * Initializes any library-global data or routines. * *-------------------------------------------------------------------------- */ herr_t H5_init_library(void) { herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5_init_library, FAIL) /* * 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_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_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_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"; #ifdef H5_HAVE_MPE /* Initialize MPE instrumentation library. May need to move this * up earlier if any of the above initialization 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_Init_log(); assert(mpe_code >=0); H5_MPEinit_g = TRUE; } } #endif /* * Install atexit() library cleanup routine 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. */ if (!H5_dont_atexit_g) { (void)HDatexit(H5_term_library); H5_dont_atexit_g = TRUE; } /* end if */ /* * Initialize interfaces that might not be able to initialize themselves * soon enough. The file & dataset interfaces must be initialized because * calling H5P_create() might require the file/dataset property classes to be * initialized. The property interface must be initialized before the file * & dataset interfaces though, in order to provide them with the proper * property classes. * The link interface needs to be initialized so that link property lists * have their properties registered. */ 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(H5AC1_init() < 0) HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize metadata caching 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") /* Debugging? */ 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 * * Programmer: Robb Matzke * Friday, November 20, 1998 * * Modifications: * *------------------------------------------------------------------------- */ void H5_term_library(void) { int pending, ntries = 0, n; size_t at = 0; char loop[1024]; H5E_auto2_t func; #ifdef H5_HAVE_THREADSAFE /* explicit locking of the API */ H5_FIRST_THREAD_INIT H5_API_LOCK #endif /* Don't do anything if the library is already closed */ if(!(H5_INIT_GLOBAL)) goto done; /* Check if we should display error output */ (void)H5Eget_auto2(H5E_DEFAULT, &func, NULL); /* * 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 */ pending += DOWN(R); pending += DOWN(D); pending += DOWN(L); pending += DOWN(G); pending += DOWN(A); pending += DOWN(S); pending += DOWN(T); /* 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 */ if(pending == 0) { pending += DOWN(AC1); pending += DOWN(AC); pending += DOWN(Z); pending += DOWN(FD); pending += DOWN(P); /* 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 free list code until _everything_ else is down */ if(pending == 0) pending += DOWN(FL); } } while(pending && ntries++ < 100); 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); #ifndef NDEBUG HDabort(); #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("cpilog"); assert(mpe_code >=0); } /* end if */ H5_MPEinit_g = FALSE; /* turn it off no matter what */ } /* end if */ #endif /* Mark library as closed */ H5_INIT_GLOBAL = FALSE; done: #ifdef H5_HAVE_THREADSAFE H5_API_UNLOCK #endif 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. * * Return: Success: non-negative * * Failure: negative if this function is called more than * once or if it is called too late. * * Programmer: Robb Matzke * Friday, November 20, 1998 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5dont_atexit(void) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API_NOINIT_NOFS(H5dont_atexit) H5TRACE0("e",""); if(H5_dont_atexit_g) ret_value = FAIL; else H5_dont_atexit_g = TRUE; FUNC_LEAVE_API_NOFS(ret_value) } /* end H5dont_atexit() */ /*------------------------------------------------------------------------- * 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. * * These should probably be registered dynamicly 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 * * Failure: negative * * Programmer: Quincey Koziol * Saturday, March 11, 2000 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5garbage_collect(void) { herr_t ret_value = SUCCEED; FUNC_ENTER_API(H5garbage_collect, FAIL) H5TRACE0("e",""); /* Call the garbage collection routines in the library */ 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() */ /*------------------------------------------------------------------------- * Function: H5set_free_list_limits * * 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 * global lists, up to 3 MB of total storage might be allocated (1MB on * each of regular, array and block type lists). * * Parameters: * int reg_global_lim; IN: The limit on all "regular" free list memory used * int reg_list_lim; IN: The limit on memory used in each "regular" free list * int arr_global_lim; IN: The limit on all "array" free list memory used * int arr_list_lim; IN: The limit on memory used in each "array" free list * 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 * * Failure: negative * * Programmer: Quincey Koziol * Wednesday, August 2, 2000 * * Modifications: * *------------------------------------------------------------------------- */ 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) { herr_t ret_value = SUCCEED; FUNC_ENTER_API(H5set_free_list_limits, FAIL) 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)<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() */ /*------------------------------------------------------------------------- * 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. *------------------------------------------------------------------------- */ static void H5_debug_mask(const char *s) { 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=(size_t)H5_NPKGS) fprintf(stderr, "HDF5_DEBUG: ignored %s\n", pkg_name); } } else if (HDisdigit(*s)) { int fd = (int)HDstrtol (s, &rest, 0); if ((stream=HDfdopen(fd, "w"))!=NULL) (void)HDsetvbuf (stream, NULL, _IOLBF, (size_t)0); s = rest; } else { s++; } } } /* end H5_debug_mask() */ /*------------------------------------------------------------------------- * 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. * * 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) * * 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 * *------------------------------------------------------------------------- */ herr_t H5get_libversion(unsigned *majnum, unsigned *minnum, unsigned *relnum) { herr_t ret_value = SUCCEED; FUNC_ENTER_API(H5get_libversion, FAIL) H5TRACE3("e", "*Iu*Iu*Iu", 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; done: FUNC_LEAVE_API(ret_value) } /* end H5get_libversion() */ /*------------------------------------------------------------------------- * 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. * * Return: Success: SUCCEED * * Failure: abort() * * Programmer: Robb Matzke * Tuesday, April 21, 1998 * * Modifications: * Albert Cheng, May 12, 2001 * Added verification of H5_VERS_INFO. * *------------------------------------------------------------------------- */ #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" \ "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 int disable_version_check = 0; /* Set if the version check should be disabled */ herr_t ret_value=SUCCEED; /* Return value */ FUNC_ENTER_API_NOINIT_NOFS(H5check_version) H5TRACE3("e", "IuIuIu", majnum, minnum, relnum); /* Don't check again, if we already have */ if (checked) HGOTO_DONE(SUCCEED) { const char *s; /* Environment string for disabling version check */ /* Allow different versions of the header files and library? */ s = HDgetenv ("HDF5_DISABLE_VERSION_CHECK"); if (s && HDisdigit(*s)) disable_version_check = (int)HDstrtol (s, NULL, 0); } if (H5_VERS_MAJOR!=majnum || H5_VERS_MINOR!=minnum || H5_VERS_RELEASE!=relnum) { switch (disable_version_check) { case 0: HDfputs (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 will suppress the warning messages totally.\n", stderr); /* 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 2: /* continue silently */ break; default: /* continue with a warning */ HDfprintf (stderr, VERSION_MISMATCH_WARNING "'HDF5_DISABLE_VERSION_CHECK' " "environment variable is set to %d, application will\n" "continue at your own risk.\n", 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; } /* end switch */ } /* end if */ /* 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. */ sprintf(lib_str, "HDF5 library version: %d.%d.%d", H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE); if (*substr){ HDstrcat(lib_str, "-"); 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 */ } done: FUNC_LEAVE_API_NOFS(ret_value) } /* end H5check_version() */ /*------------------------------------------------------------------------- * Function: H5open * * Purpose: Initialize the library. This is normally called * automatically, but if you find that an HDF5 library function * 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: * *------------------------------------------------------------------------- */ herr_t H5open(void) { herr_t ret_value=SUCCEED; /* Return value */ FUNC_ENTER_API_NOCLEAR(H5open, FAIL) H5TRACE0("e",""); /* all work is done by FUNC_ENTER() */ done: FUNC_LEAVE_API(ret_value) } /* end H5open() */ /*------------------------------------------------------------------------- * Function: H5close * * Purpose: Terminate the library and release all resources. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Friday, January 30, 1998 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5close(void) { /* * Don't call normal FUNC_ENTER() since we don't want to initialize the * whole library just to release it all right away. It is safe to call * this function for an uninitialized library. */ FUNC_ENTER_API_NOINIT_NOFS(H5close) H5TRACE0("e",""); H5_term_library(); FUNC_LEAVE_API_NOFS(SUCCEED) } /* end H5close() */