summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/H5.c10
-rw-r--r--src/H5FL.c591
-rw-r--r--src/H5FLprivate.h24
3 files changed, 459 insertions, 166 deletions
diff --git a/src/H5.c b/src/H5.c
index 70b5660..b49db8d 100644
--- a/src/H5.c
+++ b/src/H5.c
@@ -409,6 +409,9 @@ done:
* global lists, up to 3 MB of total storage might be allocated (1MB on
* each of regular, array and block type lists).
*
+ * The settings for block free lists are duplicated to factory free lists.
+ * Factory free list limits cannot be set independently currently.
+ *
* Parameters:
* int reg_global_lim; IN: The limit on all "regular" free list memory used
* int reg_list_lim; IN: The limit on memory used in each "regular" free list
@@ -424,7 +427,9 @@ done:
* Programmer: Quincey Koziol
* Wednesday, August 2, 2000
*
- * Modifications:
+ * Modifications: Neil Fortner
+ * Wednesday, April 8, 2009
+ * Added support for factory free lists
*
*-------------------------------------------------------------------------
*/
@@ -439,7 +444,8 @@ H5set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim,
arr_list_lim, blk_global_lim, blk_list_lim);
/* Call the free list function to actually set the limits */
- if(H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim, blk_global_lim, blk_list_lim)<0)
+ if(H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim,
+ blk_global_lim, blk_list_lim, blk_global_lim, blk_list_lim)<0)
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "can't set garbage collection limits")
done:
diff --git a/src/H5FL.c b/src/H5FL.c
index 1045658..dca300c 100644
--- a/src/H5FL.c
+++ b/src/H5FL.c
@@ -52,6 +52,8 @@ static size_t H5FL_arr_glb_mem_lim=4*1024*1024; /* Default to 4MB limit on all a
static size_t H5FL_arr_lst_mem_lim=4*65536; /* Default to 256KB limit on each array free list */
static size_t H5FL_blk_glb_mem_lim=16*1024*1024; /* Default to 16MB limit on all block free lists */
static size_t H5FL_blk_lst_mem_lim=1024*1024; /* Default to 1024KB (1MB) limit on each block free list */
+static size_t H5FL_fac_glb_mem_lim=16*1024*1024; /* Default to 16MB limit on all factory free lists */
+static size_t H5FL_fac_lst_mem_lim=1024*1024; /* Default to 1024KB (1MB) limit on each factory free list */
/* A garbage collection node for regular free lists */
typedef struct H5FL_reg_gc_node_t {
@@ -98,6 +100,36 @@ typedef struct H5FL_blk_gc_list_t {
/* The head of the list of PQs to garbage collect */
static H5FL_blk_gc_list_t H5FL_blk_gc_head={0,NULL};
+/* A garbage collection node for factory free lists */
+typedef struct H5FL_fac_gc_node_t {
+ H5FL_fac_head_t *list; /* Pointer to the head of the list to garbage collect */
+ struct H5FL_fac_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
+} H5FL_fac_gc_node_t;
+
+/* The garbage collection head for factory free lists */
+typedef struct H5FL_fac_gc_list_t {
+ size_t mem_freed; /* Amount of free memory on list */
+ struct H5FL_fac_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
+} H5FL_fac_gc_list_t;
+
+/* Data structure to store each block in factory free list */
+typedef struct H5FL_fac_node_t {
+ struct H5FL_fac_node_t *next; /* Pointer to next block in free list */
+} H5FL_fac_node_t;
+
+/* Data structure for free list block factory */
+struct H5FL_fac_head_t {
+ unsigned init; /* Whether the free list has been initialized */
+ unsigned allocated; /* Number of blocks allocated */
+ unsigned onlist; /* Number of blocks on free list */
+ size_t size; /* Size of the blocks in the list */
+ H5FL_fac_node_t *list; /* List of free blocks */
+ H5FL_fac_gc_node_t *prev_gc; /* Previous garbage collection node in list */
+};
+
+/* The head of the list of factory things to garbage collect */
+static H5FL_fac_gc_list_t H5FL_fac_gc_head={0,NULL};
+
#ifdef H5FL_TRACK
/* Extra headers needed */
@@ -114,14 +146,18 @@ 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);
static herr_t H5FL_blk_gc_list(H5FL_blk_head_t *head);
-static herr_t H5FL_blk_unlink(H5FL_blk_head_t *pq);
-
-/* Declare a free list to manage the H5FL_fac_head_t struct */
-H5FL_DEFINE(H5FL_fac_head_t);
+static herr_t H5FL_fac_gc(void);
+static herr_t H5FL_fac_gc_list(H5FL_fac_head_t *head);
/* Declare a free list to manage the H5FL_blk_node_t struct */
H5FL_DEFINE(H5FL_blk_node_t);
+/* Declare a free list to manage the H5FL_fac_gc_node_t struct */
+H5FL_DEFINE(H5FL_fac_gc_node_t);
+
+/* Declare a free list to manage the H5FL_fac_head_t struct */
+H5FL_DEFINE(H5FL_fac_head_t);
+
/*--------------------------------------------------------------------------
NAME
@@ -225,15 +261,15 @@ H5FL_reg_init(H5FL_reg_head_t *head)
/* Indicate that the free list is initialized */
head->init=1;
+ /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */
+ if(head->size<sizeof(H5FL_reg_node_t))
+ head->size=sizeof(H5FL_reg_node_t);
+
/* Make certain there's room for tracking information, if any */
#ifdef H5FL_TRACK
head->size += sizeof(H5FL_track_t);
#endif /* H5FL_TRACK */
- /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */
- if(head->size<sizeof(void *))
- head->size=sizeof(void *);
-
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FL_reg_init() */
@@ -259,11 +295,13 @@ H5FL_reg_free(H5FL_reg_head_t *head, void *obj)
{
void *ret_value=NULL; /* Return value */
- FUNC_ENTER_NOAPI(H5FL_reg_free, NULL)
+ /* NOINIT OK here because this must be called after H5FL_reg_malloc/calloc
+ * -NAF */
+ FUNC_ENTER_NOAPI_NOINIT(H5FL_reg_free)
/* Double check parameters */
- assert(head);
- assert(obj);
+ HDassert(head);
+ HDassert(obj);
#ifdef H5FL_TRACK
{
@@ -294,7 +332,7 @@ H5FL_reg_free(H5FL_reg_head_t *head, void *obj)
#endif /* H5FL_DEBUG */
/* Make certain that the free list is initialized */
- assert(head->init);
+ HDassert(head->init);
/* Link into the free list */
((H5FL_reg_node_t *)obj)->next=head->list;
@@ -302,16 +340,15 @@ H5FL_reg_free(H5FL_reg_head_t *head, void *obj)
/* Point free list at the node freed */
head->list=(H5FL_reg_node_t *)obj;
- /* Increment the number of blocks & memory on free list */
+ /* Increment the number of blocks on free list */
head->onlist++;
- head->list_mem+=head->size;
/* Increment the amount of "regular" freed memory globally */
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)
+ if(head->onlist * head->size > H5FL_reg_lst_mem_lim)
if(H5FL_reg_gc_list(head)<0)
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
@@ -348,7 +385,7 @@ H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS)
FUNC_ENTER_NOAPI(H5FL_reg_malloc, NULL)
/* Double check parameters */
- assert(head);
+ HDassert(head);
/* Make certain the list is initialized first */
if(!head->init)
@@ -365,7 +402,6 @@ H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS)
/* Decrement the number of blocks & memory on free list */
head->onlist--;
- head->list_mem-=head->size;
/* Decrement the amount of global "regular" free list memory in use */
H5FL_reg_gc_head.mem_freed-=(head->size);
@@ -426,7 +462,7 @@ H5FL_reg_calloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS)
FUNC_ENTER_NOAPI(H5FL_reg_calloc, NULL)
/* Double check parameters */
- assert(head);
+ HDassert(head);
/* Allocate the block */
if (NULL==(ret_value = H5FL_reg_malloc(head H5FL_TRACK_INFO_INT)))
@@ -476,17 +512,11 @@ H5FL_reg_gc_list(H5FL_reg_head_t *head)
/* Decrement the count of nodes allocated and free the node */
head->allocated--;
- /* Decrement count of free memory on this list */
- head->list_mem-=head->size;
-
- H5MM_xfree(free_list);
+ H5MM_free(free_list);
free_list = (H5FL_reg_node_t *)tmp;
} /* end while */
- /* Double check that all the memory on this list is recycled */
- HDassert(0 == head->list_mem);
-
/* Indicate no free nodes on the free list */
head->list=NULL;
head->onlist=0;
@@ -535,7 +565,7 @@ H5FL_reg_gc(void)
} /* end while */
/* Double check that all the memory on the free lists is recycled */
- assert(H5FL_reg_gc_head.mem_freed==0);
+ HDassert(H5FL_reg_gc_head.mem_freed==0);
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -797,7 +827,7 @@ H5FL_blk_free_block_avail(H5FL_blk_head_t *head, size_t size)
FUNC_ENTER_NOAPI(H5FL_blk_free_block_avail, FAIL)
/* Double check parameters */
- assert(head);
+ HDassert(head);
/* check if there is a free list for blocks of this size */
/* and if there are any blocks available on the list */
@@ -838,8 +868,8 @@ H5FL_blk_malloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS)
FUNC_ENTER_NOAPI(H5FL_blk_malloc, NULL)
/* Double check parameters */
- assert(head);
- assert(size);
+ HDassert(head);
+ HDassert(size);
/* Make certain the list is initialized first */
if(!head->init)
@@ -928,8 +958,8 @@ H5FL_blk_calloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS)
FUNC_ENTER_NOAPI(H5FL_blk_calloc, NULL)
/* Double check parameters */
- assert(head);
- assert(size);
+ HDassert(head);
+ HDassert(size);
/* Allocate the block */
if (NULL==(ret_value = H5FL_blk_malloc(head,size H5FL_TRACK_INFO_INT)))
@@ -969,11 +999,13 @@ H5FL_blk_free(H5FL_blk_head_t *head, void *block)
size_t free_size; /* Size of the block freed */
void *ret_value=NULL; /* Return value */
- FUNC_ENTER_NOAPI(H5FL_blk_free, NULL)
+ /* NOINIT OK here because this must be called after H5FL_blk_malloc/calloc
+ * -NAF */
+ FUNC_ENTER_NOAPI_NOINIT(H5FL_blk_free)
/* Double check parameters */
- assert(head);
- assert(block);
+ HDassert(head);
+ HDassert(block);
#ifdef H5FL_TRACK
{
@@ -1070,8 +1102,8 @@ H5FL_blk_realloc(H5FL_blk_head_t *head, void *block, size_t new_size H5FL_TRACK_
FUNC_ENTER_NOAPI(H5FL_blk_realloc, NULL)
/* Double check parameters */
- assert(head);
- assert(new_size);
+ HDassert(head);
+ HDassert(new_size);
/* Check if we are actually re-allocating a block */
if(block!=NULL) {
@@ -1119,67 +1151,6 @@ done:
} /* end H5FL_blk_realloc() */
-/*--------------------------------------------------------------------------
- NAME
- H5FL_blk_unlink
- PURPOSE
- Remove a block free list from the global list of initialized block free
- lists.
- USAGE
- void H5FL_blk_unlink(H5FL_blk_head_t *pq)
- H5FL_blk_head_t *pq; IN: Block free list to remove from global list
- RETURNS
- Success: Non-negative
- Failure: Negative
- DESCRIPTION
- Search through the global list of initialized block free lists and remove
- a particular free list.
- GLOBAL VARIABLES
- COMMENTS, BUGS, ASSUMPTIONS
- EXAMPLES
- REVISION LOG
---------------------------------------------------------------------------*/
-static herr_t
-H5FL_blk_unlink(H5FL_blk_head_t *pq)
-{
- H5FL_blk_gc_node_t *last; /* Pointer to the last garbage collection node examined */
- H5FL_blk_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
- herr_t ret_value=SUCCEED; /* Return value */
-
- FUNC_ENTER_NOAPI_NOINIT(H5FL_blk_unlink)
-
- /* Find the node to remove from the global list */
- last=NULL;
- tmp=H5FL_blk_gc_head.first;
- while(tmp!=NULL) {
- /* Check if the list has allocations outstanding */
- if(tmp->pq==pq) {
- /* Unlink node from linked list */
- if(last==NULL)
- H5FL_blk_gc_head.first=H5FL_blk_gc_head.first->next;
- else
- last->next=tmp->next;
-
- /* Free the block node */
- H5MM_xfree(tmp);
-
- /* Leave now */
- break;
- } /* end if */
-
- /* Advance to next node in list */
- last=tmp;
- tmp=tmp->next;
- } /* end while */
-
- if(tmp==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't release block free list")
-
-done:
- FUNC_LEAVE_NOAPI(ret_value);
-} /* end H5FL_blk_unlink() */
-
-
/*-------------------------------------------------------------------------
* Function: H5FL_blk_gc_list
*
@@ -1221,7 +1192,7 @@ H5FL_blk_gc_list(H5FL_blk_head_t *head)
H5FL_blk_gc_head.mem_freed-=head->head->size;
/* Free the block */
- H5MM_xfree(list);
+ H5MM_free(list);
list = (H5FL_blk_list_t *)next;
} /* end while */
@@ -1279,7 +1250,7 @@ H5FL_blk_gc(void)
} /* end while */
/* Double check that all the memory on the free lists are recycled */
- assert(H5FL_blk_gc_head.mem_freed==0);
+ HDassert(H5FL_blk_gc_head.mem_freed==0);
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -1334,7 +1305,7 @@ printf("H5FL_blk_term: head->name=%s, head->allocated=%d\n", H5FL_blk_gc_head.fi
H5FL_blk_gc_head.first->pq->init=0;
/* Free the node from the garbage collection list */
- H5MM_xfree(H5FL_blk_gc_head.first);
+ H5MM_free(H5FL_blk_gc_head.first);
} /* end else */
H5FL_blk_gc_head.first=tmp;
@@ -1422,17 +1393,19 @@ H5FL_arr_free(H5FL_arr_head_t *head, void *obj)
size_t free_nelem; /* Number of elements in node being free'd */
void *ret_value=NULL; /* Return value */
- FUNC_ENTER_NOAPI(H5FL_arr_free, NULL)
+ /* NOINIT OK here because this must be called after H5FL_arr_malloc/calloc
+ * -NAF */
+ FUNC_ENTER_NOAPI_NOINIT(H5FL_arr_free)
/* The H5MM_xfree code allows obj to null */
if (!obj)
HGOTO_DONE (NULL)
/* Double check parameters */
- assert(head);
+ HDassert(head);
/* Make certain that the free list is initialized */
- assert(head->init);
+ HDassert(head->init);
/* Get the pointer to the info header in front of the block to free */
temp=(H5FL_arr_list_t *)((unsigned char *)obj-sizeof(H5FL_arr_list_t)); /*lint !e826 Pointer-to-pointer cast is appropriate here */
@@ -1441,7 +1414,7 @@ H5FL_arr_free(H5FL_arr_head_t *head, void *obj)
free_nelem=temp->nelem;
/* Double-check that there is enough room for arrays of this size */
- assert((int)free_nelem<=head->maxelem);
+ HDassert((int)free_nelem<=head->maxelem);
/* Link into the free list */
temp->next=head->list_arr[free_nelem].list;
@@ -1500,8 +1473,8 @@ H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem)
FUNC_ENTER_NOAPI(H5FL_arr_malloc, NULL)
/* Double check parameters */
- assert(head);
- assert(elem);
+ HDassert(head);
+ HDassert(elem);
/* Make certain the list is initialized first */
if(!head->init)
@@ -1509,7 +1482,7 @@ H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem)
HGOTO_ERROR (H5E_RESOURCE, H5E_CANTINIT, NULL, "can't initialize 'array' blocks")
/* Sanity check that the number of elements is supported */
- assert(elem<=(unsigned) head->maxelem);
+ HDassert(elem<=(unsigned) head->maxelem);
/* Get the set of the memory block */
mem_size=head->list_arr[elem].size;
@@ -1573,8 +1546,8 @@ H5FL_arr_calloc(H5FL_arr_head_t *head, size_t elem)
FUNC_ENTER_NOAPI(H5FL_arr_calloc, NULL)
/* Double check parameters */
- assert(head);
- assert(elem);
+ HDassert(head);
+ HDassert(elem);
/* Allocate the array */
if (NULL==(ret_value = H5FL_arr_malloc(head,elem)))
@@ -1611,8 +1584,8 @@ H5FL_arr_realloc(H5FL_arr_head_t *head, void * obj, size_t new_elem)
FUNC_ENTER_NOAPI(H5FL_arr_realloc, NULL)
/* Double check parameters */
- assert(head);
- assert(new_elem);
+ HDassert(head);
+ HDassert(new_elem);
/* Check if we are really allocating the object */
if(obj==NULL)
@@ -1621,7 +1594,7 @@ H5FL_arr_realloc(H5FL_arr_head_t *head, void * obj, size_t new_elem)
H5FL_arr_list_t *temp; /* Temp. ptr to the new free list node allocated */
/* Sanity check that the number of elements is supported */
- assert((int)new_elem<=head->maxelem);
+ HDassert((int)new_elem<=head->maxelem);
/* Get the pointer to the info header in front of the block to free */
temp=(H5FL_arr_list_t *)((unsigned char *)obj-sizeof(H5FL_arr_list_t)); /*lint !e826 Pointer-to-pointer cast is appropriate here */
@@ -1687,7 +1660,7 @@ H5FL_arr_gc_list(H5FL_arr_head_t *head)
/* Decrement the count of nodes allocated and free the node */
head->allocated--;
- H5MM_xfree(arr_free_list);
+ H5MM_free(arr_free_list);
arr_free_list = (H5FL_arr_list_t *)tmp;
} /* end while */
@@ -1705,7 +1678,7 @@ H5FL_arr_gc_list(H5FL_arr_head_t *head)
} /* end for */
/* Double check that all the memory on this list is recycled */
- assert(head->list_mem==0);
+ HDassert(head->list_mem==0);
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5FL_arr_gc_list() */
@@ -1746,7 +1719,7 @@ H5FL_arr_gc(void)
} /* end while */
/* Double check that all the memory on the free lists are recycled */
- assert(H5FL_arr_gc_head.mem_freed==0);
+ HDassert(H5FL_arr_gc_head.mem_freed==0);
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -1803,7 +1776,7 @@ printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head.fi
H5FL_arr_gc_head.first->list->init=0;
/* Free the node from the garbage collection list */
- H5MM_xfree(H5FL_arr_gc_head.first);
+ H5MM_free(H5FL_arr_gc_head.first);
} /* end else */
H5FL_arr_gc_head.first=tmp;
@@ -1834,14 +1807,16 @@ printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head.fi
void *
H5FL_seq_free(H5FL_seq_head_t *head, void *obj)
{
+ /* NOINIT OK here because this must be called after H5FL_seq_malloc/calloc
+ * -NAF */
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_seq_free)
/* Double check parameters */
- assert(head);
- assert(obj);
+ HDassert(head);
+ HDassert(obj);
/* Make certain that the free list is initialized */
- assert(head->queue.init);
+ HDassert(head->queue.init);
/* Use block routine */
H5FL_blk_free(&(head->queue),obj);
@@ -1873,8 +1848,8 @@ H5FL_seq_malloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS)
FUNC_ENTER_NOAPI(H5FL_seq_malloc, NULL)
/* Double check parameters */
- assert(head);
- assert(elem);
+ HDassert(head);
+ HDassert(elem);
/* Use block routine */
ret_value=H5FL_blk_malloc(&(head->queue),head->size*elem H5FL_TRACK_INFO_INT);
@@ -1907,8 +1882,8 @@ H5FL_seq_calloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS)
FUNC_ENTER_NOAPI(H5FL_seq_calloc, NULL)
/* Double check parameters */
- assert(head);
- assert(elem);
+ HDassert(head);
+ HDassert(elem);
/* Use block routine */
ret_value=H5FL_blk_calloc(&(head->queue),head->size*elem H5FL_TRACK_INFO_INT);
@@ -1941,8 +1916,8 @@ H5FL_seq_realloc(H5FL_seq_head_t *head, void * obj, size_t new_elem H5FL_TRACK_P
FUNC_ENTER_NOAPI(H5FL_seq_realloc, NULL)
/* Double check parameters */
- assert(head);
- assert(new_elem);
+ HDassert(head);
+ HDassert(new_elem);
/* Use block routine */
ret_value=H5FL_blk_realloc(&(head->queue),obj,head->size*new_elem H5FL_TRACK_INFO_INT);
@@ -1964,14 +1939,18 @@ done:
* Wednesday, February 2, 2005
*
* Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
*
*-------------------------------------------------------------------------
*/
H5FL_fac_head_t *
H5FL_fac_init(size_t size)
{
- H5FL_fac_head_t *factory; /* Pointer to new block factory */
- H5FL_fac_head_t *ret_value; /* Return value */
+ H5FL_fac_gc_node_t *new_node; /* Pointer to the node for the new list to garbage collect */
+ H5FL_fac_head_t *factory; /* Pointer to new block factory */
+ H5FL_fac_head_t *ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5FL_fac_init, NULL)
@@ -1979,15 +1958,38 @@ H5FL_fac_init(size_t size)
HDassert(size>0);
/* Allocate room for the new factory */
- if(NULL==(factory=H5FL_MALLOC(H5FL_fac_head_t)))
+ if(NULL == (factory = (H5FL_fac_head_t *)H5FL_CALLOC(H5FL_fac_head_t)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for factory object")
- /* Initialize block header information */
- HDmemset(&(factory->queue),0,sizeof(H5FL_blk_head_t));
-
/* Set size of blocks for factory */
factory->size=size;
+ /* Allocate a new garbage collection node */
+ if(NULL == (new_node = (H5FL_fac_gc_node_t *)H5FL_MALLOC(H5FL_fac_gc_node_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Initialize the new garbage collection node */
+ new_node->list = factory;
+
+ /* Link in to the garbage collection list */
+ new_node->next=H5FL_fac_gc_head.first;
+ H5FL_fac_gc_head.first=new_node;
+ if(new_node->next)
+ new_node->next->list->prev_gc=new_node;
+ /* The new factory's prev_gc field will be set to NULL */
+
+ /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */
+ if(factory->size<sizeof(H5FL_fac_node_t))
+ factory->size=sizeof(H5FL_fac_node_t);
+
+ /* Make certain there's room for tracking information, if any */
+#ifdef H5FL_TRACK
+ factory->size += sizeof(H5FL_track_t);
+#endif /* H5FL_TRACK */
+
+ /* Indicate that the free list is initialized */
+ factory->init=1;
+
/* Set return value */
ret_value=factory;
@@ -2001,32 +2003,86 @@ done:
*
* Purpose: Release a block back to a factory & put on free list
*
- * Return: Success: Non-negative
- * Failure: Negative
+ * Return: NULL
*
* Programmer: Quincey Koziol
* Wednesday, February 2, 2005
*
* Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
*
*-------------------------------------------------------------------------
*/
void *
H5FL_fac_free(H5FL_fac_head_t *head, void *obj)
{
- FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_fac_free)
+ void *ret_value=NULL; /* Return value */
+
+ /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */
+ FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_free)
/* Double check parameters */
- assert(head);
- assert(obj);
+ HDassert(head);
+ HDassert(obj);
+
+#ifdef H5FL_TRACK
+ {
+ H5FL_track_t *trk = obj = ((unsigned char *)obj) - sizeof(H5FL_track_t);
+
+ /* Free tracking information about the allocation location */
+ H5CS_close_stack(trk->stack);
+ trk->stack = H5MM_xfree(trk->stack);
+ trk->file = H5MM_xfree(trk->file);
+ trk->func = H5MM_xfree(trk->func);
+
+ /* Remove from "outstanding allocations" list */
+ if(trk == H5FL_out_head_g) {
+ H5FL_out_head_g = H5FL_out_head_g->next;
+ if(H5FL_out_head_g)
+ H5FL_out_head_g->prev = NULL;
+ } /* end if */
+ else {
+ trk->prev->next = trk->next;
+ if(trk->next)
+ trk->next->prev = trk->prev;
+ } /* end else */
+ }
+#endif /* H5FL_TRACK */
+
+#ifdef H5FL_DEBUG
+ HDmemset(obj,255,head->size);
+#endif /* H5FL_DEBUG */
/* Make certain that the free list is initialized */
- assert(head->queue.init);
+ HDassert(head->init);
- /* Use block routine */
- H5FL_blk_free(&(head->queue),obj);
+ /* Link into the free list */
+ ((H5FL_fac_node_t *)obj)->next=head->list;
- FUNC_LEAVE_NOAPI(NULL)
+ /* Point free list at the node freed */
+ head->list=(H5FL_fac_node_t *)obj;
+
+ /* Increment the number of blocks on free list */
+ head->onlist++;
+
+ /* Increment the amount of "factory" freed memory globally */
+ H5FL_fac_gc_head.mem_freed+=head->size;
+
+ /* Check for exceeding free list memory use limits */
+ /* First check this particular list */
+ if(head->onlist * head->size > H5FL_fac_lst_mem_lim)
+ if(H5FL_fac_gc_list(head)<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+ /* Then check the global amount memory on factory free lists */
+ if(H5FL_fac_gc_head.mem_freed > H5FL_fac_glb_mem_lim)
+ if(H5FL_fac_gc()<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FL_fac_free() */
@@ -2042,6 +2098,9 @@ H5FL_fac_free(H5FL_fac_head_t *head, void *obj)
* Wednesday, February 2, 2005
*
* Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
*
*-------------------------------------------------------------------------
*/
@@ -2050,13 +2109,54 @@ H5FL_fac_malloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS)
{
void *ret_value; /* Pointer to object to return */
- FUNC_ENTER_NOAPI(H5FL_fac_malloc, NULL)
+ /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */
+ FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_malloc)
/* Double check parameters */
- assert(head);
+ HDassert(head);
+ HDassert(head->init);
- /* Use block routine */
- ret_value=H5FL_blk_malloc(&(head->queue),head->size H5FL_TRACK_INFO_INT);
+ /* 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=(void *)(head->list);
+
+ /* Remove node from free list */
+ head->list=head->list->next;
+
+ /* Decrement the number of blocks & memory on free list */
+ head->onlist--;
+
+ /* Decrement the amount of global "factory" free list memory in use */
+ H5FL_fac_gc_head.mem_freed-=(head->size);
+ } /* end if */
+ /* Otherwise allocate a node */
+ else {
+ if (NULL==(ret_value = H5FL_malloc(head->size)))
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Increment the number of blocks allocated in list */
+ head->allocated++;
+ } /* end else */
+
+#ifdef H5FL_TRACK
+ /* Copy allocation location information */
+ ((H5FL_track_t *)ret_value)->stack = H5MM_calloc(sizeof(H5CS_t));
+ H5CS_copy_stack(((H5FL_track_t *)ret_value)->stack);
+ ((H5FL_track_t *)ret_value)->file = H5MM_strdup(call_file);
+ ((H5FL_track_t *)ret_value)->func = H5MM_strdup(call_func);
+ ((H5FL_track_t *)ret_value)->line = call_line;
+
+ /* Add to "outstanding allocations" list */
+ ((H5FL_track_t *)ret_value)->prev = NULL;
+ ((H5FL_track_t *)ret_value)->next = H5FL_out_head_g;
+ if(H5FL_out_head_g)
+ H5FL_out_head_g->prev = (H5FL_track_t *)ret_value;
+ H5FL_out_head_g = (H5FL_track_t *)ret_value;
+
+ /* Adjust for allocation tracking information */
+ ret_value = ((unsigned char *)ret_value) + sizeof(H5FL_track_t);
+#endif /* H5FL_TRACK */
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -2075,6 +2175,9 @@ done:
* Wednesday, February 2, 2005
*
* Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
*
*-------------------------------------------------------------------------
*/
@@ -2083,17 +2186,115 @@ H5FL_fac_calloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS)
{
void *ret_value; /* Pointer to object to return */
- FUNC_ENTER_NOAPI(H5FL_fac_calloc, NULL)
+ /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */
+ FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_calloc)
/* Double check parameters */
- assert(head);
+ HDassert(head);
- /* Use block routine */
- ret_value=H5FL_blk_calloc(&(head->queue),head->size H5FL_TRACK_INFO_INT);
+ /* Allocate the block */
+ if (NULL==(ret_value = H5FL_fac_malloc(head H5FL_TRACK_INFO_INT)))
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Clear to zeros */
+ /* (Accomodate tracking information, if present) */
+ HDmemset(ret_value,0,head->size - H5FL_TRACK_SIZE);
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FL_fac_calloc() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_fac_gc_list
+ *
+ * Purpose: Garbage collect on a particular factory free list
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Friday, December 19, 2008
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL_fac_gc_list(H5FL_fac_head_t *head)
+{
+ H5FL_fac_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_NOAPI_NOINIT_NOFUNC(H5FL_fac_gc_list)
+
+ /* Calculate the total memory used on this list */
+ total_mem=head->onlist*head->size;
+
+ /* For each free list being garbage collected, walk through the nodes and free them */
+ free_list=head->list;
+ while(free_list!=NULL) {
+ tmp=free_list->next;
+
+ /* Decrement the count of nodes allocated and free the node */
+ head->allocated--;
+
+ H5MM_free(free_list);
+
+ free_list = (H5FL_fac_node_t *)tmp;
+ } /* end while */
+
+ /* Indicate no free nodes on the free list */
+ head->list=NULL;
+ head->onlist=0;
+
+ /* Decrement global count of free memory on "factory" lists */
+ H5FL_fac_gc_head.mem_freed-=total_mem;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FL_fac_gc_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_fac_gc
+ *
+ * Purpose: Garbage collect on all the factory free lists
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Neil Fortner
+ * Friday, December 19, 2008
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL_fac_gc(void)
+{
+ H5FL_fac_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */
+ herr_t ret_value=SUCCEED; /* return value*/
+
+ FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_gc)
+
+ /* Walk through all the free lists, free()'ing the nodes */
+ gc_node=H5FL_fac_gc_head.first;
+ while(gc_node!=NULL) {
+ /* Release the free nodes on the list */
+ if(H5FL_fac_gc_list(gc_node->list)<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of list failed")
+
+ /* 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 */
+ HDassert(H5FL_fac_gc_head.mem_freed==0);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FL_fac_gc() */
/*-------------------------------------------------------------------------
@@ -2108,29 +2309,50 @@ done:
* Wednesday, February 2, 2005
*
* Modifications:
+ * Neil Fortner
+ * Friday, December 19, 2008
+ * Totally rewritten to support new factory implementation
*
*-------------------------------------------------------------------------
*/
herr_t
H5FL_fac_term(H5FL_fac_head_t *factory)
{
- herr_t ret_value=SUCCEED; /* Return value */
+ H5FL_fac_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
+ herr_t ret_value = SUCCEED; /* Return value */
+ /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */
FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_term)
/* Sanity check */
HDassert(factory);
/* Garbage collect all the blocks in the factory's free list */
- if(H5FL_blk_gc_list(&(factory->queue))<0)
+ if(H5FL_fac_gc_list(factory)<0)
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of factory failed")
/* Verify that all the blocks have been freed */
- if(factory->queue.allocated>0)
+ if(factory->allocated>0)
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "factory still has objects allocated")
/* Unlink block free list for factory from global free list */
- H5FL_blk_unlink(&(factory->queue));
+ if(factory->prev_gc) {
+ H5FL_fac_gc_node_t *last = factory->prev_gc; /* Garbage collection node before the one being removed */
+
+ HDassert(last->next->list == factory);
+ tmp = last->next->next;
+ (void)H5FL_FREE(H5FL_fac_gc_node_t, last->next);
+ last->next = tmp;
+ if(tmp)
+ tmp->list->prev_gc = last;
+ } else {
+ HDassert(H5FL_fac_gc_head.first->list == factory);
+ tmp = H5FL_fac_gc_head.first->next;
+ (void)H5FL_FREE(H5FL_fac_gc_node_t, H5FL_fac_gc_head.first);
+ H5FL_fac_gc_head.first = tmp;
+ if(tmp)
+ tmp->list->prev_gc = NULL;
+ } /* end else */
/* Free factory info */
(void)H5FL_FREE(H5FL_fac_head_t, factory);
@@ -2141,6 +2363,52 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5FL_fac_term_all
+ *
+ * Purpose: Terminate all block factories
+ *
+ * Return: 0. There should never be any outstanding allocations
+ * when this is called.
+ *
+ * Programmer: Neil Fortner
+ * Friday, December 19, 2008
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FL_fac_term_all(void)
+{
+ H5FL_fac_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_fac_term_all)
+
+ /* Free the nodes on the garbage collection list */
+ while(H5FL_fac_gc_head.first != NULL) {
+ tmp=H5FL_fac_gc_head.first->next;
+
+#ifdef H5FL_DEBUG
+printf("H5FL_fac_term: head->size=%d, head->allocated=%d\n", (int)H5FL_fac_gc_head.first->list->size,(int)H5FL_fac_gc_head.first->list->allocated);
+#endif /* H5FL_DEBUG */
+
+ /* The list cannot have any allocations outstanding */
+ HDassert(H5FL_fac_gc_head.first->list->allocated == 0);
+
+ /* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
+ H5FL_fac_gc_head.first->list->init = 0;
+
+ /* Free the node from the garbage collection list */
+ (void)H5FL_FREE(H5FL_fac_gc_node_t, H5FL_fac_gc_head.first);
+
+ H5FL_fac_gc_head.first = tmp;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(0)
+} /* end H5FL_fac_term_all() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5FL_garbage_coll
*
* Purpose: Garbage collect on all the free lists
@@ -2160,7 +2428,7 @@ H5FL_garbage_coll(void)
{
herr_t ret_value = SUCCEED;
- FUNC_ENTER_NOAPI_NOINIT(H5FL_garbage_coll)
+ FUNC_ENTER_NOAPI(H5FL_garbage_coll, FAIL)
/* Garbage collect the free lists for array objects */
if(H5FL_arr_gc()<0)
@@ -2174,6 +2442,10 @@ H5FL_garbage_coll(void)
if(H5FL_reg_gc()<0)
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect regular objects")
+ /* Garbage collect the free lists for factory objects */
+ if(H5FL_fac_gc()<0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect regular objects")
+
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FL_garbage_coll() */
@@ -2204,13 +2476,16 @@ done:
* Programmer: Quincey Koziol
* Wednesday, August 2, 2000
*
- * Modifications:
+ * Modifications: Neil Fortner
+ * Wednesday, April 8, 2009
+ * Added support for factory free lists
*
*-------------------------------------------------------------------------
*/
herr_t
H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim,
- int arr_list_lim, int blk_global_lim, int blk_list_lim)
+ int arr_list_lim, int blk_global_lim, int blk_list_lim, int fac_global_lim,
+ int fac_list_lim)
{
herr_t ret_value = SUCCEED;
@@ -2229,6 +2504,10 @@ H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_l
H5FL_blk_glb_mem_lim=(blk_global_lim==-1 ? UINT_MAX : (size_t)blk_global_lim);
/* limit on each block free list */
H5FL_blk_lst_mem_lim=(blk_list_lim==-1 ? UINT_MAX : (size_t)blk_list_lim);
+ /* limit on all factory free lists */
+ H5FL_fac_glb_mem_lim=(fac_global_lim==-1 ? UINT_MAX : (size_t)fac_global_lim);
+ /* limit on each factory free list */
+ H5FL_fac_lst_mem_lim=(fac_list_lim==-1 ? UINT_MAX : (size_t)fac_list_lim);
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -2264,7 +2543,7 @@ H5FL_term_interface(void)
/* Garbage collect any nodes on the free lists */
(void)H5FL_garbage_coll();
- ret_value=H5FL_reg_term()+H5FL_arr_term()+H5FL_blk_term();
+ ret_value=H5FL_reg_term()+H5FL_fac_term_all()+H5FL_arr_term()+H5FL_blk_term();
#ifdef H5FL_TRACK
/* If we haven't freed all the allocated memory, dump out the list now */
diff --git a/src/H5FLprivate.h b/src/H5FLprivate.h
index a799dc4..c1a865a 100644
--- a/src/H5FLprivate.h
+++ b/src/H5FLprivate.h
@@ -100,7 +100,6 @@ typedef struct H5FL_reg_head_t {
unsigned init; /* Whether the free list has been initialized */
unsigned allocated; /* Number of blocks allocated */
unsigned 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_reg_node_t *list; /* List of free blocks */
@@ -112,7 +111,7 @@ typedef struct H5FL_reg_head_t {
#define H5FL_REG_NAME(t) H5_##t##_reg_free_list
#ifndef H5_NO_REG_FREE_LISTS
/* Common macros for H5FL_DEFINE & H5FL_DEFINE_STATIC */
-#define H5FL_DEFINE_COMMON(t) H5FL_reg_head_t H5FL_REG_NAME(t)={0,0,0,0,#t,sizeof(t),NULL}
+#define H5FL_DEFINE_COMMON(t) H5FL_reg_head_t H5FL_REG_NAME(t)={0,0,0,#t,sizeof(t),NULL}
/* Declare a free list to manage objects of type 't' */
#define H5FL_DEFINE(t) H5_DLL H5FL_DEFINE_COMMON(t)
@@ -349,11 +348,8 @@ typedef struct H5FL_seq_head_t {
#define H5FL_SEQ_REALLOC(t,obj,new_elem) (t *)H5MM_realloc(obj,(new_elem)*sizeof(t))
#endif /* H5_NO_SEQ_FREE_LISTS */
-/* Data structure for free list block factory */
-typedef struct H5FL_fac_head_t {
- H5FL_blk_head_t queue; /* Priority queue of blocks */
- size_t size; /* Size of the blocks managed */
-} H5FL_fac_head_t;
+/* Forward declaration of the data structure for free list block factory */
+typedef struct H5FL_fac_head_t H5FL_fac_head_t;
/*
* Macros for defining & using free list factories
@@ -381,30 +377,42 @@ typedef struct H5FL_fac_head_t {
/*
* Library prototypes.
*/
+ /* Block free lists */
H5_DLL void * H5FL_blk_malloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS);
H5_DLL void * H5FL_blk_calloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS);
H5_DLL void * H5FL_blk_free(H5FL_blk_head_t *head, void *block);
H5_DLL void * H5FL_blk_realloc(H5FL_blk_head_t *head, void *block, size_t new_size H5FL_TRACK_PARAMS);
H5_DLL htri_t H5FL_blk_free_block_avail(H5FL_blk_head_t *head, size_t size);
+
+/* Regular free lists */
H5_DLL void * H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS);
H5_DLL void * H5FL_reg_calloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS);
H5_DLL void * H5FL_reg_free(H5FL_reg_head_t *head, void *obj);
+
+/* Array free lists */
H5_DLL void * H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem);
H5_DLL void * H5FL_arr_calloc(H5FL_arr_head_t *head, size_t elem);
H5_DLL void * H5FL_arr_free(H5FL_arr_head_t *head, void *obj);
H5_DLL void * H5FL_arr_realloc(H5FL_arr_head_t *head, void *obj, size_t new_elem);
+
+/* Sequence free lists */
H5_DLL void * H5FL_seq_malloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS);
H5_DLL void * H5FL_seq_calloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS);
H5_DLL void * H5FL_seq_free(H5FL_seq_head_t *head, void *obj);
H5_DLL void * H5FL_seq_realloc(H5FL_seq_head_t *head, void *obj, size_t new_elem H5FL_TRACK_PARAMS);
+
+/* Factory free lists */
H5_DLL H5FL_fac_head_t *H5FL_fac_init(size_t size);
H5_DLL void * H5FL_fac_malloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS);
H5_DLL void * H5FL_fac_calloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS);
H5_DLL void * H5FL_fac_free(H5FL_fac_head_t *head, void *obj);
H5_DLL herr_t H5FL_fac_term(H5FL_fac_head_t *head);
+
+/* General free list routines */
H5_DLL herr_t H5FL_garbage_coll(void);
H5_DLL herr_t H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim,
- int arr_global_lim, int arr_list_lim, int blk_global_lim, int blk_list_lim);
+ int arr_global_lim, int arr_list_lim, int blk_global_lim, int blk_list_lim,
+ int fac_global_lim, int fac_list_lim);
H5_DLL int H5FL_term_interface(void);
#endif