/**************************************************************************** * NCSA HDF * * Software Development Group * * National Center for Supercomputing Applications * * University of Illinois at Urbana-Champaign * * 605 E. Springfield, Champaign IL 61820 * * * * For conditions of distribution and use, see the accompanying * * hdf/COPYING file. * * * ****************************************************************************/ /* $Id$ */ /* * FILE: H5I.c - Internal storage routines for handling "IDs" * * REMARKS: ID's which allow objects (void *'s currently) to be bundled * into "groups" for more general storage. * * DESIGN: The groups are stored in an array of pointers to store each * group in an element. Each "group" node contains a link to a * hash table to manage the IDs in each group. The allowed * "groups" are stored in an enum (called group_t) in * H5Ipublic.h. * * AUTHOR: Quincey Koziol * * MODIFICATIONS: * 1/3/96 - Starting writing specs & coding prototype * 1/7/96 - Finished coding prototype * 6/10/97 - Moved into HDF5 library */ #include "H5private.h" #include "H5Iprivate.h" #include "H5Eprivate.h" #include "H5FLprivate.h" /*Free Lists */ #include "H5MMprivate.h" /* Interface initialialization? */ #define PABLO_MASK H5I_mask static int interface_initialize_g = 0; #define INTERFACE_INIT H5I_init_interface static herr_t H5I_init_interface(void); /*-------------------- Locally scoped variables -----------------------------*/ #ifdef IDS_ARE_CACHED /* ID Cache */ static H5I_id_info_t *H5I_cache_g[ID_CACHE_SIZE]; #endif /* Array of pointers to atomic groups */ static H5I_id_group_t *H5I_id_group_list_g[H5I_NGROUPS]; /* Declare a free list to manage the H5I_id_info_t struct */ H5FL_DEFINE_STATIC(H5I_id_info_t); /*--------------------- Local function prototypes ---------------------------*/ static H5I_id_info_t *H5I_find_id(hid_t id); #ifdef H5I_DEBUG_OUTPUT static herr_t H5I_debug(H5I_type_t grp); #endif /* H5I_DEBUG_OUTPUT */ /*------------------------------------------------------------------------- * Function: H5I_init_interface * * Purpose: Initialize interface-specific information. * * Return: Success: Non-negative * * Failure: Negative * * Programmer: * * Modifications: * *------------------------------------------------------------------------- */ static herr_t H5I_init_interface(void) { herr_t ret_value = SUCCEED; FUNC_ENTER_NOINIT(H5I_init_interface); /* * Make certain the ID types don't overflow the number of bits allocated * for them in an ID. */ assert(H5I_NGROUPS<=(1<id_list) n++; } /* If no groups are used then clean up */ if (0==n) { for (grp=(H5I_type_t)0; grp= H5I_NGROUPS) && hash_size > 0) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid group number"); #ifdef HASH_SIZE_POWER_2 if (!POWER_OF_TWO(hash_size) || hash_size == 1) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid hash size"); #endif /* HASH_SIZE_POWER_2 */ if (H5I_id_group_list_g[grp] == NULL) { /* Allocate the group information for new group */ if (NULL==(grp_ptr = H5MM_calloc(sizeof(H5I_id_group_t)))) HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); H5I_id_group_list_g[grp] = grp_ptr; } else { /* Get the pointer to the existing group */ grp_ptr = H5I_id_group_list_g[grp]; } if (grp_ptr->count == 0) { /* Initialize the ID group structure for new groups */ grp_ptr->hash_size = hash_size; grp_ptr->reserved = reserved; grp_ptr->wrapped = 0; grp_ptr->ids = 0; grp_ptr->nextid = reserved; grp_ptr->free_func = free_func; grp_ptr->id_list = H5MM_calloc(hash_size*sizeof(H5I_id_info_t *)); if (NULL==grp_ptr->id_list) HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); } /* Increment the count of the times this group has been initialized */ grp_ptr->count++; done: if (ret_value<0) { /* Error condition cleanup */ if (grp_ptr != NULL) { H5MM_xfree(grp_ptr->id_list); H5MM_xfree(grp_ptr); } } FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_nmembers * * Purpose: Returns the number of members in a group. * * Return: Success: Number of members; zero if the group is empty * or has been deleted. * * Failure: Negative * * Programmer: Robb Matzke * Wednesday, March 24, 1999 * * Modifications: * *------------------------------------------------------------------------- */ int H5I_nmembers(H5I_type_t grp) { H5I_id_group_t *grp_ptr = NULL; H5I_id_info_t *cur=NULL; int n=0; unsigned i; int ret_value; FUNC_ENTER_NOAPI(H5I_nmembers, FAIL); if (grp<=H5I_BADID || grp>=H5I_NGROUPS) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid group number"); if (NULL==(grp_ptr=H5I_id_group_list_g[grp]) || grp_ptr->count<=0) HGOTO_DONE(0); for (i=0; ihash_size; i++) for (cur=grp_ptr->id_list[i]; cur; cur=cur->next) n++; /* Set return value */ ret_value=n; done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_clear_group * * Purpose: Removes all objects from the group, calling the free * function for each object regardless of the reference count. * * Return: Success: Non-negative * * Failure: negative * * Programmer: Robb Matzke * Wednesday, March 24, 1999 * * Modifications: * Robb Matzke, 1999-04-27 * If FORCE is zero then any item for which the free callback * failed is not removed. This function returns failure if * items could not be removed. * * Robb Matzke, 1999-08-17 * If the object reference count is larger than one then it must * be because the library is using the object internally. This * happens for instance for file driver ID's which are stored in * things like property lists, files, etc. Objects that have a * reference count larger than one are not affected unless FORCE * is non-zero. *------------------------------------------------------------------------- */ herr_t H5I_clear_group(H5I_type_t grp, hbool_t force) { H5I_id_group_t *grp_ptr = NULL; /* ptr to the atomic group */ H5I_id_info_t *cur=NULL; /* Current node being worked with */ H5I_id_info_t *next=NULL; /* Next node in list */ H5I_id_info_t *last=NULL; /* Last node seen */ H5I_id_info_t *tmp=NULL; /* Temporary node ptr */ int ret_value = SUCCEED; unsigned delete_node; /* Flag to indicate node should be removed from linked list */ unsigned i,j; FUNC_ENTER_NOAPI(H5I_clear_group, FAIL); if (grp <= H5I_BADID || grp >= H5I_NGROUPS) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid group number"); grp_ptr = H5I_id_group_list_g[grp]; if (grp_ptr == NULL || grp_ptr->count <= 0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid group"); #ifdef IDS_ARE_CACHED /* * Remove atoms from the global atom cache. */ for (i=0; iid) == grp) H5I_cache_g[i] = NULL; } #endif /* IDS_ARE_CACHED */ /* * Call free method for all objects in group regardless of their reference * counts. Ignore the return value from from the free method and remove * object from group regardless if FORCE is non-zero. */ for (i=0; ihash_size; i++) { for (cur=grp_ptr->id_list[i]; cur; cur=next) { /* * Do nothing to the object if the reference count is larger than * one and forcing is off. */ if (!force && cur->count>1) continue; /* Check for a 'free' function and call it, if it exists */ if (grp_ptr->free_func && (grp_ptr->free_func)(cur->obj_ptr)<0) { if (force) { #if H5I_DEBUG if (H5DEBUG(I)) { fprintf(H5DEBUG(I), "H5I: free grp=%d obj=0x%08lx " "failure ignored\n", (int)grp, (unsigned long)(cur->obj_ptr)); } /* end if */ #endif /*H5I_DEBUG*/ /* Indicate node should be removed from list */ delete_node=1; } /* end if */ else { /* Indicate node should _NOT_ be remove from list */ delete_node=0; } /* end else */ } /* end if */ else { /* Indicate node should be removed from list */ delete_node=1; } /* end else */ /* Check if we should delete this node or not */ if(delete_node) { /* Decrement the number of IDs in the group */ (grp_ptr->ids)--; /* Advance to next node */ next = cur->next; /* Re-scan the list of nodes and remove the node from the list */ /* (can't maintain static pointers to the previous node in the */ /* list, because the node's 'free' callback could have */ /* make an H5I call, which could potentially change the */ /* order of the nodes on the list - QAK) */ last=NULL; tmp=grp_ptr->id_list[i]; while(tmp!=cur) { assert(tmp!=NULL); last=tmp; tmp=tmp->next; } /* end while */ /* Delete the node from the list */ if(last==NULL) { /* Node at head of list, just advance the list head to next node */ assert(grp_ptr->id_list[i]==cur); grp_ptr->id_list[i] = next; } /* end if */ else { /* Node in middle of list, jump over it */ assert(last->next==cur); last->next=next; } /* end else */ #ifdef IDS_ARE_CACHED /* Scan through cache & remove node, if present */ /* (node's 'free' callback function could have made an H5I */ /* call, which would probably put the node back in */ /* the cache - QAK) */ for(j=0; jnext; } /* end else */ } /* end for */ } /* end for */ done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_destroy_group * * Purpose: Decrements the reference count on an entire group of IDs. * If the group reference count becomes zero then the group is * destroyed along with all atoms in that group 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: Non-negative on success/Negative on failure * * Programmer: Unknown * * Modifications: * * Robb Matzke, 25 Feb 1998 * IDs are freed when a group is destroyed. * *------------------------------------------------------------------------- */ herr_t H5I_destroy_group(H5I_type_t grp) { H5I_id_group_t *grp_ptr = NULL; /* ptr to the atomic group */ int ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5I_destroy_group, FAIL); if (grp <= H5I_BADID || grp >= H5I_NGROUPS) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid group number"); grp_ptr = H5I_id_group_list_g[grp]; if (grp_ptr == NULL || grp_ptr->count <= 0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid group"); /* * Decrement the number of users of the atomic group. If this is the * last user of the group then release all atoms from the group. The * free function is invoked for each atom being freed. */ if (1==grp_ptr->count) { H5I_clear_group(grp, TRUE); H5E_clear(); /*don't care about errors*/ H5MM_xfree(grp_ptr->id_list); HDmemset (grp_ptr, 0, sizeof(*grp_ptr)); } else { --(grp_ptr->count); } done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_register * * Purpose: Registers an OBJECT in a GROUP 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 * group is unique. IDs are created by getting a unique number * for the group the ID is in and incorporating the group into * the ID which is returned to the user. * * Return: Success: New object id. * * Failure: Negative * * Programmer: Unknown * * Modifications: * *------------------------------------------------------------------------- */ hid_t H5I_register(H5I_type_t grp, void *object) { H5I_id_group_t *grp_ptr=NULL; /*ptr to the group */ H5I_id_info_t *id_ptr=NULL; /*ptr to the new ID information */ hid_t new_id; /*new ID */ unsigned hash_loc; /*new item's hash table location*/ hid_t next_id; /*next ID to check */ hid_t ret_value=SUCCEED; /*return value */ H5I_id_info_t *curr_id; /*ptr to the current atom */ unsigned i; /*counter */ FUNC_ENTER_NOAPI(H5I_register, FAIL); /* Check arguments */ if (grp <= H5I_BADID || grp >= H5I_NGROUPS) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid group number"); grp_ptr = H5I_id_group_list_g[grp]; if (grp_ptr == NULL || grp_ptr->count <= 0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid group"); if ((id_ptr = H5FL_ALLOC(H5I_id_info_t,0)) == NULL) HGOTO_ERROR(H5E_ATOM, H5E_NOSPACE, FAIL, "memory allocation failed"); /* Create the struct & it's ID */ new_id = H5I_MAKE(grp, grp_ptr->nextid); id_ptr->id = new_id; id_ptr->count = 1; /*initial reference count*/ id_ptr->obj_ptr = object; id_ptr->next = NULL; /* hash bucket already full, prepend to front of chain */ hash_loc = grp_ptr->nextid % (unsigned) grp_ptr->hash_size; if (grp_ptr->id_list[hash_loc] != NULL) id_ptr->next = grp_ptr->id_list[hash_loc]; /* Insert into the group */ grp_ptr->id_list[hash_loc] = id_ptr; grp_ptr->ids++; grp_ptr->nextid++; /* * This next section of code checks for the 'nextid' getting too large and * wrapping around, thus necessitating checking for duplicate IDs being * handed out. */ if (grp_ptr->nextid > (unsigned)ID_MASK) { grp_ptr->wrapped = 1; grp_ptr->nextid = grp_ptr->reserved; } /* * If we've wrapped around then we need to check for duplicate id's being * handed out. */ if (grp_ptr->wrapped) { /* * Make sure we check all available ID's. If we're about at the end * of the range then wrap around and check the beginning values. If * we check all possible values and didn't find any free ones *then* * we can fail. */ for (i=grp_ptr->reserved; inextid>(unsigned)ID_MASK) grp_ptr->nextid = grp_ptr->reserved; /* new ID to check for */ next_id = H5I_MAKE(grp, grp_ptr->nextid); hash_loc = H5I_LOC (grp_ptr->nextid, grp_ptr->hash_size); curr_id = grp_ptr->id_list[hash_loc]; if (curr_id == NULL) break; /* Ha! this is not likely... */ while (curr_id) { if (curr_id->id == next_id) break; curr_id = curr_id->next; } if (!curr_id) break; /* must not have found a match */ grp_ptr->nextid++; } if (i>=(unsigned)ID_MASK) /* All the IDs are gone! */ HGOTO_ERROR(H5E_ATOM, H5E_NOIDS, FAIL, "no IDs available in group"); } ret_value = new_id; done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * 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 * * Programmer: * * Modifications: * *------------------------------------------------------------------------- */ void * H5I_object(hid_t id) { H5I_id_info_t *id_ptr = NULL; /*ptr to the new atom */ void *ret_value = NULL; /*return value */ FUNC_ENTER_NOAPI(H5I_object, NULL); /* General lookup of the ID */ if (NULL!=(id_ptr = H5I_find_id(id))) { /* Get the object pointer to return */ ret_value = id_ptr->obj_ptr; } /* end if */ FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_object_verify * * Purpose: Find an object pointer for the specified ID, verifying that * its in a particular group. * * Return: Success: Non-null object pointer associated with the * specified ID. * * Failure: NULL * * Programmer: Quincey Koziol * Wednesday, July 31, 2002 * * Modifications: * *------------------------------------------------------------------------- */ void * H5I_object_verify(hid_t id, H5I_type_t id_type) { H5I_id_info_t *id_ptr = NULL; /*ptr to the new atom */ void *ret_value = NULL; /*return value */ FUNC_ENTER_NOAPI(H5I_object_verify, NULL); assert(id_type>=H5I_FILE && id_typeobj_ptr; } /* end if */ FUNC_LEAVE(ret_value); } /* H5I_object_verify() */ /*------------------------------------------------------------------------- * Function: H5I_get_type * * Purpose: Given an object ID return the group (type) to which it * belongs. The ID need not be the ID of an object which * currently exists because the group number (type) is encoded * in the object ID. * * Return: Success: A valid group number (type) * * Failure: H5I_BADID, a negative value. * * Programmer: Robb Matzke * Friday, February 19, 1999 * * Modifications: * *------------------------------------------------------------------------- */ H5I_type_t H5I_get_type(hid_t id) { H5I_type_t ret_value = H5I_BADID; FUNC_ENTER_NOAPI(H5I_get_type, H5I_BADID); if (id>0) ret_value = H5I_GROUP(id); assert(ret_value>=H5I_BADID && ret_value= H5I_NGROUPS || NULL==H5I_object(id)) HGOTO_DONE(H5I_BADID); done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_remove * * Purpose: Removes the specified ID from its group. * * 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: * * Modifications: * *------------------------------------------------------------------------- */ void * H5I_remove(hid_t id) { H5I_id_group_t *grp_ptr = NULL;/*ptr to the atomic group */ H5I_id_info_t *curr_id; /*ptr to the current atom */ H5I_id_info_t *last_id; /*ptr to the last atom */ H5I_type_t grp; /*atom's atomic group */ unsigned hash_loc; /*atom's hash table location */ #ifdef IDS_ARE_CACHED unsigned i; /*local counting variable */ #endif void * ret_value = NULL; /*return value */ FUNC_ENTER_NOAPI(H5I_remove, NULL); /* Check arguments */ grp = H5I_GROUP(id); if (grp <= H5I_BADID || grp >= H5I_NGROUPS) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid group number"); grp_ptr = H5I_id_group_list_g[grp]; if (grp_ptr == NULL || grp_ptr->count <= 0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "invalid group"); /* Get the bucket in which the ID is located */ hash_loc = (unsigned) H5I_LOC(id, grp_ptr->hash_size); curr_id = grp_ptr->id_list[hash_loc]; if (curr_id == NULL) HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, NULL, "invalid ID"); last_id = NULL; while (curr_id != NULL) { if (curr_id->id == id) break; last_id = curr_id; curr_id = curr_id->next; } #ifdef IDS_ARE_CACHED /* Delete object from cache */ for (i = 0; i < ID_CACHE_SIZE; i++) if (H5I_cache_g[i] && H5I_cache_g[i]->id == id) { H5I_cache_g[i] = NULL; break; /* we assume there is only one instance in the cache */ } #endif /* IDS_ARE_CACHED */ if (curr_id != NULL) { if (last_id == NULL) { /* ID is the first in the chain */ grp_ptr->id_list[hash_loc] = curr_id->next; } else { last_id->next = curr_id->next; } ret_value = curr_id->obj_ptr; H5FL_FREE(H5I_id_info_t,curr_id); } else { /* couldn't find the ID in the proper place */ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, NULL, "invalid ID"); } /* Decrement the number of IDs in the group */ (grp_ptr->ids)--; done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_dec_ref * * Purpose: Decrements the number of references outstanding for an ID. * This will fail if the group is not a reference counted group. * The ID group'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 group creation time. * * Return: Success: New reference count. * * Failure: Negative * * Programmer: Unknown * * Modifications: * * Robb Matzke, 19 Feb 1998 * It is no longer an error when the reference count of an item reaches * zero and no `free' function has been defined. The object is still * removed from the list. * * Robb Matzke, 30 Dec 1998 * Fixed a bug where the return value was always zero instead of the new * reference count. * * Robb Matzke, 19 Feb 1999 * If the free method is defined and fails then the object is not * removed from the group and its reference count is not decremented. * The group number is now passed to the free method. * * Raymond, 11 Dec 2001 * If the freeing function fails, return failure instead of reference * count 1. This feature is needed by file close with H5F_CLOSE_SEMI * value. * *------------------------------------------------------------------------- */ int H5I_dec_ref(hid_t id) { H5I_type_t grp = H5I_GROUP(id); /*group the object is in*/ H5I_id_group_t *grp_ptr = NULL; /*ptr to the group */ H5I_id_info_t *id_ptr = NULL; /*ptr to the new ID */ int ret_value; /*return value */ FUNC_ENTER_NOAPI(H5I_dec_ref, FAIL); /* Check arguments */ grp_ptr = H5I_id_group_list_g[grp]; if (grp_ptr == NULL || grp_ptr->count <= 0) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid group number"); /* General lookup of the ID */ if ((id_ptr=H5I_find_id(id))) { /* * If this is the last reference to the object then invoke the group's * free method on the object. If the free method is undefined or * successful then remove the object from the group; otherwise leave * the object in the group 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 (1==id_ptr->count) { if (!grp_ptr->free_func || (grp_ptr->free_func)(id_ptr->obj_ptr)>=0) { H5I_remove(id); ret_value = 0; } else { ret_value = FAIL; } } else { ret_value = --(id_ptr->count); } } done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_inc_ref * * Purpose: Increment the reference count for an object. * * Return: Success: The new reference count. * * Failure: Negative * * Programmer: Robb Matzke * Thursday, July 29, 1999 * * Modifications: * *------------------------------------------------------------------------- */ int H5I_inc_ref(hid_t id) { H5I_type_t grp = H5I_GROUP(id); /*group the object is in*/ H5I_id_group_t *grp_ptr = NULL; /*ptr to the group */ H5I_id_info_t *id_ptr = NULL; /*ptr to the ID */ int ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5I_inc_ref, FAIL); /* Check arguments */ if (id<0) HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "invalid ID"); grp_ptr = H5I_id_group_list_g[grp]; if (!grp_ptr || grp_ptr->count<=0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid group"); /* General lookup of the ID */ if (NULL==(id_ptr=H5I_find_id(id))) HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't locate ID"); id_ptr->count++; /* Set return value */ ret_value=id_ptr->count; done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_search * * Purpose: Apply function FUNC to each member of group GRP and return a * pointer to the first object for which FUNC returns non-zero. * The FUNC should take a pointer to the object and the KEY as * arguments and return non-zero to terminate the search (zero * to continue). * * Limitation: Currently there is no way to start searching from where a * previous search left off. * * Return: Success: The first object in the group for which FUNC * returns non-zero. NULL if FUNC returned zero * for every object in the group. * * Failure: NULL * * Programmer: Robb Matzke * Friday, February 19, 1999 * * Modifications: * *------------------------------------------------------------------------- */ void * H5I_search(H5I_type_t grp, H5I_search_func_t func, const void *key) { H5I_id_group_t *grp_ptr = NULL; /*ptr to the group */ H5I_id_info_t *id_ptr = NULL; /*ptr to the new ID */ unsigned i; /*counter */ void *ret_value = NULL; /*return value */ FUNC_ENTER_NOAPI(H5I_search, NULL); /* Check arguments */ if (grp <= H5I_BADID || grp >= H5I_NGROUPS) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid group number"); grp_ptr = H5I_id_group_list_g[grp]; if (grp_ptr == NULL || grp_ptr->count <= 0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "invalid group"); /* Start at the beginning of the array */ for (i=0; ihash_size; i++) { id_ptr = grp_ptr->id_list[i]; while (id_ptr) { if ((*func)(id_ptr->obj_ptr, id_ptr->id, key)) HGOTO_DONE(id_ptr->obj_ptr); /*found the item*/ id_ptr = id_ptr->next; } } done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_find_id * * Purpose: Given an object ID find the info struct that describes the * object. * * Return: Success: Ptr to the object's info struct. * * Failure: NULL * * Programmer: * * Modifications: * *------------------------------------------------------------------------- */ static H5I_id_info_t * H5I_find_id(hid_t id) { H5I_id_group_t *grp_ptr = NULL; /*ptr to the group */ H5I_id_info_t *id_ptr = NULL; /*ptr to the new ID */ H5I_type_t grp; /*ID's group */ unsigned hash_loc; /*bucket pointer */ H5I_id_info_t *ret_value = NULL; /*return value */ #ifdef IDS_ARE_CACHED int i; #endif FUNC_ENTER_NOINIT(H5I_find_id); /* Check arguments */ grp = H5I_GROUP(id); if (grp <= H5I_BADID || grp >= H5I_NGROUPS) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid group number"); grp_ptr = H5I_id_group_list_g[grp]; if (grp_ptr == NULL || grp_ptr->count <= 0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "invalid group"); #ifdef IDS_ARE_CACHED /* * Look for the ID in the cache first. Implement a simple "move * forward" caching scheme by swapping the found cache item with the * previous cache item. This gradually migrates used cache items toward * the front of the cache and unused items toward the end. For instance, * finding `e' in the cache results in: * * Before: a b c d e f g h i j * | | | X | | | | | * After: a b c e d f g h i j */ for (i=0; iid == id) { ret_value = H5I_cache_g[i]; if (i > 0) { H5I_id_info_t *tmp = H5I_cache_g[i-1]; H5I_cache_g[i-1] = H5I_cache_g[i]; H5I_cache_g[i] = tmp; } HGOTO_DONE(ret_value); } #endif /* IDS_ARE_CACHED */ /* Get the bucket in which the ID is located */ hash_loc = (unsigned)H5I_LOC(id, grp_ptr->hash_size); id_ptr = grp_ptr->id_list[hash_loc]; if (id_ptr == NULL) HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, NULL, "invalid ID"); /* Scan the bucket's linked list for a match */ while (id_ptr) { if (id_ptr->id == id) break; id_ptr = id_ptr->next; } ret_value = id_ptr; #ifdef IDS_ARE_CACHED /* Add id to the end of the cache */ H5I_cache_g[ID_CACHE_SIZE-1] = id_ptr; #endif /* IDS_ARE_CACHED */ done: FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5I_debug * * Purpose: Dump the contents of a group to stderr for debugging. * * Return: Success: Non-negative * * Failure: Negative * * Programmer: Robb Matzke * Friday, February 19, 1999 * * Modifications: * *------------------------------------------------------------------------- */ #ifdef H5I_DEBUG_OUTPUT static herr_t H5I_debug(H5I_type_t grp) { H5I_id_group_t *grp_ptr; H5I_id_info_t *cur; int is, js; unsigned int iu; FUNC_ENTER_NOAPI(H5I_debug, FAIL); fprintf(stderr, "Dumping group %d\n", (int)grp); grp_ptr = H5I_id_group_list_g[grp]; /* Header */ fprintf(stderr, " count = %u\n", grp_ptr->count); fprintf(stderr, " reserved = %u\n", grp_ptr->reserved); fprintf(stderr, " wrapped = %u\n", grp_ptr->wrapped); fprintf(stderr, " hash_size = %lu\n", (unsigned long)grp_ptr->hash_size); fprintf(stderr, " ids = %u\n", grp_ptr->ids); fprintf(stderr, " nextid = %u\n", grp_ptr->nextid); /* Cache */ fprintf(stderr, " Cache:\n"); for (is=0; isid)==grp) { fprintf(stderr, " Entry-%d, ID=%lu\n", is, (unsigned long)(H5I_cache_g[is]->id)); } } /* List */ fprintf(stderr, " List:\n"); for (iu=0; iuhash_size; iu++) { for (js=0, cur=grp_ptr->id_list[iu]; cur; cur=cur->next, js++) { fprintf(stderr, " #%u.%d\n", iu, js); fprintf(stderr, " id = %lu\n", (unsigned long)(cur->id)); fprintf(stderr, " count = %u\n", cur->count); fprintf(stderr, " obj = 0x%08lx\n", (unsigned long)(cur->obj_ptr)); } } FUNC_LEAVE(SUCCEED); } #endif /* H5I_DEBUG_OUTPUT */