libwinpr-utils: add support for variable size buffer pool

This commit is contained in:
Marc-André Moreau 2013-08-15 00:01:42 -04:00
parent 1e5118116d
commit c149ede6f2
4 changed files with 294 additions and 34 deletions

View File

@ -312,18 +312,33 @@ WINPR_API void CountdownEvent_Free(wCountdownEvent* countdown);
/* BufferPool */
struct _wBufferPool
struct _wBufferPoolItem
{
int size;
int capacity;
void** array;
CRITICAL_SECTION lock;
int fixedSize;
void* buffer;
};
typedef struct _wBufferPoolItem wBufferPoolItem;
struct _wBufferPool
{
int defaultSize;
DWORD alignment;
BOOL synchronized;
CRITICAL_SECTION lock;
int aSize;
int aCapacity;
wBufferPoolItem* aArray;
int uSize;
int uCapacity;
wBufferPoolItem* uArray;
};
typedef struct _wBufferPool wBufferPool;
WINPR_API int BufferPool_GetPoolSize(wBufferPool* pool);
WINPR_API int BufferPool_GetBufferSize(wBufferPool* pool, void* buffer);
WINPR_API void* BufferPool_Take(wBufferPool* pool, int bufferSize);
WINPR_API void BufferPool_Return(wBufferPool* pool, void* buffer);
WINPR_API void BufferPool_Clear(wBufferPool* pool);

View File

