rvobjpool.c

来自「基于h323协议的软phone」· C语言 代码 · 共 831 行 · 第 1/2 页

C
831
字号
/***********************************************************************
Filename   : rvobjpool.c
Description: utility for building pools of objects (structures)
************************************************************************
      Copyright (c) 2001,2002 RADVISION Inc. and RADVISION Ltd.
************************************************************************
NOTICE:
This document contains information that is confidential and proprietary
to RADVISION Inc. and RADVISION Ltd.. No part of this document may be
reproduced in any form whatsoever without written prior approval by
RADVISION Inc. or RADVISION Ltd..

RADVISION Inc. and RADVISION Ltd. reserve the right to revise this
publication and make changes without obligation to notify any person of
such revisions or changes.
***********************************************************************/
#include "rvobjpool.h"
#include <string.h>

/* Basic pool utility for structures. User is responsible for locking */
/* if pool is to be shared. */

/* Define additional data to be stored with each page. The OVERHEAD size */
/* must account for proper alignment of the items. */
typedef struct {
	RvObjPool *pool;
	RvObjListElement pagelistelem;
	RvSize_t maxelements;
	RvSize_t freecount;
} RvObjPoolPage;
#define RV_OBJPOOL_PAGE_OVERHEAD RvRoundToSize(sizeof(RvObjPoolPage), RV_ALIGN_SIZE)

/* Define additional data to be stored with each item. The OVERHEAD size */
/* must account for the alignment of the ptr that will be returned to the user. */
typedef RvObjPoolPage *RvObjPoolData;
#define RV_OBJPOOL_ITEM_OVERHEAD RV_ALIGN_SIZE

static RvObjPoolPage *RvObjPoolNewPage(RvObjPool *objpool);
static RvBool RvObjPoolRemovePage(RvObjPoolPage *page);

/* Construct a pool. Some parameters only effect some pool types. */
/* itemtemp: a pointer to the start of object of the type to be stored */
/*           This item is never touched but is simply used to find the */
/*           offset of the RvObjPoolElement structure (elementptr) within it. */
/* elementptr: pointer to the RvObjPoolElement structure within itemtemp */
/* callbacks: must be completely filled in (a copy is made and maintained) */
/* itemsize: size of itemtemp */
/* pageitems: number of items per page (if 0, calculate based on pagesize) */
/* pagesize: size of each page (if 0, calculated based on pageitems) */
/* pooltype: FIXED, EXAPNDING, DYNAMIC (see header file) */
/* salvage: set to RV_TRUE to allow page salvage (must be RV_TRUE for DYNAMIC) */
/* maxitems: number of items not to exceed this value (0 = no max) */
/* minitems: number of items not to go below this value */
/* freelevel: minimum items free per 100 to be maintained (DYNAMIC only) */
RvObjPool *RvObjPoolConstruct(RvObjPool *objpool, void *itemtemp, RvObjPoolElement *elementptr, RvObjPoolFuncs *callbacks, RvSize_t itemsize, RvSize_t pageitems, RvSize_t pagesize, RvInt pooltype, RvBool salvage, RvSize_t maxitems, RvSize_t minitems, RvSize_t freelevel)
{
	RvObjPoolPage poolpage;
	
#if defined(RV_NULLCHECK)
	if((objpool == NULL) || (callbacks == NULL) || (callbacks->pagealloc == NULL) ||
	   (callbacks->pagefree == NULL))
		return NULL;
#endif
#if defined(RV_RANGECHECK)
	if((salvage != RV_OBJPOOL_SALVAGE_ALLOWED) && (salvage != RV_OBJPOOL_SALVAGE_NEVER))
		return NULL;
	if(freelevel > 100)
		return NULL;
	if((maxitems < minitems) && (maxitems != 0))
		return NULL;
#endif

	/* Set options based on pool type and data parameter */
	switch(pooltype) {
		case RV_OBJPOOL_TYPE_FIXED: objpool->autoexpand = RV_FALSE;
									objpool->autoreduct = RV_FALSE;
									break;
		case RV_OBJPOOL_TYPE_EXPANDING: objpool->autoexpand = RV_TRUE;
										objpool->autoreduct = RV_FALSE;
										break;
		case RV_OBJPOOL_TYPE_DYNAMIC: objpool->autoexpand = RV_TRUE;
									  objpool->autoreduct = RV_TRUE;
									  if(salvage != RV_OBJPOOL_SALVAGE_ALLOWED)
										  return NULL; /* DYNAMIC must allow salvage */
									  break;
		default: return NULL; /* invalid pooltype */
	}

	if(maxitems == 0) {
		objpool->maxitems = (RvSize_t)(~0); /* Allow easy setting of no maximum */
	} else objpool->maxitems = maxitems;
	objpool->minitems = minitems;
	objpool->allowsalvage = salvage;
	objpool->reductlevel = freelevel;

	/* Set item size and calculate actual size of each block */
	objpool->itemsize = itemsize;
	objpool->blocksize = itemsize + RV_ALIGN_SIZE - 1 - ((itemsize - 1) % RV_ALIGN_SIZE); /* insure alignment */
	if(objpool->allowsalvage == RV_OBJPOOL_SALVAGE_ALLOWED)
		objpool->blocksize += RV_OBJPOOL_ITEM_OVERHEAD; /* We'll need space to store the page pointer */
#if defined(RV_RANGECHECK)
	if(objpool->blocksize < objpool->itemsize)
		return(NULL); /* overflow */
#endif

	/* Calculate page information based on user input */
	if(pageitems == 0) {
		/* User wants us to calculate items per page */
		objpool->pageitems = (pagesize - RV_OBJPOOL_PAGE_OVERHEAD) / objpool->blocksize;
	} else objpool->pageitems = pageitems;
	if(pagesize == 0) {
		/* User wants us to calculate size of each page */
		objpool->pagesize = (pageitems * objpool->blocksize) + RV_OBJPOOL_PAGE_OVERHEAD;
	} else objpool->pagesize = pagesize;
#if defined(RV_RANGECHECK)
	if((objpool->pagesize <= RV_OBJPOOL_PAGE_OVERHEAD) || (objpool->pageitems == 0))
		return NULL; /* pagesize not big enough for one block. */
	if(((objpool->pagesize - RV_OBJPOOL_PAGE_OVERHEAD) / objpool->blocksize) < objpool->pageitems)
		return NULL; /* calculation overflowed */
#endif

	/* Copy callbacks */
	memcpy(&objpool->callbacks, callbacks, sizeof(*callbacks));

	/* Set up free list (a pool element is simply a list elelment) */
	if(RvObjListConstruct(&objpool->freelist, itemtemp, elementptr) == NULL)
		return NULL;
	
	/* Create our list of pages */
	RvObjListConstruct(&objpool->pagelist, &poolpage, &poolpage.pagelistelem);

	/* If a minimum is set, start with that amount. */
	if(objpool->minitems > 0) {
		if(RvObjPoolAddItems(objpool, objpool->minitems) < objpool->minitems) {
			/* If we can't get the minimum, then undo everything and abort. */
			RvObjPoolDestruct(objpool);
			return NULL;
		}
	}

	return objpool;
}

