[svn-r2453] Made free-list code garbage collect if it runs out memory during a memory

allocation & attempt to allocate the memory once more.  Also re-named a bunch
of private functions & structures to align with other function names.
This commit is contained in:
Quincey Koziol 2000-08-01 14:13:38 -05:00
parent 3651a0a0bf
commit c675419497
2 changed files with 121 additions and 83 deletions

View File

@ -42,19 +42,19 @@ static intn interface_initialize_g = 0;
#define H5FL_BLK_LST_MEM_LIM (2*1024*1024) /* Default to 2MB on each block free list */
/* A garbage collection node for regular free lists */
typedef struct H5FL_gc_node_t {
H5FL_head_t *list; /* Pointer to the head of the list to garbage collect */
struct H5FL_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
} H5FL_gc_node_t;
typedef struct H5FL_reg_gc_node_t {
H5FL_reg_head_t *list; /* Pointer to the head of the list to garbage collect */
struct H5FL_reg_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
} H5FL_reg_gc_node_t;
/* The garbage collection head for regular free lists */
typedef struct H5FL_gc_list_t {
typedef struct H5FL_reg_gc_list_t {
size_t mem_freed; /* Amount of free memory on list */
struct H5FL_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
} H5FL_gc_list_t;
struct H5FL_reg_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
} H5FL_reg_gc_list_t;
/* The head of the list of things to garbage collect */
static H5FL_gc_list_t H5FL_gc_head={0,NULL};
static H5FL_reg_gc_list_t H5FL_reg_gc_head={0,NULL};
/* A garbage collection node for array free lists */
typedef struct H5FL_gc_arr_node_t {
@ -95,8 +95,8 @@ static H5FL_blk_gc_list_t H5FL_blk_gc_head={0,NULL};
#endif /* NO_FREE_LISTS */
/* Forward declarations of local static functions */
static herr_t H5FL_gc(void);
static herr_t H5FL_gc_list(H5FL_head_t *head);
static herr_t H5FL_reg_gc(void);
static herr_t H5FL_reg_gc_list(H5FL_reg_head_t *head);
static herr_t H5FL_arr_gc(void);
static herr_t H5FL_arr_gc_list(H5FL_arr_head_t *head);
static herr_t H5FL_blk_gc(void);
@ -107,7 +107,45 @@ H5FL_DEFINE(H5FL_blk_node_t);
/*-------------------------------------------------------------------------
* Function: H5FL_init
* Function: H5FL_malloc
*
* Purpose: Attempt to allocate space using malloc. If malloc fails, garbage
* collect and try again. If malloc fails again, then return NULL.
*
* Return: Success: non-NULL
* Failure: NULL
*
* Programmer: Quincey Koziol
* Tuesday, August 1, 2000
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static void *
H5FL_malloc(size_t mem_size)
{
void *ret_value=NULL; /* return value*/
FUNC_ENTER (H5FL_malloc, NULL);
/* Attempt to allocate the memory requested */
if(NULL==(ret_value=H5MM_malloc(mem_size))) {
/* If we can't allocate the memory now, try garbage collecting first */
H5FL_garbage_coll();
/* Now try allocating the memory again */
if(NULL==(ret_value=H5MM_malloc(mem_size)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for chunk");
} /* end if */
done:
FUNC_LEAVE (ret_value);
} /* end H5FL_malloc() */
/*-------------------------------------------------------------------------
* Function: H5FL_reg_init
*
* Purpose: Initialize a free list for a certain type. Right now, this just
* adds the free list to the list of things to garbage collect.
@ -123,33 +161,33 @@ H5FL_DEFINE(H5FL_blk_node_t);
*-------------------------------------------------------------------------
*/
static herr_t
H5FL_init(H5FL_head_t *head)
H5FL_reg_init(H5FL_reg_head_t *head)
{
H5FL_gc_node_t *new_node; /* Pointer to the node for the new list to garbage collect */
H5FL_reg_gc_node_t *new_node; /* Pointer to the node for the new list to garbage collect */
herr_t ret_value=SUCCEED; /* return value*/
FUNC_ENTER (H5FL_init, FAIL);
FUNC_ENTER (H5FL_reg_init, FAIL);
/* Allocate a new garbage collection node */
if (NULL==(new_node = H5MM_malloc(sizeof(H5FL_gc_node_t))))
if (NULL==(new_node = H5MM_malloc(sizeof(H5FL_reg_gc_node_t))))
HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
/* Initialize the new garbage collection node */
new_node->list=head;
/* Link in to the garbage collection list */
new_node->next=H5FL_gc_head.first;
H5FL_gc_head.first=new_node;
new_node->next=H5FL_reg_gc_head.first;
H5FL_reg_gc_head.first=new_node;
/* Indicate that the free list is initialized */
head->init=1;
FUNC_LEAVE (ret_value);
} /* end H5FL_init() */
} /* end H5FL_reg_init() */
/*-------------------------------------------------------------------------
* Function: H5FL_free
* Function: H5FL_reg_free
*
* Purpose: Release an object & put on free list
*
@ -164,11 +202,11 @@ H5FL_init(H5FL_head_t *head)
*-------------------------------------------------------------------------
*/
void *
H5FL_free(H5FL_head_t *head, void *obj)
H5FL_reg_free(H5FL_reg_head_t *head, void *obj)
{
H5FL_node_t *temp; /* Temp. ptr to the new free list node allocated */
H5FL_reg_node_t *temp; /* Temp. ptr to the new free list node allocated */
FUNC_ENTER (H5FL_free, NULL);
FUNC_ENTER (H5FL_reg_free, NULL);
/* Double check parameters */
assert(head);
@ -185,7 +223,7 @@ H5FL_free(H5FL_head_t *head, void *obj)
assert(head->init);
/* Get the pointer to the info header in front of the block to free */
temp=(H5FL_node_t *)((unsigned char *)obj-sizeof(H5FL_node_t));
temp=(H5FL_reg_node_t *)((unsigned char *)obj-sizeof(H5FL_reg_node_t));
#ifdef H5FL_DEBUG
assert(temp->inuse);
@ -203,25 +241,25 @@ H5FL_free(H5FL_head_t *head, void *obj)
head->list_mem+=head->size;
/* Increment the amount of "regular" freed memory globally */
H5FL_gc_head.mem_freed+=head->size;
H5FL_reg_gc_head.mem_freed+=head->size;
/* Check for exceeding free list memory use limits */
/* First check this particular list */
if(head->list_mem>H5FL_REG_LST_MEM_LIM)
H5FL_gc_list(head);
H5FL_reg_gc_list(head);
/* Then check the global amount memory on regular free lists */
if(H5FL_gc_head.mem_freed>H5FL_REG_GLB_MEM_LIM)
H5FL_gc();
if(H5FL_reg_gc_head.mem_freed>H5FL_REG_GLB_MEM_LIM)
H5FL_reg_gc();
#endif /* NO_REG_FREE_LISTS */
FUNC_LEAVE(NULL);
} /* end H5FL_free() */
} /* end H5FL_reg_free() */
/*-------------------------------------------------------------------------
* Function: H5FL_alloc
* Function: H5FL_reg_alloc
*
* Purpose: Allocate a block on a free list
*
@ -236,12 +274,12 @@ H5FL_free(H5FL_head_t *head, void *obj)
*-------------------------------------------------------------------------
*/
void *
H5FL_alloc(H5FL_head_t *head, uintn clear)
H5FL_reg_alloc(H5FL_reg_head_t *head, uintn clear)
{
H5FL_node_t *new_obj; /* Pointer to the new free list node allocated */
H5FL_reg_node_t *new_obj; /* Pointer to the new free list node allocated */
void *ret_value; /* Pointer to object to return */
FUNC_ENTER (H5FL_alloc, NULL);
FUNC_ENTER (H5FL_reg_alloc, NULL);
/* Double check parameters */
assert(head);
@ -254,12 +292,12 @@ H5FL_alloc(H5FL_head_t *head, uintn clear)
#else /* NO_REG_FREE_LISTS */
/* Make certain the list is initialized first */
if(!head->init)
H5FL_init(head);
H5FL_reg_init(head);
/* Check for nodes available on the free list first */
if(head->list!=NULL) {
/* Get a pointer to the block on the free list */
ret_value=((char *)(head->list))+sizeof(H5FL_node_t);
ret_value=((char *)(head->list))+sizeof(H5FL_reg_node_t);
#ifdef H5FL_DEBUG
head->list->inuse=1;
@ -273,12 +311,12 @@ H5FL_alloc(H5FL_head_t *head, uintn clear)
head->list_mem-=head->size;
/* Decrement the amount of global "regular" free list memory in use */
H5FL_gc_head.mem_freed-=(head->size);
H5FL_reg_gc_head.mem_freed-=(head->size);
} /* end if */
/* Otherwise allocate a node */
else {
if (NULL==(new_obj = H5MM_malloc(sizeof(H5FL_node_t)+head->size)))
if (NULL==(new_obj = H5FL_malloc(sizeof(H5FL_reg_node_t)+head->size)))
HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
#ifdef H5FL_DEBUG
@ -289,7 +327,7 @@ H5FL_alloc(H5FL_head_t *head, uintn clear)
head->allocated++;
/* Get a pointer to the new block */
ret_value=((char *)new_obj)+sizeof(H5FL_node_t);
ret_value=((char *)new_obj)+sizeof(H5FL_reg_node_t);
} /* end else */
/* Clear to zeros, if asked */
@ -298,11 +336,11 @@ H5FL_alloc(H5FL_head_t *head, uintn clear)
#endif /* NO_REG_FREE_LISTS */
FUNC_LEAVE (ret_value);
} /* end H5FL_alloc() */
} /* end H5FL_reg_alloc() */
/*-------------------------------------------------------------------------
* Function: H5FL_gc_list
* Function: H5FL_reg_gc_list
*
* Purpose: Garbage collect on a particular object free list
*
@ -317,15 +355,15 @@ H5FL_alloc(H5FL_head_t *head, uintn clear)
*-------------------------------------------------------------------------
*/
static herr_t
H5FL_gc_list(H5FL_head_t *head)
H5FL_reg_gc_list(H5FL_reg_head_t *head)
{
H5FL_node_t *free_list; /* Pointer to nodes in free list being garbage collected */
H5FL_reg_node_t *free_list; /* Pointer to nodes in free list being garbage collected */
void *tmp; /* Temporary node pointer */
size_t total_mem; /* Total memory used on list */
/* FUNC_ENTER_INIT() should not be called, it causes an infinite loop at library termination */
#ifdef H5_DEBUG_API
H5_trace(FALSE, "H5FL_gc_list", "");
H5_trace(FALSE, "H5FL_reg_gc_list", "");
#endif
/* Calculate the total memory used on this list */
@ -359,17 +397,17 @@ H5FL_gc_list(H5FL_head_t *head)
head->onlist=0;
/* Decrement global count of free memory on "regular" lists */
H5FL_gc_head.mem_freed-=total_mem;
H5FL_reg_gc_head.mem_freed-=total_mem;
#ifdef H5_DEBUG_API
H5_trace(TRUE, NULL, "e", SUCCEED);
#endif
return(SUCCEED);
} /* end H5FL_gc_list() */
} /* end H5FL_reg_gc_list() */
/*-------------------------------------------------------------------------
* Function: H5FL_gc
* Function: H5FL_reg_gc
*
* Purpose: Garbage collect on all the object free lists
*
@ -386,38 +424,38 @@ H5FL_gc_list(H5FL_head_t *head)
*-------------------------------------------------------------------------
*/
static herr_t
H5FL_gc(void)
H5FL_reg_gc(void)
{
H5FL_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */
H5FL_reg_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */
/* FUNC_ENTER_INIT() should not be called, it causes an infinite loop at library termination */
#ifdef H5_DEBUG_API
H5_trace(FALSE, "H5FL_gc", "");
H5_trace(FALSE, "H5FL_reg_gc", "");
#endif
/* Walk through all the free lists, free()'ing the nodes */
gc_node=H5FL_gc_head.first;
gc_node=H5FL_reg_gc_head.first;
while(gc_node!=NULL) {
/* Release the free nodes on the list */
H5FL_gc_list(gc_node->list);
H5FL_reg_gc_list(gc_node->list);
/* Go on to the next free list to garbage collect */
gc_node=gc_node->next;
} /* end while */
/* Double check that all the memory on the free lists is recycled */
assert(H5FL_gc_head.mem_freed==0);
assert(H5FL_reg_gc_head.mem_freed==0);
#ifdef H5_DEBUG_API
H5_trace(TRUE, NULL, "e", SUCCEED);
#endif
return(SUCCEED);
} /* end H5FL_gc() */
} /* end H5FL_reg_gc() */
/*--------------------------------------------------------------------------
NAME
H5FL_term
H5FL_reg_term
PURPOSE
Terminate various H5FL object free lists
USAGE
@ -441,40 +479,40 @@ H5FL_gc(void)
again to reclaim this layer's memory.
--------------------------------------------------------------------------*/
static intn
H5FL_term(void)
H5FL_reg_term(void)
{
H5FL_gc_node_t *left; /* pointer to garbage collection lists with work left */
H5FL_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
H5FL_reg_gc_node_t *left; /* pointer to garbage collection lists with work left */
H5FL_reg_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
if (interface_initialize_g) {
/* Free the nodes on the garbage collection list, keeping nodes with allocations outstanding */
left=NULL;
while(H5FL_gc_head.first!=NULL) {
tmp=H5FL_gc_head.first->next;
while(H5FL_reg_gc_head.first!=NULL) {
tmp=H5FL_reg_gc_head.first->next;
#ifdef H5FL_DEBUG
printf("H5FL_term: head->name=%s, head->allocated=%d\n", H5FL_gc_head.first->list->name,(int)H5FL_gc_head.first->list->allocated);
printf("H5FL_reg_term: head->name=%s, head->allocated=%d\n", H5FL_reg_gc_head.first->list->name,(int)H5FL_reg_gc_head.first->list->allocated);
#endif /* H5FL_DEBUG */
/* Check if the list has allocations outstanding */
if(H5FL_gc_head.first->list->allocated>0) {
if(H5FL_reg_gc_head.first->list->allocated>0) {
/* Add free list to the list of nodes with allocations open still */
H5FL_gc_head.first->next=left;
left=H5FL_gc_head.first;
H5FL_reg_gc_head.first->next=left;
left=H5FL_reg_gc_head.first;
} /* end if */
/* No allocations left open for list, get rid of it */
else {
/* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
H5FL_gc_head.first->list->init=0;
H5FL_reg_gc_head.first->list->init=0;
/* Free the node from the garbage collection list */
H5MM_xfree(H5FL_gc_head.first);
H5MM_xfree(H5FL_reg_gc_head.first);
} /* end else */
H5FL_gc_head.first=tmp;
H5FL_reg_gc_head.first=tmp;
} /* end while */
/* Point to the list of nodes left with allocations open, if any */
H5FL_gc_head.first=left;
H5FL_reg_gc_head.first=left;
if (!left)
interface_initialize_g = 0; /*this layer has reached its initial state*/
}
@ -482,7 +520,7 @@ H5FL_term(void)
/* Terminating this layer never affects other layers; rather, other layers affect
* the termination of this layer. */
return(0);
} /* end H5FL_term() */
} /* end H5FL_reg_term() */
/*-------------------------------------------------------------------------
@ -693,7 +731,7 @@ H5FL_blk_alloc(H5FL_blk_head_t *head, size_t size, uintn clear)
/* No free list available, or there are no nodes on the list, allocate a new node to give to the user */
else {
/* Allocate new node, with room for the page info header and the actual page data */
if(NULL==(temp=H5MM_malloc(sizeof(H5FL_blk_list_t)+size)))
if(NULL==(temp=H5FL_malloc(sizeof(H5FL_blk_list_t)+size)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for chunk");
/* Increment the number of blocks allocated */
@ -1220,7 +1258,7 @@ H5FL_arr_alloc(H5FL_arr_head_t *head, uintn elem, uintn clear)
} /* end if */
/* Otherwise allocate a node */
else {
if (NULL==(new_obj = H5MM_malloc(sizeof(H5FL_arr_node_t)+mem_size)))
if (NULL==(new_obj = H5FL_malloc(sizeof(H5FL_arr_node_t)+mem_size)))
HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
/* Increment the number of blocks allocated in list */
@ -1551,7 +1589,7 @@ H5FL_garbage_coll(void)
H5FL_blk_gc();
/* Garbage collect the free lists for regular objects */
H5FL_gc();
H5FL_reg_gc();
#ifdef H5_DEBUG_API
H5_trace(TRUE, NULL, "e", SUCCEED);
@ -1587,7 +1625,7 @@ H5FL_term_interface(void)
/* Garbage collect any nodes on the free lists */
H5FL_garbage_coll();
ret_value=H5FL_term()+H5FL_arr_term()+H5FL_blk_term();
ret_value=H5FL_reg_term()+H5FL_arr_term()+H5FL_blk_term();
return(ret_value);
}

View File

@ -29,8 +29,8 @@
*/
/* Data structure to store each block in free list */
typedef struct H5FL_node_t {
struct H5FL_node_t *next; /* Pointer to next block in free list */
typedef struct H5FL_reg_node_t {
struct H5FL_reg_node_t *next; /* Pointer to next block in free list */
#ifdef H5FL_DEBUG
uintn inuse; /* Indicate when object is in use */
#endif /* H5FL_DEBUG */
@ -38,36 +38,36 @@ typedef struct H5FL_node_t {
double unused1; /* Unused normally, just here for aligment */
haddr_t unused2; /* Unused normally, just here for aligment */
}align; /* Bogus union, just here to align following block */
} H5FL_node_t;
} H5FL_reg_node_t;
/* Data structure for free list of blocks */
typedef struct H5FL_head_t {
typedef struct H5FL_reg_head_t {
uintn init; /* Whether the free list has been initialized */
uintn allocated; /* Number of blocks allocated */
uintn onlist; /* Number of blocks on free list */
size_t list_mem; /* Amount of memory on free list */
const char *name; /* Name of the type */
size_t size; /* Size of the blocks in the list */
H5FL_node_t *list; /* List of free blocks */
} H5FL_head_t;
H5FL_reg_node_t *list; /* List of free blocks */
} H5FL_reg_head_t;
/*
* Macros for defining & using free lists for a type
*/
/* Declare a free list to manage objects of type 't' */
#define H5FL_DEFINE(t) H5FL_head_t t##_free_list={0,0,0,0,#t,sizeof(t),NULL}
#define H5FL_DEFINE(t) H5FL_reg_head_t t##_free_list={0,0,0,0,#t,sizeof(t),NULL}
/* Reference a free list for type 't' defined in another file */
#define H5FL_EXTERN(t) extern H5FL_head_t t##_free_list
#define H5FL_EXTERN(t) extern H5FL_reg_head_t t##_free_list
/* Declare a static free list to manage objects of type 't' */
#define H5FL_DEFINE_STATIC(t) static H5FL_DEFINE(t)
/* Allocate an object of type 't' */
#define H5FL_ALLOC(t,clr) H5FL_alloc(&(t##_free_list),clr)
#define H5FL_ALLOC(t,clr) H5FL_reg_alloc(&(t##_free_list),clr)
/* Free an object of type 't' */
#define H5FL_FREE(t,obj) H5FL_free(&(t##_free_list),obj)
#define H5FL_FREE(t,obj) H5FL_reg_free(&(t##_free_list),obj)
/* Re-allocating an object of type 't' is not defined, because these free-lists
* only support fixed sized types, like structs, etc..
@ -174,8 +174,8 @@ typedef struct H5FL_arr_head_t {
__DLL__ void * H5FL_blk_alloc(H5FL_blk_head_t *head, size_t size, uintn clear);
__DLL__ void * H5FL_blk_free(H5FL_blk_head_t *head, void *block);
__DLL__ void * H5FL_blk_realloc(H5FL_blk_head_t *head, void *block, size_t new_size);
__DLL__ void * H5FL_alloc(H5FL_head_t *head, uintn clear);
__DLL__ void * H5FL_free(H5FL_head_t *head, void *obj);
__DLL__ void * H5FL_reg_alloc(H5FL_reg_head_t *head, uintn clear);
__DLL__ void * H5FL_reg_free(H5FL_reg_head_t *head, void *obj);
__DLL__ void * H5FL_arr_alloc(H5FL_arr_head_t *head, uintn elem, uintn clear);
__DLL__ void * H5FL_arr_free(H5FL_arr_head_t *head, void *obj);
__DLL__ void * H5FL_arr_realloc(H5FL_arr_head_t *head, void *obj, uintn new_elem);