From c6754194970865d03d90c5dc10d6832d9b6f4608 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Tue, 1 Aug 2000 14:13:38 -0500 Subject: [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. --- src/H5FL.c | 180 +++++++++++++++++++++++++++++++++--------------------- src/H5FLprivate.h | 24 ++++---- 2 files changed, 121 insertions(+), 83 deletions(-) diff --git a/src/H5FL.c b/src/H5FL.c index 0db2b32..5ca400c 100644 --- a/src/H5FL.c +++ b/src/H5FL.c @@ -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); } diff --git a/src/H5FLprivate.h b/src/H5FLprivate.h index 4a9d90d..d3de019 100644 --- a/src/H5FLprivate.h +++ b/src/H5FLprivate.h @@ -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); -- cgit v0.12