/* Will destruct all items, free all pages and then destroy the pool. */
/* Returns RV_TRUE upon success. Will fail, returning RV_FALSE, if some */
/* items have not been returned to the pool. */
RvBool RvObjPoolDestruct(RvObjPool *objpool)
{
	void *item;
	RvObjPoolPage *page;

#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return RV_FALSE;
#endif

	if(RvObjPoolTotalItems(objpool) != RvObjPoolFreeItems(objpool))
		return RV_FALSE; /* All items not returned to pool */

	/* Destruct all items (don't bother if no destruct callback) */
	if(objpool->callbacks.objdestruct != NULL) {
		for(;;) {
			item = RvObjListGetNext(&objpool->freelist, NULL, RV_OBJLIST_REMOVE);
			if(item == NULL) break;
			objpool->callbacks.objdestruct(item, objpool->callbacks.objdestructdata);
		}
	}

	/* Free up all the pages */
	for(;;) {
		page = (RvObjPoolPage *)RvObjListGetNext(&objpool->pagelist, NULL, RV_OBJLIST_REMOVE);
		if(page == NULL) break;
		objpool->callbacks.pagefree((void *)page, objpool->callbacks.pagefreedata);
	}

	/* That'it, nothing else needs to be cleaned up */
	return RV_TRUE;
}

RvSize_t RvObjPoolTotalItems(RvObjPool *objpool)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	return RvObjListSize(&objpool->pagelist) * objpool->pageitems;
}

RvSize_t RvObjPoolFreeItems(RvObjPool *objpool)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	return RvObjListSize(&objpool->freelist);
}

RvSize_t RvObjPoolTotalPages(RvObjPool *objpool)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	return RvObjListSize(&objpool->pagelist);
}

RvSize_t RvObjPoolItemsPerPage(RvObjPool *objpool)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif
	
	return objpool->pageitems;
}

RvSize_t RvObjPoolItemBlockSize(RvObjPool *objpool)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	return objpool->blocksize;
}

RvSize_t RvObjPoolPageSize(RvObjPool *objpool)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	return objpool->pagesize;
}

