rvobjpool.c

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

C
831
字号
	item = RvObjListGetNext(&objpool->freelist, NULL, RV_OBJLIST_REMOVE);
	if((item == NULL) && (objpool->autoexpand == RV_TRUE)) {
		/* No items and we're allowed to make more so make them and try again */
		RvObjPoolNewPage(objpool);
		item = RvObjListGetNext(&objpool->freelist, NULL, RV_OBJLIST_REMOVE);
	}

	/* If we're keeping page references, increment item count */
	if((item != NULL) && (objpool->allowsalvage == RV_OBJPOOL_SALVAGE_ALLOWED)) {
		pageref = (RvObjPoolPage **)((RvInt8 *)item - RV_OBJPOOL_ITEM_OVERHEAD);
		(*pageref)->freecount--;
	}

	return item;
}

/* Returns RV_TRUE if successful */
RvBool RvObjPoolReleaseItem(RvObjPool *objpool, void *item)
{
	RvObjPoolPage **pageref;
	RvSize_t total, minlevel;

#if defined(RV_NULLCHECK)
	if((objpool == NULL) || (item == NULL))
		return RV_FALSE;
#endif
#if defined(RV_OTHERCHECK)
	if(objpool->allowsalvage == RV_OBJPOOL_SALVAGE_ALLOWED) {
		pageref = (RvObjPoolPage **)((RvInt8 *)item - RV_OBJPOOL_ITEM_OVERHEAD);
		if((*pageref)->pool != objpool)
			return RV_FALSE; /* Object being returned to wrong pool */
	}
#endif

	/* Put item at front of free list (so it gets reused first) */
	if(RvObjListInsertAfter(&objpool->freelist, NULL, item) == NULL)
		return RV_FALSE;

	if(objpool->allowsalvage == RV_OBJPOOL_SALVAGE_ALLOWED) {
		/* Page reference only exists if pages can be removed */
		pageref = (RvObjPoolPage **)((RvInt8 *)item - RV_OBJPOOL_ITEM_OVERHEAD);
		(*pageref)->freecount++;
		if((objpool->autoreduct == RV_TRUE) && ((*pageref)->freecount == (*pageref)->maxelements)) {
			/* The page is no longer in use so we may want to delete the page */
			if(objpool->reductlevel > 0) {
				/* Calculate free level */
				total = RvObjPoolTotalItems(objpool) - objpool->pageitems;
				minlevel = (objpool->reductlevel * (total / 100)) +
						   ((objpool->reductlevel * (total % 100)) / 100);
				if(RvObjPoolFreeItems(objpool) > (minlevel + objpool->pageitems))
					RvObjPoolRemovePage(*pageref);
			} else RvObjPoolRemovePage(*pageref); /* reductlevel = 0 means always delete */
		}
	}

	return RV_TRUE;
}

/* Create new page and add it to a pool */
static RvObjPoolPage *RvObjPoolNewPage(RvObjPool *objpool)
{
	RvObjPoolPage *page, **pageref;
	RvSize_t count;
	void *item, *useritem;

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

	if(((RvObjListSize(&objpool->pagelist) + 1) * objpool->pageitems) > objpool->maxitems)
		return RV_FALSE; /* adding a page would go above maximum */

	page = (RvObjPoolPage *)objpool->callbacks.pagealloc(objpool->pagesize, objpool->callbacks.pageallocdata);
	if(page == NULL)
		return NULL; /* can't get a new page */

	/* Create each item in page */
	item = (void *)((RvInt8 *)page + RV_OBJPOOL_PAGE_OVERHEAD);
	for(count = 0; count < objpool->pageitems; count++) {
		if(objpool->allowsalvage == RV_OBJPOOL_SALVAGE_ALLOWED) {
			/* Add page reference before actual item */
			pageref = (RvObjPoolPage **)item;
			*pageref = page;
			useritem = (void *)((RvInt8 *)item + RV_OBJPOOL_ITEM_OVERHEAD);
		} else useritem = item;

		/* Call user construct if there is one */
		if(objpool->callbacks.objconstruct != NULL) {
			if(objpool->callbacks.objconstruct(useritem, objpool->callbacks.objconstructdata) == NULL) {
				/* User can't construct object, we need to undo things */
				while(count > 0) {
					count--;
					item = (void *)((RvInt8 *)item - objpool->blocksize);
					if(objpool->allowsalvage == RV_OBJPOOL_SALVAGE_ALLOWED) {
						useritem = (void *)((RvInt8 *)item - RV_OBJPOOL_ITEM_OVERHEAD);
					} else useritem = item;
					RvObjListRemoveItem(&objpool->freelist, useritem);
					if(objpool->callbacks.objdestruct != NULL)
						objpool->callbacks.objdestruct(useritem, objpool->callbacks.objdestructdata);
				}
				objpool->callbacks.pagefree((void *)page, objpool->callbacks.pagefreedata);
				return NULL; /* Page is undone, bail out */
			}
		}
		/* Add new item to end of pool's free list */
		RvObjListInsertBefore(&objpool->freelist, NULL, useritem);

		item = (void *)((RvInt8 *)item + objpool->blocksize);
	}

	/* Set up page info */
	page->pool = objpool;
	page->maxelements = objpool->pageitems;
	page->freecount = objpool->pageitems;
	RvObjListInsertBefore(&objpool->pagelist, NULL, (void *)page); /* Put page at end of list */

	return page;
}

