/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * H5Iint.c - Private routines for handling IDs */ /****************/ /* Module Setup */ /****************/ #include "H5Imodule.h" /* This source code file is part of the H5I module */ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free Lists */ #include "H5Ipkg.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ #include "H5Tprivate.h" /* Datatypes */ #include "H5VLprivate.h" /* Virtual Object Layer */ /****************/ /* Local Macros */ /****************/ /* Combine a Type number and an ID index into an ID */ #define H5I_MAKE(g, i) ((((hid_t)(g)&TYPE_MASK) << ID_BITS) | ((hid_t)(i)&ID_MASK)) /******************/ /* Local Typedefs */ /******************/ /* User data for iterator callback for retrieving an ID corresponding to an object pointer */ typedef struct { const void *object; /* object pointer to search for */ H5I_type_t obj_type; /* type of object we are searching for */ hid_t ret_id; /* ID returned */ } H5I_get_id_ud_t; /* User data for iterator callback for ID iteration */ typedef struct { H5I_search_func_t user_func; /* 'User' function to invoke */ void *user_udata; /* User data to pass to 'user' function */ hbool_t app_ref; /* Whether this is an appl. ref. call */ H5I_type_t obj_type; /* Type of object we are iterating over */ } H5I_iterate_ud_t; /* User data for H5I__clear_type_cb */ typedef struct { H5I_type_info_t *type_info; /* Pointer to the type's info to be cleared */ hbool_t force; /* Whether to always remove the ID */ hbool_t app_ref; /* Whether this is an appl. ref. call */ } H5I_clear_type_ud_t; /********************/ /* Package Typedefs */ /********************/ /********************/ /* Local Prototypes */ /********************/ static void *H5I__unwrap(void *object, H5I_type_t type); static herr_t H5I__mark_node(void *_id, void *key, void *udata); static void *H5I__remove_common(H5I_type_info_t *type_info, hid_t id); static int H5I__dec_ref(hid_t id, void **request); static int H5I__dec_app_ref(hid_t id, void **request); static int H5I__dec_app_ref_always_close(hid_t id, void **request); static int H5I__find_id_cb(void *_item, void *_key, void *_udata); /*********************/ /* Package Variables */ /*********************/ /* Declared extern in H5Ipkg.h and documented there */ H5I_type_info_t *H5I_type_info_array_g[H5I_MAX_NUM_TYPES]; int H5I_next_type_g = (int)H5I_NTYPES; /* Declare a free list to manage the H5I_id_info_t struct */ H5FL_DEFINE_STATIC(H5I_id_info_t); /* Whether deletes are actually marks (for mark-and-sweep) */ hbool_t H5I_marking_g = FALSE; /*****************************/ /* Library Private Variables */ /*****************************/ /*******************/ /* Local Variables */ /*******************/ /*------------------------------------------------------------------------- * Function: H5I_term_package * * Purpose: Terminate the H5I interface: release all memory, reset all * global variables to initial values. This only happens if all * types have been destroyed from other interfaces. * * Return: Success: Positive if any action was taken that might * affect some other interface; zero otherwise. * * Failure: Negative * *------------------------------------------------------------------------- */ int H5I_term_package(void) { int in_use = 0; /* Number of ID types still in use */ FUNC_ENTER_NOAPI_NOINIT_NOERR H5I_type_info_t *type_info = NULL; /* Pointer to ID type */ int i; /* Count the number of types still in use */ for (i = 0; i < H5I_next_type_g; i++) if ((type_info = H5I_type_info_array_g[i]) && type_info->hash_table) in_use++; /* If no types are still being used then clean up */ if (0 == in_use) { for (i = 0; i < H5I_next_type_g; i++) { type_info = H5I_type_info_array_g[i]; if (type_info) { HDassert(NULL == type_info->hash_table); type_info = H5MM_xfree(type_info); H5I_type_info_array_g[i] = NULL; in_use++; } } } FUNC_LEAVE_NOAPI(in_use) } /* end H5I_term_package() */ /*------------------------------------------------------------------------- * Function: H5I_register_type * * Purpose: Creates a new type of ID's to give out. * The class is initialized or its reference count is incremented * (if it is already initialized). * * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ herr_t H5I_register_type(const H5I_class_t *cls) { H5I_type_info_t *type_info = NULL; /* Pointer to the ID type*/ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ HDassert(cls); HDassert(cls->type > 0 && (int)cls->type < H5I_MAX_NUM_TYPES); /* Initialize the type */ if (NULL == H5I_type_info_array_g[cls->type]) { /* Allocate the type information for new type */ if (NULL == (type_info = (H5I_type_info_t *)H5MM_calloc(sizeof(H5I_type_info_t)))) HGOTO_ERROR(H5E_ID, H5E_CANTALLOC, FAIL, "ID type allocation failed") H5I_type_info_array_g[cls->type] = type_info; } else { /* Get the pointer to the existing type */ type_info = H5I_type_info_array_g[cls->type]; } /* Initialize the ID type structure for new types */ if (type_info->init_count == 0) { type_info->cls = cls; type_info->id_count = 0; type_info->nextid = cls->reserved; type_info->last_id_info = NULL; type_info->hash_table = NULL; } /* Increment the count of the times this type has been initialized */ type_info->init_count++; done: /* Clean up on error */ if (ret_value < 0) if (type_info) H5MM_free(type_info); FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_register_type() */ /*------------------------------------------------------------------------- * Function: H5I_nmembers * * Purpose: Returns the number of members in a type. * * Return: Success: Number of members; zero if the type is empty * or has been deleted. * * Failure: Negative * * Programmer: Robb Matzke * Wednesday, March 24, 1999 * *------------------------------------------------------------------------- */ int64_t H5I_nmembers(H5I_type_t type) { H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */ int64_t ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI((-1)) /* Validate parameter */ if (type <= H5I_BADID || (int)type >= H5I_next_type_g) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number") if (NULL == (type_info = H5I_type_info_array_g[type]) || type_info->init_count <= 0) HGOTO_DONE(0); /* Set return value */ H5_CHECKED_ASSIGN(ret_value, int64_t, type_info->id_count, uint64_t); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_nmembers() */ /*------------------------------------------------------------------------- * Function: H5I__unwrap * * Purpose: Unwraps the object pointer for the 'item' that corresponds * to an ID. * * Return: Pointer to the unwrapped pointer (can't fail) * * Programmer: Quincey Koziol * Friday, October 19, 2018 * *------------------------------------------------------------------------- */ static void * H5I__unwrap(void *object, H5I_type_t type) { void *ret_value = NULL; /* Return value */ FUNC_ENTER_PACKAGE_NOERR /* Sanity checks */ HDassert(object); /* The stored object pointer might be an H5VL_object_t, in which * case we'll need to get the wrapped object struct (H5F_t *, etc.). */ if (H5I_FILE == type || H5I_GROUP == type || H5I_DATASET == type || H5I_ATTR == type) { const H5VL_object_t *vol_obj; vol_obj = (const H5VL_object_t *)object; ret_value = H5VL_object_data(vol_obj); } else if (H5I_DATATYPE == type) { H5T_t *dt = (H5T_t *)object; ret_value = (void *)H5T_get_actual_type(dt); } else ret_value = object; FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__unwrap() */ /*------------------------------------------------------------------------- * Function: H5I_clear_type * * Purpose: Removes all objects from the type, calling the free * function for each object regardless of the reference count. * * Return: SUCCEED/FAIL * * Programmer: Robb Matzke * Wednesday, March 24, 1999 * *------------------------------------------------------------------------- */ herr_t H5I_clear_type(H5I_type_t type, hbool_t force, hbool_t app_ref) { H5I_clear_type_ud_t udata; /* udata struct for callback */ H5I_id_info_t *item = NULL; H5I_id_info_t *tmp = NULL; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Validate parameters */ if (type <= H5I_BADID || (int)type >= H5I_next_type_g) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number") udata.type_info = H5I_type_info_array_g[type]; if (udata.type_info == NULL || udata.type_info->init_count <= 0) HGOTO_ERROR(H5E_ID, H5E_BADGROUP, FAIL, "invalid type") /* Finish constructing udata */ udata.force = force; udata.app_ref = app_ref; /* Clearing a type is done in two phases (mark-and-sweep). This is because * the type's free callback can free other IDs, potentially corrupting * the data structure during the traversal. */ /* Set marking flag */ H5I_marking_g = TRUE; /* Mark nodes for deletion */ HASH_ITER(hh, udata.type_info->hash_table, item, tmp) { if (!item->marked) if (H5I__mark_node((void *)item, NULL, (void *)&udata) < 0) HGOTO_ERROR(H5E_ID, H5E_BADITER, FAIL, "iteration failed while clearing the ID type") } /* Unset marking flag */ H5I_marking_g = FALSE; /* Perform sweep */ HASH_ITER(hh, udata.type_info->hash_table, item, tmp) { if (item->marked) { HASH_DELETE(hh, udata.type_info->hash_table, item); item = H5FL_FREE(H5I_id_info_t, item); } } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_clear_type() */ /*------------------------------------------------------------------------- * Function: H5I__mark_node * * Purpose: Attempts to mark the node for freeing and calls the free * function for the object, if any * * Return: SUCCEED/FAIL * * Programmer: Neil Fortner * Friday, July 10, 2015 * *------------------------------------------------------------------------- */ static herr_t H5I__mark_node(void *_info, void H5_ATTR_UNUSED *key, void *_udata) { H5I_id_info_t *info = (H5I_id_info_t *)_info; /* Current ID info being worked with */ H5I_clear_type_ud_t *udata = (H5I_clear_type_ud_t *)_udata; /* udata struct */ hbool_t mark = FALSE; FUNC_ENTER_PACKAGE_NOERR /* Sanity checks */ HDassert(info); HDassert(udata); HDassert(udata->type_info); /* Do nothing to the object if the reference count is larger than * one and forcing is off. */ if (udata->force || (info->count - (!udata->app_ref * info->app_count)) <= 1) { /* Check if this is an un-realized future object */ H5_GCC_CLANG_DIAG_OFF("cast-qual") if (info->is_future) { /* Discard the future object */ if ((info->discard_cb)((void *)info->object) < 0) { if (udata->force) { #ifdef H5I_DEBUG if (H5DEBUG(I)) { HDfprintf(H5DEBUG(I), "H5I: discard type=%d obj=0x%08lx " "failure ignored\n", (int)udata->type_info->cls->type, (unsigned long)(info->object)); } #endif /* H5I_DEBUG */ /* Indicate node should be removed from list */ mark = TRUE; } } else { /* Indicate node should be removed from list */ mark = TRUE; } } else { /* Check for a 'free' function and call it, if it exists */ if (udata->type_info->cls->free_func && (udata->type_info->cls->free_func)((void *)info->object, H5_REQUEST_NULL) < 0) { if (udata->force) { #ifdef H5I_DEBUG if (H5DEBUG(I)) { HDfprintf(H5DEBUG(I), "H5I: free type=%d obj=0x%08lx " "failure ignored\n", (int)udata->type_info->cls->type, (unsigned long)(info->object)); } #endif /* H5I_DEBUG */ /* Indicate node should be removed from list */ mark = TRUE; } } else { /* Indicate node should be removed from list */ mark = TRUE; } } H5_GCC_CLANG_DIAG_ON("cast-qual") /* Remove ID if requested */ if (mark) { /* Mark ID for deletion */ info->marked = TRUE; /* Decrement the number of IDs in the type */ udata->type_info->id_count--; } } FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5I__mark_node() */ /*------------------------------------------------------------------------- * Function: H5I__destroy_type * * Purpose: Destroys a type along with all IDs in that type * regardless of their reference counts. Destroying IDs * involves calling the free-func for each ID's object and * then adding the ID struct to the ID free list. * * Return: SUCCEED/FAIL * * Programmer: Nathaniel Furrer * James Laird * *------------------------------------------------------------------------- */ herr_t H5I__destroy_type(H5I_type_t type) { H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Validate parameter */ if (type <= H5I_BADID || (int)type >= H5I_next_type_g) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number") type_info = H5I_type_info_array_g[type]; if (type_info == NULL || type_info->init_count <= 0) HGOTO_ERROR(H5E_ID, H5E_BADGROUP, FAIL, "invalid type") /* Close/clear/destroy all IDs for this type */ H5E_BEGIN_TRY { H5I_clear_type(type, TRUE, FALSE); } H5E_END_TRY /* don't care about errors */ /* Check if we should release the ID class */ if (type_info->cls->flags & H5I_CLASS_IS_APPLICATION) type_info->cls = H5MM_xfree_const(type_info->cls); HASH_CLEAR(hh, type_info->hash_table); type_info->hash_table = NULL; type_info = H5MM_xfree(type_info); H5I_type_info_array_g[type] = NULL; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__destroy_type() */ /*------------------------------------------------------------------------- * Function: H5I__register * * Purpose: Registers an OBJECT in a TYPE and returns an ID for it. * This routine does _not_ check for unique-ness of the objects, * if you register an object twice, you will get two different * IDs for it. This routine does make certain that each ID in a * type is unique. IDs are created by getting a unique number * for the type the ID is in and incorporating the TYPE into * the ID which is returned to the user. * * IDs are marked as "future" if the realize_cb and discard_cb * parameters are non-NULL. * * Return: Success: New object ID * Failure: H5I_INVALID_HID * *------------------------------------------------------------------------- */ hid_t H5I__register(H5I_type_t type, const void *object, hbool_t app_ref, H5I_future_realize_func_t realize_cb, H5I_future_discard_func_t discard_cb) { H5I_type_info_t *type_info = NULL; /* Pointer to the type */ H5I_id_info_t *info = NULL; /* Pointer to the new ID information */ hid_t new_id = H5I_INVALID_HID; /* New ID */ hid_t ret_value = H5I_INVALID_HID; /* Return value */ FUNC_ENTER_PACKAGE /* Check arguments */ if (type <= H5I_BADID || (int)type >= H5I_next_type_g) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, H5I_INVALID_HID, "invalid type number") type_info = H5I_type_info_array_g[type]; if ((NULL == type_info) || (type_info->init_count <= 0)) HGOTO_ERROR(H5E_ID, H5E_BADGROUP, H5I_INVALID_HID, "invalid type") if (NULL == (info = H5FL_CALLOC(H5I_id_info_t))) HGOTO_ERROR(H5E_ID, H5E_NOSPACE, H5I_INVALID_HID, "memory allocation failed") /* Create the struct & its ID */ new_id = H5I_MAKE(type, type_info->nextid); info->id = new_id; info->count = 1; /* initial reference count */ info->app_count = !!app_ref; info->object = object; info->is_future = (NULL != realize_cb); info->realize_cb = realize_cb; info->discard_cb = discard_cb; info->marked = FALSE; /* Insert into the type */ HASH_ADD(hh, type_info->hash_table, id, sizeof(hid_t), info); type_info->id_count++; type_info->nextid++; /* Sanity check for the 'nextid' getting too large and wrapping around */ HDassert(type_info->nextid <= ID_MASK); /* Set the most recent ID to this object */ type_info->last_id_info = info; /* Set return value */ ret_value = new_id; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__register() */ /*------------------------------------------------------------------------- * Function: H5I_register * * Purpose: Library-private wrapper for H5I__register. * * Return: Success: New object ID * Failure: H5I_INVALID_HID * *------------------------------------------------------------------------- */ hid_t H5I_register(H5I_type_t type, const void *object, hbool_t app_ref) { hid_t ret_value = H5I_INVALID_HID; /* Return value */ FUNC_ENTER_NOAPI(H5I_INVALID_HID) /* Sanity checks */ HDassert(type >= H5I_FILE && type < H5I_NTYPES); HDassert(object); /* Retrieve ID for object */ if (H5I_INVALID_HID == (ret_value = H5I__register(type, object, app_ref, NULL, NULL))) HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register object") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_register() */ /*------------------------------------------------------------------------- * Function: H5I_register_using_existing_id * * Purpose: Registers an OBJECT in a TYPE with the supplied ID for it. * This routine will check to ensure the supplied ID is not already * in use, and ensure that it is a valid ID for the given type, * but will NOT check to ensure the OBJECT is not already * registered (thus, it is possible to register one object under * multiple IDs). * * NOTE: Intended for use in refresh calls, where we have to close * and re-open the underlying data, then hook the object back * up to the original ID. * * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ herr_t H5I_register_using_existing_id(H5I_type_t type, void *object, hbool_t app_ref, hid_t existing_id) { H5I_type_info_t *type_info = NULL; /* Pointer to the type */ H5I_id_info_t *info = NULL; /* Pointer to the new ID information */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Check arguments */ HDassert(object); /* Make sure ID is not already in use */ if (NULL != (info = H5I__find_id(existing_id))) HGOTO_ERROR(H5E_ID, H5E_BADRANGE, FAIL, "ID already in use") /* Make sure type number is valid */ if (type <= H5I_BADID || (int)type >= H5I_next_type_g) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number") /* Get type pointer from list of types */ type_info = H5I_type_info_array_g[type]; if (NULL == type_info || type_info->init_count <= 0) HGOTO_ERROR(H5E_ID, H5E_BADGROUP, FAIL, "invalid type") /* Make sure requested ID belongs to object's type */ if (H5I_TYPE(existing_id) != type) HGOTO_ERROR(H5E_ID, H5E_BADRANGE, FAIL, "invalid type for provided ID") /* Allocate new structure to house this ID */ if (NULL == (info = H5FL_CALLOC(H5I_id_info_t))) HGOTO_ERROR(H5E_ID, H5E_NOSPACE, FAIL, "memory allocation failed") /* Create the struct & insert requested ID */ info->id = existing_id; info->count = 1; /* initial reference count*/ info->app_count = !!app_ref; info->object = object; /* This API call is only used by the native VOL connector, which is * not asynchronous. */ info->is_future = FALSE; info->realize_cb = NULL; info->discard_cb = NULL; info->marked = FALSE; /* Insert into the type */ HASH_ADD(hh, type_info->hash_table, id, sizeof(hid_t), info); type_info->id_count++; /* Set the most recent ID to this object */ type_info->last_id_info = info; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_register_using_existing_id() */ /*------------------------------------------------------------------------- * Function: H5I_subst * * Purpose: Substitute a new object pointer for the specified ID. * * Return: Success: Non-NULL previous object pointer associated * with the specified ID. * Failure: NULL * * Programmer: Quincey Koziol * Saturday, February 27, 2010 * *------------------------------------------------------------------------- */ void * H5I_subst(hid_t id, const void *new_object) { H5I_id_info_t *info = NULL; /* Pointer to the ID's info */ void *ret_value = NULL; /* Return value */ FUNC_ENTER_NOAPI(NULL) /* General lookup of the ID */ if (NULL == (info = H5I__find_id(id))) HGOTO_ERROR(H5E_ID, H5E_NOTFOUND, NULL, "can't get ID ref count") /* Get the old object pointer to return */ H5_GCC_CLANG_DIAG_OFF("cast-qual") ret_value = (void *)info->object; H5_GCC_CLANG_DIAG_ON("cast-qual") /* Set the new object pointer for the ID */ info->object = new_object; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_subst() */ /*------------------------------------------------------------------------- * Function: H5I_object * * Purpose: Find an object pointer for the specified ID. * * Return: Success: Non-NULL object pointer associated with the * specified ID * * Failure: NULL * *------------------------------------------------------------------------- */ void * H5I_object(hid_t id) { H5I_id_info_t *info = NULL; /* Pointer to the ID info */ void *ret_value = NULL; /* Return value */ FUNC_ENTER_NOAPI_NOERR /* General lookup of the ID */ if (NULL != (info = H5I__find_id(id))) { /* Get the object pointer to return */ H5_GCC_CLANG_DIAG_OFF("cast-qual") ret_value = (void *)info->object; H5_GCC_CLANG_DIAG_ON("cast-qual") } FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_object() */ /*------------------------------------------------------------------------- * Function: H5I_object_verify * * Purpose: Find an object pointer for the specified ID, verifying that * its in a particular type. * * Return: Success: Non-NULL object pointer associated with the * specified ID. * Failure: NULL * * Programmer: Quincey Koziol * Wednesday, July 31, 2002 * *------------------------------------------------------------------------- */ void * H5I_object_verify(hid_t id, H5I_type_t type) { H5I_id_info_t *info = NULL; /* Pointer to the ID info */ void *ret_value = NULL; /* Return value */ FUNC_ENTER_NOAPI_NOERR HDassert(type >= 1 && (int)type < H5I_next_type_g); /* Verify that the type of the ID is correct & lookup the ID */ if (type == H5I_TYPE(id) && NULL != (info = H5I__find_id(id))) { /* Get the object pointer to return */ H5_GCC_CLANG_DIAG_OFF("cast-qual") ret_value = (void *)info->object; H5_GCC_CLANG_DIAG_ON("cast-qual") } FUNC_LEAVE_NOAPI(ret_value) } /* H5I_object_verify() */ /*------------------------------------------------------------------------- * Function: H5I_get_type * * Purpose: Given an object ID return the type to which it * belongs. The ID need not be the ID of an object which * currently exists because the type number is encoded * in the object ID. * * Return: Success: A positive integer (corresponding to an H5I_type_t * enum value for library ID types, but not for user * ID types). * Failure: H5I_BADID * * Programmer: Robb Matzke * Friday, February 19, 1999 * *------------------------------------------------------------------------- */ H5I_type_t H5I_get_type(hid_t id) { H5I_type_t ret_value = H5I_BADID; /* Return value */ FUNC_ENTER_NOAPI_NOERR if (id > 0) ret_value = H5I_TYPE(id); HDassert(ret_value >= H5I_BADID && (int)ret_value < H5I_next_type_g); FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_get_type() */ /*------------------------------------------------------------------------- * Function: H5I_is_file_object * * Purpose: Convenience function to determine if an ID represents * a file object. * * In H5O calls, you can't use object_verify to ensure * the ID was of the correct class since there's no * H5I_OBJECT ID class. * * Return: Success: TRUE/FALSE * Failure: FAIL * *------------------------------------------------------------------------- */ htri_t H5I_is_file_object(hid_t id) { H5I_type_t type = H5I_get_type(id); htri_t ret_value = FAIL; FUNC_ENTER_NOAPI(FAIL); /* Fail if the ID type is out of range */ if (type < 1 || type >= H5I_NTYPES) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "ID type out of range"); /* Return TRUE if the ID is a file object (dataset, group, map, or committed * datatype), FALSE otherwise. */ if (H5I_DATASET == type || H5I_GROUP == type || H5I_MAP == type) ret_value = TRUE; else if (H5I_DATATYPE == type) { H5T_t *dt = NULL; if (NULL == (dt = (H5T_t *)H5I_object(id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unable to get underlying datatype struct"); ret_value = H5T_is_named(dt); } else ret_value = FALSE; done: FUNC_LEAVE_NOAPI(ret_value); } /* H5I_is_file_object() */ /*------------------------------------------------------------------------- * Function: H5I__remove_verify * * Purpose: Removes the specified ID from its type, first checking that * the ID's type is the same as the ID type supplied as an argument * * Return: Success: A pointer to the object that was removed, the * same pointer which would have been found by * calling H5I_object(). * Failure: NULL * * Programmer: James Laird * Nat Furrer * *------------------------------------------------------------------------- */ void * H5I__remove_verify(hid_t id, H5I_type_t type) { void *ret_value = NULL; /*return value */ FUNC_ENTER_PACKAGE_NOERR /* Argument checking will be performed by H5I_remove() */ /* Verify that the type of the ID is correct */ if (type == H5I_TYPE(id)) ret_value = H5I_remove(id); FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__remove_verify() */ /*------------------------------------------------------------------------- * Function: H5I__remove_common * * Purpose: Common code to remove a specified ID from its type. * * Return: Success: A pointer to the object that was removed, the * same pointer which would have been found by * calling H5I_object(). * Failure: NULL * * Programmer: Quincey Koziol * October 3, 2013 * *------------------------------------------------------------------------- */ static void * H5I__remove_common(H5I_type_info_t *type_info, hid_t id) { H5I_id_info_t *info = NULL; /* Pointer to the current ID */ void *ret_value = NULL; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(type_info); /* Delete or mark the node */ HASH_FIND(hh, type_info->hash_table, &id, sizeof(hid_t), info); if (info) { HDassert(!info->marked); if (!H5I_marking_g) HASH_DELETE(hh, type_info->hash_table, info); else info->marked = TRUE; } else HGOTO_ERROR(H5E_ID, H5E_CANTDELETE, NULL, "can't remove ID node from hash table") /* Check if this ID was the last one accessed */ if (type_info->last_id_info == info) type_info->last_id_info = NULL; H5_GCC_CLANG_DIAG_OFF("cast-qual") ret_value = (void *)info->object; H5_GCC_CLANG_DIAG_ON("cast-qual") if (!H5I_marking_g) info = H5FL_FREE(H5I_id_info_t, info); /* Decrement the number of IDs in the type */ (type_info->id_count)--; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__remove_common() */ /*------------------------------------------------------------------------- * Function: H5I_remove * * Purpose: Removes the specified ID from its type. * * Return: Success: A pointer to the object that was removed, the * same pointer which would have been found by * calling H5I_object(). * Failure: NULL * *------------------------------------------------------------------------- */ void * H5I_remove(hid_t id) { H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */ H5I_type_t type = H5I_BADID; /* ID's type */ void *ret_value = NULL; /* Return value */ FUNC_ENTER_NOAPI(NULL) /* Check arguments */ type = H5I_TYPE(id); if (type <= H5I_BADID || (int)type >= H5I_next_type_g) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid type number") type_info = H5I_type_info_array_g[type]; if (type_info == NULL || type_info->init_count <= 0) HGOTO_ERROR(H5E_ID, H5E_BADGROUP, NULL, "invalid type") /* Remove the node from the type */ if (NULL == (ret_value = H5I__remove_common(type_info, id))) HGOTO_ERROR(H5E_ID, H5E_CANTDELETE, NULL, "can't remove ID node") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_remove() */ /*------------------------------------------------------------------------- * Function: H5I__dec_ref * * Purpose: This will fail if the type is not a reference counted type. * The ID type's 'free' function will be called for the ID * if the reference count for the ID reaches 0 and a free * function has been defined at type creation time. * * Note: Allows for asynchronous 'close' operation on object, with * request != H5_REQUEST_NULL. * * Return: Success: New reference count * Failure: -1 * *------------------------------------------------------------------------- */ static int H5I__dec_ref(hid_t id, void **request) { H5I_id_info_t *info = NULL; /* Pointer to the ID */ int ret_value = 0; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(id >= 0); /* General lookup of the ID */ if (NULL == (info = H5I__find_id(id))) HGOTO_ERROR(H5E_ID, H5E_BADID, (-1), "can't locate ID") /* If this is the last reference to the object then invoke the type's * free method on the object. If the free method is undefined or * successful then remove the object from the type; otherwise leave * the object in the type without decrementing the reference * count. If the reference count is more than one then decrement the * reference count without calling the free method. * * Beware: the free method may call other H5I functions. * * If an object is closing, we can remove the ID even though the free * method might fail. This can happen when a mandatory filter fails to * write when a dataset is closed and the chunk cache is flushed to the * file. We have to close the dataset anyway. (SLU - 2010/9/7) */ if (1 == info->count) { H5I_type_info_t *type_info; /*ptr to the type */ /* Get the ID's type */ type_info = H5I_type_info_array_g[H5I_TYPE(id)]; H5_GCC_CLANG_DIAG_OFF("cast-qual") if (!type_info->cls->free_func || (type_info->cls->free_func)((void *)info->object, request) >= 0) { /* Remove the node from the type */ if (NULL == H5I__remove_common(type_info, id)) HGOTO_ERROR(H5E_ID, H5E_CANTDELETE, (-1), "can't remove ID node") ret_value = 0; } /* end if */ else ret_value = -1; H5_GCC_CLANG_DIAG_ON("cast-qual") } /* end if */ else { --(info->count); ret_value = (int)info->count; } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__dec_ref */ /*------------------------------------------------------------------------- * Function: H5I_dec_ref * * Purpose: Decrements the number of references outstanding for an ID. * * Return: Success: New reference count * Failure: -1 * *------------------------------------------------------------------------- */ int H5I_dec_ref(hid_t id) { int ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI((-1)) /* Sanity check */ HDassert(id >= 0); /* Synchronously decrement refcount on ID */ if ((ret_value = H5I__dec_ref(id, H5_REQUEST_NULL)) < 0) HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_dec_ref() */ /*------------------------------------------------------------------------- * Function: H5I__dec_app_ref * * Purpose: Wrapper for case of modifying the application ref. * count for an ID as well as normal reference count. * * Note: Allows for asynchronous 'close' operation on object, with * request != H5_REQUEST_NULL. * * Return: Success: New app. reference count * Failure: -1 * *------------------------------------------------------------------------- */ static int H5I__dec_app_ref(hid_t id, void **request) { int ret_value = 0; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(id >= 0); /* Call regular decrement reference count routine */ if ((ret_value = H5I__dec_ref(id, request)) < 0) HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count") /* Check if the ID still exists */ if (ret_value > 0) { H5I_id_info_t *info = NULL; /* Pointer to the ID info */ /* General lookup of the ID */ if (NULL == (info = H5I__find_id(id))) HGOTO_ERROR(H5E_ID, H5E_BADID, (-1), "can't locate ID") /* Adjust app_ref */ --(info->app_count); HDassert(info->count >= info->app_count); /* Set return value */ ret_value = (int)info->app_count; } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__dec_app_ref() */ /*------------------------------------------------------------------------- * Function: H5I_dec_app_ref * * Purpose: Wrapper for case of modifying the application ref. count for * an ID as well as normal reference count. * * Return: Success: New app. reference count * Failure: -1 * * Programmer: Quincey Koziol * Sept 16, 2010 * *------------------------------------------------------------------------- */ int H5I_dec_app_ref(hid_t id) { int ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI((-1)) /* Sanity check */ HDassert(id >= 0); /* Synchronously decrement refcount on ID */ if ((ret_value = H5I__dec_app_ref(id, H5_REQUEST_NULL)) < 0) HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_dec_app_ref() */ /*------------------------------------------------------------------------- * Function: H5I_dec_app_ref_async * * Purpose: Asynchronous wrapper for case of modifying the application ref. * count for an ID as well as normal reference count. * * Note: Allows for asynchronous 'close' operation on object, with * token != H5_REQUEST_NULL. * * Return: Success: New app. reference count * Failure: -1 * * Programmer: Houjun Tang * Oct 21, 2019 * *------------------------------------------------------------------------- */ int H5I_dec_app_ref_async(hid_t id, void **token) { int ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI((-1)) /* Sanity check */ HDassert(id >= 0); /* [Possibly] aynchronously decrement refcount on ID */ if ((ret_value = H5I__dec_app_ref(id, token)) < 0) HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't asynchronously decrement ID ref count") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_dec_app_ref_async() */ /*------------------------------------------------------------------------- * Function: H5I__dec_app_ref_always_close * * Purpose: Wrapper for case of always closing the ID, even when the free * routine fails * * Note: Allows for asynchronous 'close' operation on object, with * request != H5_REQUEST_NULL. * * Return: Success: New app. reference count * Failure: -1 * *------------------------------------------------------------------------- */ static int H5I__dec_app_ref_always_close(hid_t id, void **request) { int ret_value = 0; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(id >= 0); /* Call application decrement reference count routine */ ret_value = H5I__dec_app_ref(id, request); /* Check for failure */ if (ret_value < 0) { /* * If an object is closing, we can remove the ID even though the free * method might fail. This can happen when a mandatory filter fails to * write when a dataset is closed and the chunk cache is flushed to the * file. We have to close the dataset anyway. (SLU - 2010/9/7) */ H5I_remove(id); HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count") } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__dec_app_ref_always_close() */ /*------------------------------------------------------------------------- * Function: H5I_dec_app_ref_always_close * * Purpose: Wrapper for case of always closing the ID, even when the free * routine fails. * * Return: Success: New app. reference count * Failure: -1 * *------------------------------------------------------------------------- */ int H5I_dec_app_ref_always_close(hid_t id) { int ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI((-1)) /* Sanity check */ HDassert(id >= 0); /* Synchronously decrement refcount on ID */ if ((ret_value = H5I__dec_app_ref_always_close(id, H5_REQUEST_NULL)) < 0) HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't decrement ID ref count") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_dec_app_ref_always_close() */ /*------------------------------------------------------------------------- * Function: H5I_dec_app_ref_always_close_async * * Purpose: Asynchronous wrapper for case of always closing the ID, even * when the free routine fails * * Note: Allows for asynchronous 'close' operation on object, with * token != H5_REQUEST_NULL. * * Return: Success: New app. reference count * Failure: -1 * *------------------------------------------------------------------------- */ int H5I_dec_app_ref_always_close_async(hid_t id, void **token) { int ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI((-1)) /* Sanity check */ HDassert(id >= 0); /* [Possibly] aynchronously decrement refcount on ID */ if ((ret_value = H5I__dec_app_ref_always_close(id, token)) < 0) HGOTO_ERROR(H5E_ID, H5E_CANTDEC, (-1), "can't asynchronously decrement ID ref count") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_dec_app_ref_always_close_async() */ /*------------------------------------------------------------------------- * Function: H5I_inc_ref * * Purpose: Increment the reference count for an object. * * Return: Success: The new reference count * Failure: -1 * *------------------------------------------------------------------------- */ int H5I_inc_ref(hid_t id, hbool_t app_ref) { H5I_id_info_t *info = NULL; /* Pointer to the ID info */ int ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI((-1)) /* Sanity check */ HDassert(id >= 0); /* General lookup of the ID */ if (NULL == (info = H5I__find_id(id))) HGOTO_ERROR(H5E_ID, H5E_BADID, (-1), "can't locate ID") /* Adjust reference counts */ ++(info->count); if (app_ref) ++(info->app_count); /* Set return value */ ret_value = (int)(app_ref ? info->app_count : info->count); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_inc_ref() */ /*------------------------------------------------------------------------- * Function: H5I_get_ref * * Purpose: Retrieve the reference count for an object. * * Return: Success: The reference count * Failure: -1 * *------------------------------------------------------------------------- */ int H5I_get_ref(hid_t id, hbool_t app_ref) { H5I_id_info_t *info = NULL; /* Pointer to the ID */ int ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI((-1)) /* Sanity check */ HDassert(id >= 0); /* General lookup of the ID */ if (NULL == (info = H5I__find_id(id))) HGOTO_ERROR(H5E_ID, H5E_BADID, (-1), "can't locate ID") /* Set return value */ ret_value = (int)(app_ref ? info->app_count : info->count); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_get_ref() */ /*------------------------------------------------------------------------- * Function: H5I__inc_type_ref * * Purpose: Increment the reference count for an ID type. * * Return: Success: The new reference count * Failure: -1 * *------------------------------------------------------------------------- */ int H5I__inc_type_ref(H5I_type_t type) { H5I_type_info_t *type_info = NULL; /* Pointer to the type */ int ret_value = -1; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(type > 0 && (int)type < H5I_next_type_g); /* Check arguments */ type_info = H5I_type_info_array_g[type]; if (NULL == type_info) HGOTO_ERROR(H5E_ID, H5E_BADGROUP, (-1), "invalid type") /* Set return value */ ret_value = (int)(++(type_info->init_count)); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__inc_type_ref() */ /*------------------------------------------------------------------------- * Function: H5I_dec_type_ref * * Purpose: Decrements the reference count on an entire type of IDs. * If the type reference count becomes zero then the type is * destroyed along with all IDs in that type regardless of * their reference counts. Destroying IDs involves calling * the free-func for each ID's object and then adding the ID * struct to the ID free list. * Returns the number of references to the type on success; a * return value of 0 means that the type will have to be * re-initialized before it can be used again (and should probably * be set to H5I_UNINIT). * * Return: Success: Number of references to type * Failure: -1 * *------------------------------------------------------------------------- */ int H5I_dec_type_ref(H5I_type_t type) { H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */ herr_t ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI((-1)) if (type <= H5I_BADID || (int)type >= H5I_next_type_g) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, (-1), "invalid type number") type_info = H5I_type_info_array_g[type]; if (type_info == NULL || type_info->init_count <= 0) HGOTO_ERROR(H5E_ID, H5E_BADGROUP, (-1), "invalid type") /* Decrement the number of users of the ID type. If this is the * last user of the type then release all IDs from the type and * free all memory it used. The free function is invoked for each ID * being freed. */ if (1 == type_info->init_count) { H5I__destroy_type(type); ret_value = 0; } else { --(type_info->init_count); ret_value = (herr_t)type_info->init_count; } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_dec_type_ref() */ /*------------------------------------------------------------------------- * Function: H5I__get_type_ref * * Purpose: Retrieve the reference count for an ID type. * * Return: Success: The reference count * * Failure: -1 * *------------------------------------------------------------------------- */ int H5I__get_type_ref(H5I_type_t type) { H5I_type_info_t *type_info = NULL; /* Pointer to the type */ int ret_value = -1; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(type >= 0); /* Check arguments */ type_info = H5I_type_info_array_g[type]; if (!type_info) HGOTO_ERROR(H5E_ID, H5E_BADGROUP, (-1), "invalid type") /* Set return value */ ret_value = (int)type_info->init_count; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__get_type_ref() */ /*------------------------------------------------------------------------- * Function: H5I__iterate_cb * * Purpose: Callback routine for H5I_iterate, invokes "user" callback * function, and then sets return value, based on the result of * that callback. * * Return: Success: H5_ITER_CONT (0) or H5_ITER_STOP (1) * Failure: H5_ITER_ERROR (-1) * *------------------------------------------------------------------------- */ static int H5I__iterate_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) { H5I_id_info_t *info = (H5I_id_info_t *)_item; /* Pointer to the ID info */ H5I_iterate_ud_t *udata = (H5I_iterate_ud_t *)_udata; /* User data for callback */ int ret_value = H5_ITER_CONT; /* Callback return value */ FUNC_ENTER_PACKAGE_NOERR /* Only invoke the callback function if this ID is visible externally and * its reference count is positive. */ if ((!udata->app_ref) || (info->app_count > 0)) { H5I_type_t type = udata->obj_type; void *object; herr_t cb_ret_val; /* The stored object pointer might be an H5VL_object_t, in which * case we'll need to get the wrapped object struct (H5F_t *, etc.). */ H5_GCC_CLANG_DIAG_OFF("cast-qual") object = H5I__unwrap((void *)info->object, type); H5_GCC_CLANG_DIAG_ON("cast-qual") /* Invoke callback function */ cb_ret_val = (*udata->user_func)((void *)object, info->id, udata->user_udata); /* Set the return value based on the callback's return value */ if (cb_ret_val > 0) ret_value = H5_ITER_STOP; /* terminate iteration early */ else if (cb_ret_val < 0) ret_value = H5_ITER_ERROR; /* indicate failure (which terminates iteration) */ } FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__iterate_cb() */ /*------------------------------------------------------------------------- * Function: H5I_iterate * * Purpose: Apply function FUNC to each member of type TYPE (with * non-zero application reference count if app_ref is TRUE). * Stop if FUNC returns a non zero value (i.e. anything * other than H5_ITER_CONT). * * If FUNC returns a positive value (i.e. H5_ITER_STOP), * return SUCCEED. * * If FUNC returns a negative value (i.e. H5_ITER_ERROR), * return FAIL. * * The FUNC should take a pointer to the object and the * udata as arguments and return non-zero to terminate * siteration, and zero to continue. * * Limitation: Currently there is no way to start the iteration from * where a previous iteration left off. * * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ herr_t H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_ref) { H5I_type_info_t *type_info = NULL; /* Pointer to the type */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Check arguments */ if (type <= H5I_BADID || (int)type >= H5I_next_type_g) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number") type_info = H5I_type_info_array_g[type]; /* Only iterate through ID list if it is initialized and there are IDs in type */ if (type_info && type_info->init_count > 0 && type_info->id_count > 0) { H5I_iterate_ud_t iter_udata; /* User data for iteration callback */ H5I_id_info_t *item = NULL; H5I_id_info_t *tmp = NULL; /* Set up iterator user data */ iter_udata.user_func = func; iter_udata.user_udata = udata; iter_udata.app_ref = app_ref; iter_udata.obj_type = type; /* Iterate over IDs */ HASH_ITER(hh, type_info->hash_table, item, tmp) { if (!item->marked) { int ret = H5I__iterate_cb((void *)item, NULL, (void *)&iter_udata); if (H5_ITER_ERROR == ret) HGOTO_ERROR(H5E_ID, H5E_BADITER, FAIL, "iteration failed") if (H5_ITER_STOP == ret) break; } } } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_iterate() */ /*------------------------------------------------------------------------- * Function: H5I__find_id * * Purpose: Given an object ID find the info struct that describes the * object. * * Return: Success: A pointer to the object's info struct. * * Failure: NULL * *------------------------------------------------------------------------- */ H5I_id_info_t * H5I__find_id(hid_t id) { H5I_type_t type; /* ID's type */ H5I_type_info_t *type_info = NULL; /* Pointer to the type */ H5I_id_info_t *id_info = NULL; /* ID's info */ H5I_id_info_t *ret_value = NULL; /* Return value */ FUNC_ENTER_PACKAGE_NOERR /* Check arguments */ type = H5I_TYPE(id); if (type <= H5I_BADID || (int)type >= H5I_next_type_g) HGOTO_DONE(NULL) type_info = H5I_type_info_array_g[type]; if (!type_info || type_info->init_count <= 0) HGOTO_DONE(NULL) /* Check for same ID as we have looked up last time */ if (type_info->last_id_info && type_info->last_id_info->id == id) id_info = type_info->last_id_info; else { HASH_FIND(hh, type_info->hash_table, &id, sizeof(hid_t), id_info); /* Remember this ID */ type_info->last_id_info = id_info; } /* Check if this is a future ID */ H5_GCC_CLANG_DIAG_OFF("cast-qual") if (id_info && id_info->is_future) { hid_t actual_id = H5I_INVALID_HID; /* ID for actual object */ void *future_object; /* Pointer to the future object */ void *actual_object; /* Pointer to the actual object */ /* Invoke the realize callback, to get the actual object */ if ((id_info->realize_cb)((void *)id_info->object, &actual_id) < 0) HGOTO_DONE(NULL) /* Verify that we received a valid ID, of the same type */ if (H5I_INVALID_HID == actual_id) HGOTO_DONE(NULL) if (H5I_TYPE(id) != H5I_TYPE(actual_id)) HGOTO_DONE(NULL) /* Swap the actual object in for the future object */ future_object = (void *)id_info->object; actual_object = H5I__remove_common(type_info, actual_id); HDassert(actual_object); id_info->object = actual_object; /* Discard the future object */ if ((id_info->discard_cb)(future_object) < 0) HGOTO_DONE(NULL) future_object = NULL; /* Change the ID from 'future' to 'actual' */ id_info->is_future = FALSE; id_info->realize_cb = NULL; id_info->discard_cb = NULL; } H5_GCC_CLANG_DIAG_ON("cast-qual") /* Set return value */ ret_value = id_info; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__find_id() */ /*------------------------------------------------------------------------- * Function: H5I__find_id_cb * * Purpose: Callback for searching for an ID with a specific pointer * * Return: Success: H5_ITER_CONT (0) or H5_ITER_STOP (1) * Failure: H5_ITER_ERROR (-1) * *------------------------------------------------------------------------- */ static int H5I__find_id_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) { H5I_id_info_t *info = (H5I_id_info_t *)_item; /* Pointer to the ID info */ H5I_get_id_ud_t *udata = (H5I_get_id_ud_t *)_udata; /* Pointer to user data */ H5I_type_t type = udata->obj_type; const void *object = NULL; int ret_value = H5_ITER_CONT; /* Return value */ FUNC_ENTER_PACKAGE_NOERR /* Sanity check */ HDassert(info); HDassert(udata); /* Get a pointer to the VOL connector's data */ H5_GCC_CLANG_DIAG_OFF("cast-qual") object = H5I__unwrap((void *)info->object, type); H5_GCC_CLANG_DIAG_ON("cast-qual") /* Check for a match */ if (object == udata->object) { udata->ret_id = info->id; ret_value = H5_ITER_STOP; } FUNC_LEAVE_NOAPI(ret_value) } /* end H5I__find_id_cb() */ /*------------------------------------------------------------------------- * Function: H5I_find_id * * Purpose: Return the ID of an object by searching through the ID list * for the type. * * Return: SUCCEED/FAIL * (id will be set to H5I_INVALID_HID on errors or not found) * *------------------------------------------------------------------------- */ herr_t H5I_find_id(const void *object, H5I_type_t type, hid_t *id) { H5I_type_info_t *type_info = NULL; /* Pointer to the type */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) HDassert(id); *id = H5I_INVALID_HID; type_info = H5I_type_info_array_g[type]; if (!type_info || type_info->init_count <= 0) HGOTO_ERROR(H5E_ID, H5E_BADGROUP, FAIL, "invalid type") /* Only iterate through ID list if it is initialized and there are IDs in type */ if (type_info->init_count > 0 && type_info->id_count > 0) { H5I_get_id_ud_t udata; /* User data */ H5I_id_info_t *item = NULL; H5I_id_info_t *tmp = NULL; /* Set up iterator user data */ udata.object = object; udata.obj_type = type; udata.ret_id = H5I_INVALID_HID; /* Iterate over IDs for the ID type */ HASH_ITER(hh, type_info->hash_table, item, tmp) { int ret = H5I__find_id_cb((void *)item, NULL, (void *)&udata); if (H5_ITER_ERROR == ret) HGOTO_ERROR(H5E_ID, H5E_BADITER, FAIL, "iteration failed") if (H5_ITER_STOP == ret) break; } *id = udata.ret_id; } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_find_id() */