RvSize_t RvObjPoolGetMaxitems(RvObjPool *objpool)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	return objpool->maxitems;
}

/* Returns RV_TRUE if successful. Not valid for FIXED pools. */
/* A value of 0 means no maximum. */
RvBool RvObjPoolSetMaxitems(RvObjPool *objpool, RvSize_t newmax)
{
	RvSize_t maxitems;
	
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return RV_FALSE;
#endif

	maxitems = newmax;
	if(maxitems == 0)
		maxitems = (RvSize_t)(~0);

	/* We don't allow reducing this beneath the min or the */
	/* current number of items since that gets way too messy. */
	if((maxitems < objpool->minitems) || (maxitems < RvObjPoolTotalItems(objpool)))
		return RV_FALSE;
	
	objpool->maxitems = maxitems;
	return RV_TRUE;
}

RvSize_t RvObjPoolGetMinitems(RvObjPool *objpool)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	return objpool->minitems;
}

/* Returns RV_TRUE if successful. Will increase the current pool */
/* size if needed to meet the new minimum. */
RvBool RvObjPoolSetMinitems(RvObjPool *objpool, RvSize_t newmin)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return RV_FALSE;
#endif

	/* Don't allow min/max to cross. */
	if(newmin > ((objpool->maxitems / objpool->pageitems) * objpool->pageitems))
		return RV_FALSE;

	/* If we are below the minimum, add pages until we're not */
	while(newmin > RvObjPoolTotalItems(objpool)) {
		if(RvObjPoolAddPages(objpool, 1) != 1)
			break; /* We can't add any more pages so just stop */
	}
	
	objpool->minitems = newmin;
	return RV_TRUE;
}

RvSize_t RvObjPoolGetFreelevel(RvObjPool *objpool)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	return objpool->reductlevel;
}

/* Returns RV_TRUE if successful. Only valid for DYNAMIC pools. */
RvBool RvObjPoolSetFreelevel(RvObjPool *objpool, RvSize_t newlevel)
{
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return RV_FALSE;
#endif
#if defined(RV_RANGECHECK)
	if(newlevel > 100)
		return RV_FALSE;
#endif

	/* Trying to adjust to pool for a new level is to messy so */
	/* just set the new value and let it get there naturally. */
	objpool->reductlevel = newlevel;
	return RV_TRUE;
}

/* Actual number of items added will be a multiple of the number of items */
/* in a page. The total number of items added to the pool is returned. */
/* Requesting 0 items will allocate an entire page of them. */
RvSize_t RvObjPoolAddItems(RvObjPool *objpool, RvSize_t numitems)
{
	RvSize_t numpages, newpages;
	
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	if(numitems > 0) {
		numpages = ((numitems - 1) / objpool->pageitems) + 1;
	} else numpages = 1;

	newpages = RvObjPoolAddPages(objpool, numpages);
	return (newpages * objpool->pageitems);
}

/* Add a number of pages work to the pool. Returns the number of pages */
/* successfully added. */
RvSize_t RvObjPoolAddPages(RvObjPool *objpool, RvSize_t numpages)
{
	RvSize_t i, errcount;

#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif

	errcount = 0;
	for(i = 0; i < numpages; i++) {
		if(RvObjPoolNewPage(objpool) == NULL)
			errcount += 1;
	}
	return (numpages - errcount);
}

/* Remove any unused pages, return number of pages released */
RvSize_t RvObjPoolSalvage(RvObjPool *objpool)
{
	RvObjPoolPage *page, *prevpage;
	RvSize_t result;
	
#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return 0;
#endif
#if defined(RV_OTHERCHECK)
	if(objpool->allowsalvage == RV_OBJPOOL_SALVAGE_NEVER)
		return 0;
#endif

	result = 0;
	page = NULL; /* start with first page */
	for(;;) {
		page = (RvObjPoolPage *)RvObjListGetNext(&objpool->pagelist, page, RV_OBJLIST_LEAVE);
		if(page == NULL) break;
		if(page->freecount == page->maxelements) {
			/* page is not being used */
			prevpage = (RvObjPoolPage *)RvObjListGetPrevious(&objpool->pagelist, page, RV_OBJLIST_LEAVE);
			if(RvObjPoolRemovePage(page) == RV_TRUE) {
				result += 1;
				page = prevpage; /* deleted page isn't in the list anymore */
			}
		}
	}

	return result;
}

void *RvObjPoolGetItem(RvObjPool *objpool)
{
	RvObjPoolPage **pageref;
	void *item;

#if defined(RV_NULLCHECK)
	if(objpool == NULL)
		return NULL;
#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?