/* Remove a page from its object pool, returns RV_TRUE if successful. */
static RvBool RvObjPoolRemovePage(RvObjPoolPage *page)
{
	RvObjPool *objpool;
	RvSize_t count;
	void *item, *useritem;

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

	objpool = page->pool;
	if(((RvObjListSize(&objpool->pagelist) - 1) * objpool->pageitems) < objpool->minitems)
		return RV_FALSE; /* removing a page would go below minimum */

	RvObjListRemoveItem(&objpool->pagelist, (void *)page);
	
	/* Remove each item in page */
	item = (void *)((RvInt8 *)page + RV_OBJPOOL_PAGE_OVERHEAD);
	for(count = 0; count < objpool->pageitems; count++) {
		if(objpool->allowsalvage == RV_OBJPOOL_SALVAGE_ALLOWED) {
			/* skip page reference before actual item */
			useritem = (void *)((RvInt8 *)item + RV_OBJPOOL_ITEM_OVERHEAD);
		} else useritem = item;

		RvObjListRemoveItem(&objpool->freelist, useritem); /* remove from freelist */
		
		/* Call user destruct if there is one */
		if(objpool->callbacks.objdestruct != NULL)
			objpool->callbacks.objdestruct(useritem, objpool->callbacks.objdestructdata);

		item = (void *)((RvInt8 *)item + objpool->blocksize);
	}

	/* free up page and we're done */
	objpool->callbacks.pagefree(page, objpool->callbacks.pagefreedata);
	return RV_TRUE;
}

#if defined(RV_TEST_CODE)
#include "rvstdio.h"
#include <stdlib.h>
typedef struct {
	RvInt32 dummy1;
	RvInt64 dummy2;
	RvObjPoolElement poolElem;
	RvChar dummy3[80];
	RvSize_t index;
} RvObjPoolTestStruct;

static volatile int callbackprint = 0;
static volatile RvSize_t counter = 0;

/* Set GETMEMORY & FREEMEMORY to function that will allocate memory pages */
#if (RV_OS_TYPE == RV_OS_TYPE_NUCLEUS) /* Shouldn't use this here but its a test */
#define FREEMEMORY(_x) NU_Deallocate_Memory((_x))
#define GETMEMORY(_x) NU_getmemory((_x))
#include <nucleus.h>
extern NU_MEMORY_POOL System_Memory;
static void *NU_getmemory(RvSize_t n)
{
	int status;
	void *ptr;

	status = NU_Allocate_Memory(&System_Memory, &ptr, n, NU_NO_SUSPEND);
	if(status != NU_SUCCESS) return NULL;
	return ptr;
}
#elif (RV_OS_TYPE == RV_OS_TYPE_OSE) /* Shouldn't use this here but its a test */
#define GETMEMORY(_x) heap_alloc_shared((_x), (__FILE__), (__LINE__))
#define FREEMEMORY(_x) heap_free_shared((_x))
#include "ose.h"
#include "heapapi.h"
#else
#define GETMEMORY(_x) malloc((_x))
#define FREEMEMORY(_x) free((_x))
#endif