@ -34,35 +34,167 @@
* Methods
*/
void BufferPool_ShiftAvailable(wBufferPool* pool, int index, int count)
{
if (count > 0)
{
if (pool->aSize + count > pool->aCapacity)
{
pool->aCapacity *= 2;
pool->aArray = (wBufferPoolItem*) realloc(pool->aArray, sizeof(wBufferPoolItem) * pool->aCapacity);
}
MoveMemory(&pool->aArray[index + count], &pool->aArray[index], (pool->aSize - index) * sizeof(wBufferPoolItem));
pool->aSize += count;
}
else if (count < 0)
{
MoveMemory(&pool->aArray[index], &pool->aArray[index - count], (pool->aSize - index) * sizeof(wBufferPoolItem));
pool->aSize += count;
}
}
void BufferPool_ShiftUsed(wBufferPool* pool, int index, int count)
{
if (count > 0)
{
if (pool->uSize + count > pool->uCapacity)
{
pool->uCapacity *= 2;
pool->uArray = (wBufferPoolItem*) realloc(pool->uArray, sizeof(wBufferPoolItem) * pool->uCapacity);
}
MoveMemory(&pool->uArray[index + count], &pool->uArray[index], (pool->uSize - index) * sizeof(wBufferPoolItem));
pool->uSize += count;
}
else if (count < 0)
{
MoveMemory(&pool->uArray[index], &pool->uArray[index - count], (pool->uSize - index) * sizeof(wBufferPoolItem));
pool->uSize += count;
}
}
/**
* Get the buffer pool size
*/
int BufferPool_GetPoolSize(wBufferPool* pool)
{
int size;
if (pool->synchronized)
EnterCriticalSection(&pool->lock);
size = pool->uSize;
if (pool->synchronized)
LeaveCriticalSection(&pool->lock);
return size;
}
/**
* Get the size of a pooled buffer
*/
int BufferPool_GetBufferSize(wBufferPool* pool, void* buffer)
{
int size = 0;
int index = 0;
BOOL found = FALSE;
if (pool->synchronized)
EnterCriticalSection(&pool->lock);
for (index = 0; index < pool->uSize; index++)
{
if (pool->uArray[index].buffer == buffer)
{
size = pool->uArray[index].size;
found = TRUE;
break;
}
}
if (pool->synchronized)
LeaveCriticalSection(&pool->lock);
return (found) ? size : -1;
}
/**
* Gets a buffer of at least the specified size from the pool.
*/
void* BufferPool_Take(wBufferPool* pool, int bufferSize)
void* BufferPool_Take(wBufferPool* pool, int size)
{
int index;
int maxSize;
int maxIndex;
int foundIndex;
BOOL found = FALSE;
void* buffer = NULL;
if (pool->synchronized)
EnterCriticalSection(&pool->lock);
if (pool->fixedSize)
{
if (pool->size > 0)
buffer = pool->array[--(pool->size)];
maxSize = 0;
maxIndex = 0;
if (!buffer)
if (size < 1)
size = pool->defaultSize;
for (index = 0; index < pool->aSize; index++)
{
if (pool->aArray[index].size > maxSize)
{
maxSize = pool->aArray[index].size;
maxIndex = index;
}
if (pool->aArray[index].size >= size)
{
foundIndex = index;
found = TRUE;
break;
}
}
if (!found)
{
if (!maxSize)
{
if (pool->alignment)
buffer = _aligned_malloc(pool->fixedSize, pool->alignment);
buffer = _aligned_malloc(size, pool->alignment);
else
buffer = malloc(pool->fixedSize);
buffer = malloc(size);
}
else
{
buffer = pool->aArray[maxIndex].buffer;
if (pool->alignment)
buffer = _aligned_realloc(buffer, size, pool->alignment);
else
buffer = realloc(buffer, size);
}
}
else
{
fprintf(stderr, "Variable-size BufferPool not yet implemented\n");
buffer = pool->aArray[index].buffer;
BufferPool_ShiftAvailable(pool, foundIndex, -1);
}
if (pool->uSize + 1 > pool->uCapacity)
{
pool->uCapacity *= 2;
pool->uArray = (wBufferPoolItem*) realloc(pool->uArray, sizeof(wBufferPoolItem) * pool->uCapacity);
}
pool->uArray[pool->uSize].buffer = buffer;
pool->uArray[pool->uSize].size = size;
(pool->uSize)++;
if (pool->synchronized)
LeaveCriticalSection(&pool->lock);
@ -75,16 +207,40 @@ void* BufferPool_Take(wBufferPool* pool, int bufferSize)
void BufferPool_Return(wBufferPool* pool, void* buffer)
{
int size = 0;
int index = 0;
BOOL found = FALSE;
if (pool->synchronized)
EnterCriticalSection(&pool->lock);
if ((pool->size + 1) >= pool->capacity)
for (index = 0; index < pool->uSize; index++)
{
pool->capacity *= 2;
pool->array = (void**) realloc(pool->array, sizeof(void*) * pool->capacity);
if (pool->uArray[index].buffer == buffer)
{
found = TRUE;
break;
}
}
pool->array[(pool->size)++] = buffer;
if (found)
{
size = pool->uArray[index].size;
BufferPool_ShiftUsed(pool, index, -1);
}
if (size)
{
if ((pool->aSize + 1) >= pool->aCapacity)
{
pool->aCapacity *= 2;
pool->aArray = (wBufferPoolItem*) realloc(pool->aArray, sizeof(wBufferPoolItem) * pool->aCapacity);
}
pool->aArray[pool->aSize].buffer = buffer;
pool->aArray[pool->aSize].size = size;
(pool->aSize)++;
}
if (pool->synchronized)
LeaveCriticalSection(&pool->lock);
@ -99,14 +255,24 @@ void BufferPool_Clear(wBufferPool* pool)
if (pool->synchronized)
EnterCriticalSection(&pool->lock);
while (pool->size > 0)
while (pool->aSize > 0)
{
(pool->size)--;
(pool->aSize)--;
if (pool->alignment)
_aligned_free(pool->array[pool->size]);
_aligned_free(pool->aArray[pool->aSize].buffer);
else
free(pool->array[pool->size]);
free(pool->aArray[pool->aSize].buffer);
}
while (pool->uSize > 0)
{
(pool->uSize)--;
if (pool->alignment)
_aligned_free(pool->uArray[pool->uSize].buffer);
else
free(pool->uArray[pool->uSize].buffer);
}
if (pool->synchronized)
@ -117,7 +283,7 @@ void BufferPool_Clear(wBufferPool* pool)
* Construction, Destruction
*/
wBufferPool* BufferPool_New(BOOL synchronized, int fixedSize, DWORD alignment)
wBufferPool* BufferPool_New(BOOL synchronized, int defaultSize, DWORD alignment)
{
wBufferPool* pool = NULL;
@ -125,10 +291,10 @@ wBufferPool* BufferPool_New(BOOL synchronized, int fixedSize, DWORD alignment)
if (pool)
{
pool->fixedSize = fixedSize;
pool->defaultSize = defaultSize;
if (pool->fixedSize < 0)
pool->fixedSize = 0;
if (pool->defaultSize < 0)
pool->defaultSize = 0;
pool->alignment = alignment;
pool->synchronized = synchronized;
@ -136,14 +302,13 @@ wBufferPool* BufferPool_New(BOOL synchronized, int fixedSize, DWORD alignment)
if (pool->synchronized)
InitializeCriticalSectionAndSpinCount(&pool->lock, 4000);
if (!pool->fixedSize)
{
fprintf(stderr, "Variable-size BufferPool not yet implemented\n");
}
pool->aSize = 0;
pool->aCapacity = 32;
pool->aArray = (wBufferPoolItem*) malloc(sizeof(wBufferPoolItem) * pool->aCapacity);
pool->size = 0;
pool->capacity = 32;
pool->array = (void**) malloc(sizeof(void*) * pool->capacity);
pool->uSize = 0;
pool->uCapacity = 32;
pool->uArray = (wBufferPoolItem*) malloc(sizeof(wBufferPoolItem) * pool->uCapacity);
}
return pool;
@ -158,7 +323,8 @@ void BufferPool_Free(wBufferPool* pool)
if (pool->synchronized)
DeleteCriticalSection(&pool->lock);
free(pool->array);
free(pool->aArray);
free(pool->uArray);
free(pool);
}

View File

@ -12,6 +12,7 @@ set(${MODULE_PREFIX}_TESTS
TestLinkedList.c
TestListDictionary.c
TestCmdLine.c
TestBufferPool.c
TestStreamPool.c
TestMessageQueue.c
TestMessagePipe.c)

View File

@ -0,0 +1,78 @@
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
int TestBufferPool(int argc, char* argv[])
{
int PoolSize;
int BufferSize;
int DefaultSize;
wBufferPool* pool;
BYTE* Buffers[10];
DefaultSize = 1234;
pool = BufferPool_New(TRUE, DefaultSize, 16);
Buffers[0] = BufferPool_Take(pool, -1);
Buffers[1] = BufferPool_Take(pool, 0);
Buffers[2] = BufferPool_Take(pool, 2048);
PoolSize = BufferPool_GetPoolSize(pool);
if (PoolSize != 3)
{
printf("BufferPool_GetPoolSize failure: Actual: %d Expected: %d\n", PoolSize, 3);
return -1;
}
BufferSize = BufferPool_GetBufferSize(pool, Buffers[0]);
if (BufferSize != DefaultSize)
{
printf("BufferPool_GetBufferSize failure: Actual: %d Expected: %d\n", BufferSize, DefaultSize);
return -1;
}
BufferSize = BufferPool_GetBufferSize(pool, Buffers[1]);
if (BufferSize != DefaultSize)
{
printf("BufferPool_GetBufferSize failure: Actual: %d Expected: %d\n", BufferSize, DefaultSize);
return -1;
}
BufferSize = BufferPool_GetBufferSize(pool, Buffers[2]);
if (BufferSize != 2048)
{
printf("BufferPool_GetBufferSize failure: Actual: %d Expected: %d\n", BufferSize, 2048);
return -1;
}
BufferPool_Return(pool, Buffers[1]);
PoolSize = BufferPool_GetPoolSize(pool);
if (PoolSize != 2)
{
printf("BufferPool_GetPoolSize failure: Actual: %d Expected: %d\n", PoolSize, 2);
return -1;
}
BufferPool_Clear(pool);
PoolSize = BufferPool_GetPoolSize(pool);
if (PoolSize != 0)
{
printf("BufferPool_GetPoolSize failure: Actual: %d Expected: %d\n", PoolSize, 0);
return -1;
}
BufferPool_Free(pool);
return 0;
}