hdf5/src/H5I.c
Quincey Koziol eaa30bb648 [svn-r6433] Purpose:
Code/comment cleanup

Description:
    Made more information about reference-counted strings private to the
    H5RS package by trimming the typedef used in H5RSprivate.h and switching
    from using macros for a couple of operations to using functions.

    Updated copyright information for a few of these files.

Platforms tested:
    Tested h5committest {arabica (fortran), eirene (fortran, C++)
	modi4 (parallel, fortran)}
2003-02-24 15:19:01 -05:00

1271 lines
39 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
* access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* 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 "H5Eprivate.h"
#include "H5FLprivate.h" /*Free Lists */
#include "H5Iprivate.h"
#include "H5MMprivate.h"
/* Define this to compile in support for dumping ID information */
/* #define H5I_DEBUG_OUTPUT */
#ifndef H5I_DEBUG_OUTPUT
#include "H5Gprivate.h" /*symbol tables */
#else /* H5I_DEBUG_OUTPUT */
#define H5G_PACKAGE /*suppress error message about including H5Gpkg.h */
#include "H5Gpkg.h"
#include "H5Dprivate.h" /*datasets */
#include "H5Tprivate.h" /*data types */
#endif /* H5I_DEBUG_OUTPUT */
/* 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)
{
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<<GROUP_BITS));
FUNC_LEAVE_NOAPI(SUCCEED);
}
/*-------------------------------------------------------------------------
* Function: H5I_term_interface
*
* Purpose: Terminate the H5I interface: release all memory, reset all
* global variables to initial values. This only happens if all
* groups have been destroyed from other interfaces.
*
* Return: Success: Positive if any action was taken that might
* affect some other interface; zero otherwise.
*
* Failure: Negative.
*
* Programmer:
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
int
H5I_term_interface(void)
{
H5I_id_group_t *grp_ptr;
H5I_type_t grp;
int n=0;
FUNC_ENTER_NOINIT(H5I_term_interface);
if (interface_initialize_g) {
/* How many groups are still being used? */
for (grp=(H5I_type_t)0; grp<H5I_NGROUPS; H5_INC_ENUM(H5I_type_t,grp)) {
if ((grp_ptr=H5I_id_group_list_g[grp]) && grp_ptr->id_list)
n++;
}
/* If no groups are used then clean up */
if (0==n) {
for (grp=(H5I_type_t)0; grp<H5I_NGROUPS; H5_INC_ENUM(H5I_type_t,grp)) {
grp_ptr = H5I_id_group_list_g[grp];
H5MM_xfree(grp_ptr);
H5I_id_group_list_g[grp] = NULL;
}
}
/* Mark interface closed */
interface_initialize_g = 0;
}
FUNC_LEAVE_NOAPI(n);
}
/*-------------------------------------------------------------------------
* Function: H5I_init_group
*
* Purpose: Initialize an ID group whose ID number is specified by GRP,
* If the group has already been initialized, this routine just
* increments the count of number of initializations and returns
* without trying to change the size of the hash table. A
* specific number (RESERVED) of group entries may be reserved
* to enable "constant" values to be handed out which are valid
* IDs in the group, but which do not map to any data structures
* and are not allocated dynamicly later. HASH_SIZE is the
* minimum hash table size to use for the group. FREE_FUNC is
* called with an object pointer when the object is removed from
* the group.
*
* Return: Success: Non-negative
*
* Failure: Negative
*
* Programmer: Robb Matzke
* Friday, February 19, 1999
*
* Modifications:
* Bill Wendling, 2000-05-05
* Instead of the ugly test of whether hash_size is a power of
* two, I placed it in a macro POWER_OF_TWO which uses the fact
* that a number that is a power of two has only 1 bit set.
*
* Bill Wendling, 2000-05-09
* Changed POWER_OF_TWO macro to allow 1 as a valid power of two.
* Changed test below accordingly.
*
*-------------------------------------------------------------------------
*/
int
H5I_init_group(H5I_type_t grp, size_t hash_size, unsigned reserved,
H5I_free_t free_func)
{
H5I_id_group_t *grp_ptr = NULL; /*ptr to the atomic group*/
int ret_value = SUCCEED; /*return value */
FUNC_ENTER_NOAPI(H5I_init_group, FAIL);
/* Check arguments */
if ((grp <= H5I_BADID || 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_NOAPI(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; i<grp_ptr->hash_size; i++)
for (cur=grp_ptr->id_list[i]; cur; cur=cur->next)
n++;
/* Set return value */
ret_value=n;
done:
FUNC_LEAVE_NOAPI(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; i<ID_CACHE_SIZE; i++) {
if (H5I_cache_g[i] && H5I_GROUP(H5I_cache_g[i]->id) == 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; i<grp_ptr->hash_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) {
next=cur->next;
continue;
} /* end if */
/* 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) {
#ifdef 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; j<ID_CACHE_SIZE; j++)
if(H5I_cache_g[j]==cur)
H5I_cache_g[j]=NULL;
#endif /* IDS_ARE_CACHED */
/* Free the node */
H5FL_FREE(H5I_id_info_t,cur);
} /* end if */
else {
/* Advance to next node */
next = cur->next;
} /* end else */
} /* end for */
} /* end for */
done:
FUNC_LEAVE_NOAPI(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_NOAPI(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_MALLOC(H5I_id_info_t)) == 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; i<ID_MASK; i++) {
/* Handle end of range by wrapping to beginning */
if (grp_ptr->nextid>(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_NOAPI(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 */
done:
FUNC_LEAVE_NOAPI(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_type<H5I_NGROUPS);
/* Verify that the group of the ID is correct & lookup the ID */
if(id_type == H5I_GROUP(id) && NULL!=(id_ptr = H5I_find_id(id))) {
/* Get the object pointer to return */
ret_value = id_ptr->obj_ptr;
} /* end if */
done:
FUNC_LEAVE_NOAPI(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);
done:
FUNC_LEAVE_NOAPI(ret_value);
}
/*-------------------------------------------------------------------------
* Function: H5Iget_type
*
* Purpose: The public version of H5I_get_type(), obtains a group number
* (type) when given an ID. The ID need not be the ID of an
* object which currently exists because the group number is
* encoded as part of the ID.
*
* Return: Success: Group number (type)
*
* Failure: H5I_BADID, a negative value
*
* Programmer:
*
* Modifications:
* Robb Matzke, 1999-08-23
* Also fails if the ID has a valid group but no longer exists
* in the ID tables.
*-------------------------------------------------------------------------
*/
H5I_type_t
H5Iget_type(hid_t id)
{
H5I_type_t ret_value = H5I_BADID;
FUNC_ENTER_API(H5Iget_type, H5I_BADID);
H5TRACE1("It","i",id);
ret_value = H5I_get_type(id);
if (ret_value <= H5I_BADID || ret_value >= H5I_NGROUPS || NULL==H5I_object(id))
HGOTO_DONE(H5I_BADID);
done:
FUNC_LEAVE_API(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_NOAPI(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=FAIL; /*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_NOAPI(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_NOAPI(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; i<grp_ptr->hash_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_NOAPI(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; i<ID_CACHE_SIZE; i++)
if (H5I_cache_g[i] && H5I_cache_g[i]->id == 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_NOAPI(ret_value);
}
/*-------------------------------------------------------------------------
* Function: H5Iget_name
*
* Purpose: Gets a name of an object from its ID.
*
* Return: Success: 0, Failure: -1
*
* Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
*
* Date: July 26, 2002
*
* Comments: Public function
* If `name' is non-NULL then write up to `size' bytes into that
* buffer and always return the length of the entry name.
* Otherwise `size' is ignored and the function does not store the name,
* just returning the number of characters required to store the name.
* If an error occurs then the buffer pointed to by `name' (NULL or non-NULL)
* is unchanged and the function returns a negative value.
* If a zero is returned for the name's length, then there is no name
* associated with the ID.
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
ssize_t
H5Iget_name(hid_t id, char *name/*out*/, size_t size)
{
H5G_entry_t *ent; /*symbol table entry */
size_t len=0;
ssize_t ret_value;
FUNC_ENTER_API (H5Iget_name, FAIL);
H5TRACE3("Zs","ixz",id,name,size);
/* get symbol table entry */
if(NULL!=(ent = H5G_loc(id))) {
if (ent->user_path_r != NULL && ent->user_path_hidden==0) {
len = H5RS_len(ent->user_path_r);
if(name) {
HDstrncpy(name, H5RS_get_str(ent->user_path_r), MIN(len+1,size));
if(len >= size)
name[size-1]='\0';
} /* end if */
} /* end if */
} /* end if */
/* Set return value */
ret_value=(ssize_t)len;
done:
FUNC_LEAVE_API(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:
*
* Pedro Vicente, <pvn@ncsa.uiuc.edu> 22 Aug 2002
* Added `id to name' support.
*
*-------------------------------------------------------------------------
*/
#ifdef H5I_DEBUG_OUTPUT
static herr_t
H5I_debug(H5I_type_t grp)
{
H5I_id_group_t *grp_ptr;
H5I_id_info_t *cur;
H5G_entry_t *ent = NULL;
int is, js;
unsigned int iu;
herr_t ret_value; /* Return value */
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; is<ID_CACHE_SIZE; is++) {
if (H5I_cache_g[is] && H5I_GROUP(H5I_cache_g[is]->id)==grp) {
fprintf(stderr, " Entry-%d, ID=%lu\n",
is, (unsigned long)(H5I_cache_g[is]->id));
}
}
/* List */
fprintf(stderr, " List:\n");
for (iu=0; iu<grp_ptr->hash_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));
/* Get the symbol table entry, so we get get the name */
switch(grp) {
case H5I_GROUP:
ent = H5G_entof((H5G_t*)cur->obj_ptr);
break;
case H5I_DATASET:
ent = H5D_entof((H5D_t*)cur->obj_ptr);
break;
case H5I_DATATYPE:
ent = H5T_entof((H5T_t*)cur->obj_ptr);
break;
default:
continue; /* Other types of IDs are not stored in files */
} /* end switch*/
if(ent) {
if(ent->name)
fprintf(stderr, " name = %s\n",ent->name);
if(ent->old_name)
fprintf(stderr, " old_name = %s\n",ent->old_name);
} /* end if */
} /* end for */
} /* end for */
done:
FUNC_LEAVE_NOAPI(SUCCEED);
}
#endif /* H5I_DEBUG_OUTPUT */