static void *RvObjPoolTestObjConstruct(void *item, void *data)
{
	RvObjPoolTestStruct *testitem;

	testitem = (RvObjPoolTestStruct *)item;
	memset(item, 0x5A, sizeof(RvObjPoolTestStruct));
	testitem->index = counter;
	counter++;

	if(callbackprint != 0)
		RvPrintf("ObjConstruct item = %p, data = %p, index = %u\n", testitem, data, testitem->index);

	return item;
}

static void RvObjPoolTestObjDestruct(void *item, void *data)
{
	RvObjPoolTestStruct *testitem;

	testitem = (RvObjPoolTestStruct *)item;
	if(callbackprint != 0)
		RvPrintf("ObjDestruct item = %p, data = %p, index = %u\n", testitem, data, testitem->index);
	counter--;
	memset(item, 0xA0, sizeof(RvObjPoolTestStruct));
}

static void *RvObjPoolTestPageAlloc(RvSize_t size, void *data)
{
	void *result;

	result = (void *)GETMEMORY(size);
	if(callbackprint != 0)
		RvPrintf("PageAlloc size = %d, data = %p, result = %p\n", size, data, result);

	return result;
}

static void RvObjPoolTestPageFree(void *ptr, void *data)
{
	if(callbackprint != 0)
		RvPrintf("PageFree ptr = %p, data = %p\n", ptr, data);
	FREEMEMORY(ptr);
}

static void RvObjPoolTestPool(RvInt pooltype, RvBool salvage, RvSize_t maxitems, RvSize_t minitems, RvSize_t freelevel, RvSize_t pageitems, RvSize_t pagesize)
{
	RvObjPoolTestStruct testitem, *poolitem;
	RvObjPoolFuncs callbacks;
	RvObjPool objpool, *poolresult;
	RvBool boolresult;
	RvSize_t uiresult;
	int i, arraysize;
	void **objarray;

	RvPrintf("++++Testing pool++++\n");
	RvPrintf("Type=");
	switch(pooltype) {
		case RV_OBJPOOL_TYPE_FIXED: RvPrintf("FIXED");
									break;
		case RV_OBJPOOL_TYPE_EXPANDING: RvPrintf("EXPANDING");
										break;
		case RV_OBJPOOL_TYPE_DYNAMIC: RvPrintf("DYNAMIC");
									  break;
	}
	RvPrintf(", salvage=");
	switch(salvage) {
		case RV_OBJPOOL_SALVAGE_ALLOWED: RvPrintf("allowed");
										 break;
		case RV_OBJPOOL_SALVAGE_NEVER: RvPrintf("never");
										 break;
	}
	RvPrintf(", max=%u, min=%u, freelevel=%u\n", maxitems, minitems, freelevel);
	RvPrintf("items/page=%u, pagesize=%u, item size=%u\n", pageitems, pagesize, sizeof(testitem));
	callbackprint = 1;
	
	RvPrintf("RvObjPoolConstruct : ");
	callbacks.objconstruct = RvObjPoolTestObjConstruct;
	callbacks.objdestruct = RvObjPoolTestObjDestruct;
	callbacks.pagealloc = RvObjPoolTestPageAlloc;
	callbacks.pagefree = RvObjPoolTestPageFree;
	callbacks.objconstructdata = (void *)1;
	callbacks.objdestructdata = (void *)2;
	callbacks.pageallocdata = (void *)3;
	callbacks.pagefreedata = (void *)4;
	poolresult = RvObjPoolConstruct(&objpool, &testitem, &testitem.poolElem, &callbacks, sizeof(testitem), pageitems, pagesize, pooltype, salvage, maxitems, minitems, freelevel);
	if(poolresult == NULL) {
		RvPrintf("ERROR\n");
		RvPrintf("++++Pool Test Aborted++++\n");
		return;
	} else RvPrintf("OK\n");

	RvPrintf("RvObjPoolItemsPerPage = %u\n", RvObjPoolItemsPerPage(&objpool));
	RvPrintf("RvObjPoolItemsBlockSize = %u\n", RvObjPoolItemBlockSize(&objpool));
	RvPrintf("RvObjPoolPageSize = %u\n", RvObjPoolPageSize(&objpool));
	RvPrintf("RvObjPoolSalvage = %u\n", RvObjPoolSalvage(&objpool));

	RvPrintf("Getting an item...\n");
	poolitem = (RvObjPoolTestStruct *)RvObjPoolGetItem(&objpool);
	RvPrintf("RvObjPoolGetItem: ");
	if(poolitem != NULL) {
		RvPrintf("%p\n", poolitem);
	} else RvPrintf("ERROR!\n");
	RvPrintf("RvObjPoolTotalItems = %u\n", RvObjPoolTotalItems(&objpool));
	RvPrintf("RvObjPoolFreeItems = %u\n", RvObjPoolFreeItems(&objpool));
	RvPrintf("RvObjPoolTotalPages = %u\n", RvObjPoolTotalPages(&objpool));

	RvPrintf("Releasing an item...\n");
	boolresult = RvObjPoolReleaseItem(&objpool, poolitem);
	RvPrintf("RvObjPoolReleaseItem: ");
	if(boolresult == RV_TRUE) {
		RvPrintf("OK.\n");
	} else RvPrintf("ERROR!\n");
	RvPrintf("RvObjPoolTotalItems = %u\n", RvObjPoolTotalItems(&objpool));
	RvPrintf("RvObjPoolFreeItems = %u\n", RvObjPoolFreeItems(&objpool));
	RvPrintf("RvObjPoolTotalPages = %u\n", RvObjPoolTotalPages(&objpool));

	RvPrintf("Adding pages...\n");
	uiresult = RvObjPoolAddPages(&objpool, 2);
	RvPrintf("RvObjPoolAddPages (2): ");
	if(uiresult == 2) {
		RvPrintf("OK.\n");
	} else RvPrintf("ERROR!\n");
	RvPrintf("Adding items...\n");
	uiresult = RvObjPoolAddItems(&objpool, ((RvObjPoolItemsPerPage(&objpool) * 3) / 2));
	RvPrintf("RvObjPoolAddItems (%u): ", ((RvObjPoolItemsPerPage(&objpool) * 3) / 2));
	if(uiresult == (RvObjPoolItemsPerPage(&objpool) * 2)) {
		RvPrintf("OK.\n");
	} else RvPrintf("ERROR!\n");
	RvPrintf("RvObjPoolTotalItems = %u\n", RvObjPoolTotalItems(&objpool));
	RvPrintf("RvObjPoolFreeItems = %u\n", RvObjPoolFreeItems(&objpool));
	RvPrintf("RvObjPoolTotalPages = %u\n", RvObjPoolTotalPages(&objpool));

	arraysize = (RvObjPoolItemsPerPage(&objpool) * 4) + 3;
	objarray = (void **)GETMEMORY((RvSize_t)arraysize * sizeof(void *));
	RvPrintf("Getting %d items...\n", arraysize);
	for(i = 0; i < 	arraysize; i++) {
		objarray[i] = RvObjPoolGetItem(&objpool);
		if(objarray[i] == NULL) RvPrintf("ERROR! Bad get: %d\n", i);
	}
	RvPrintf("RvObjPoolTotalItems = %u\n", RvObjPoolTotalItems(&objpool));
	RvPrintf("RvObjPoolFreeItems = %u\n", RvObjPoolFreeItems(&objpool));
	RvPrintf("RvObjPoolTotalPages = %u\n", RvObjPoolTotalPages(&objpool));
	RvPrintf("RvObjPoolSalvage = %u\n", RvObjPoolSalvage(&objpool));

	RvPrintf("Releasing %d items...\n", (arraysize / 2));
	for(i = 0; i < 	(arraysize / 2); i++) {
		if(RvObjPoolReleaseItem(&objpool, objarray[i]) == RV_FALSE)
			RvPrintf("ERROR! Bad release: %d\n", i);
		objarray[i] = NULL;
	}
	RvPrintf("RvObjPoolTotalItems = %u\n", RvObjPoolTotalItems(&objpool));
	RvPrintf("RvObjPoolFreeItems = %u\n", RvObjPoolFreeItems(&objpool));
	RvPrintf("RvObjPoolTotalPages = %u\n", RvObjPoolTotalPages(&objpool));
	RvPrintf("Salvaging free pages...\n");
	RvPrintf("RvObjPoolSalvage = %u\n", RvObjPoolSalvage(&objpool));
	RvPrintf("RvObjPoolTotalItems = %u\n", RvObjPoolTotalItems(&objpool));
	RvPrintf("RvObjPoolFreeItems = %u\n", RvObjPoolFreeItems(&objpool));
	RvPrintf("RvObjPoolTotalPages = %u\n", RvObjPoolTotalPages(&objpool));

	if(RvObjPoolFreeItems(&objpool) != RvObjPoolTotalItems(&objpool)) {
		RvPrintf("Trying to Destruct Pool: ");
		boolresult = RvObjPoolDestruct(&objpool);
		if(boolresult == RV_TRUE) {
			RvPrintf("ERROR! Destruct should have failed.\n");
		} else RvPrintf("OK. Didn't destroy pool with outstanding items.\n");
	}

	RvPrintf("Releasing rest of items...\n");
	for(i = 0; i < 	arraysize; i++) {
		if(objarray[i] != NULL) {
			if(RvObjPoolReleaseItem(&objpool, objarray[i]) == RV_FALSE)
				RvPrintf("ERROR! Bad release: %d\n", i);
		}
	}
	RvPrintf("RvObjPoolTotalItems = %u\n", RvObjPoolTotalItems(&objpool));
	RvPrintf("RvObjPoolFreeItems = %u\n", RvObjPoolFreeItems(&objpool));
	RvPrintf("RvObjPoolTotalPages = %u\n", RvObjPoolTotalPages(&objpool));
	

	RvPrintf("Destructing pool: ");
	boolresult = RvObjPoolDestruct(&objpool);
	if(boolresult == RV_TRUE) {
		RvPrintf("OK\n");
	} else RvPrintf("ERROR!\n");

	callbackprint = 0;
	FREEMEMORY(objarray);
	RvPrintf("++++Pool test completed++++\n");
}

void RvObjPoolTest(void)
{
	RvPrintf("Starting test of Rvobjpool.\n");

	/* type, salvage, max, min, freelevel, items/page, pagesize */
	RvObjPoolTestPool(RV_OBJPOOL_TYPE_FIXED, RV_OBJPOOL_SALVAGE_ALLOWED, 0, 0, 0, 15, 0);
	RvObjPoolTestPool(RV_OBJPOOL_TYPE_FIXED, RV_OBJPOOL_SALVAGE_NEVER, 0, 0, 0, 0, 1500);
	RvObjPoolTestPool(RV_OBJPOOL_TYPE_FIXED, RV_OBJPOOL_SALVAGE_ALLOWED, 40, 5, 0, 15, 0);

	RvPrintf("Testing bas Min/Max. Should fail.\n");
	RvObjPoolTestPool(RV_OBJPOOL_TYPE_FIXED, RV_OBJPOOL_SALVAGE_ALLOWED, 5, 40, 0, 15, 0);

	RvPrintf("Testing Page size too small. Should fail.\n");
	RvObjPoolTestPool(RV_OBJPOOL_TYPE_FIXED, RV_OBJPOOL_SALVAGE_NEVER, 0, 0, 0, 0, 100);

	RvObjPoolTestPool(RV_OBJPOOL_TYPE_EXPANDING, RV_OBJPOOL_SALVAGE_ALLOWED, 0, 0, 0, 17, 0);
	RvObjPoolTestPool(RV_OBJPOOL_TYPE_EXPANDING, RV_OBJPOOL_SALVAGE_NEVER, 0, 0, 0, 0, 1200);
	RvObjPoolTestPool(RV_OBJPOOL_TYPE_EXPANDING, RV_OBJPOOL_SALVAGE_ALLOWED, 40, 0, 0, 17, 0);

	RvObjPoolTestPool(RV_OBJPOOL_TYPE_DYNAMIC, RV_OBJPOOL_SALVAGE_ALLOWED, 0, 0, 0, 13, 0);
	RvObjPoolTestPool(RV_OBJPOOL_TYPE_DYNAMIC, RV_OBJPOOL_SALVAGE_ALLOWED, 0, 0, 25, 13, 2000);
	RvObjPoolTestPool(RV_OBJPOOL_TYPE_DYNAMIC, RV_OBJPOOL_SALVAGE_ALLOWED, 0, 15, 0, 13, 0);
}

#endif /* RV_TEST_CODE */

⌨️ 快捷键说明

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