mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 00:14:11 +09:00
[winpr,queue] improve queue management
* Fix Queue_EnsureCapacity reallocation handling, ensure queue->tail is properly updated. * Fix allocation behaviour, use growthFactor * 32 as block size. * Add doxygen for Queue_New
This commit is contained in:
@@ -181,6 +181,14 @@ extern "C"
|
||||
WINPR_API void Queue_Free(wQueue* queue);
|
||||
|
||||
/** @brief Creates a new queue
|
||||
*
|
||||
* @param synchronized If \b TRUE all functions are thread safe, if \b FALSE no synchronization
|
||||
* is done.
|
||||
* @param capacity The initial capacity of the queue. If \b 0 or \b -1 default settings are
|
||||
* applied.
|
||||
* @param growthFactor allocation behaviour when the queue capacity should be increased. Larger
|
||||
* values increase the allocation contingent. \b 0 or \b -1 apply default settings.
|
||||
*
|
||||
*
|
||||
* @return A newly allocated queue or \b NULL in case of failure
|
||||
*/
|
||||
|
||||
@@ -35,7 +35,7 @@ struct s_wQueue
|
||||
size_t head;
|
||||
size_t tail;
|
||||
size_t size;
|
||||
void** array;
|
||||
uintptr_t* array;
|
||||
CRITICAL_SECTION lock;
|
||||
HANDLE event;
|
||||
|
||||
@@ -45,6 +45,16 @@ struct s_wQueue
|
||||
BYTE padding2[4];
|
||||
};
|
||||
|
||||
static inline void* uptr2void(uintptr_t ptr)
|
||||
{
|
||||
return (void*)ptr;
|
||||
}
|
||||
|
||||
static inline uintptr_t void2uptr(const void* ptr)
|
||||
{
|
||||
return (uintptr_t)ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* C equivalent of the C# Queue Class:
|
||||
* http://msdn.microsoft.com/en-us/library/system.collections.queue.aspx
|
||||
@@ -124,9 +134,12 @@ void Queue_Clear(wQueue* queue)
|
||||
for (size_t index = queue->head; index != queue->tail; index = (index + 1) % queue->capacity)
|
||||
{
|
||||
if (queue->object.fnObjectFree)
|
||||
queue->object.fnObjectFree(queue->array[index]);
|
||||
{
|
||||
void* obj = uptr2void(queue->array[index]);
|
||||
queue->object.fnObjectFree(obj);
|
||||
}
|
||||
|
||||
queue->array[index] = NULL;
|
||||
queue->array[index] = 0;
|
||||
}
|
||||
|
||||
queue->size = 0;
|
||||
@@ -147,7 +160,8 @@ BOOL Queue_Contains(wQueue* queue, const void* obj)
|
||||
|
||||
for (size_t index = 0; index < queue->tail; index++)
|
||||
{
|
||||
if (queue->object.fnObjectEquals(queue->array[index], obj))
|
||||
void* ptr = uptr2void(queue->array[index]);
|
||||
if (queue->object.fnObjectEquals(ptr, obj))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
@@ -163,29 +177,52 @@ static BOOL Queue_EnsureCapacity(wQueue* queue, size_t count)
|
||||
{
|
||||
WINPR_ASSERT(queue);
|
||||
|
||||
if (queue->size + count >= queue->capacity)
|
||||
if (queue->size + count > queue->capacity)
|
||||
{
|
||||
if (queue->growthFactor > SIZE_MAX / 32ull)
|
||||
return FALSE;
|
||||
if (queue->size > SIZE_MAX - count)
|
||||
return FALSE;
|
||||
|
||||
const size_t increment = 32ull * queue->growthFactor;
|
||||
const size_t old_capacity = queue->capacity;
|
||||
size_t new_capacity = queue->capacity * queue->growthFactor;
|
||||
void** newArray = NULL;
|
||||
if (new_capacity < queue->size + count)
|
||||
new_capacity = queue->size + count;
|
||||
newArray = (void**)realloc((void*)queue->array, sizeof(void*) * new_capacity);
|
||||
const size_t required = queue->size + count;
|
||||
const size_t new_capacity = required + increment - required % increment;
|
||||
if (new_capacity > SIZE_MAX / sizeof(BYTE*))
|
||||
return FALSE;
|
||||
|
||||
uintptr_t* newArray = (uintptr_t*)realloc(queue->array, sizeof(uintptr_t) * new_capacity);
|
||||
|
||||
if (!newArray)
|
||||
return FALSE;
|
||||
|
||||
queue->capacity = new_capacity;
|
||||
queue->array = newArray;
|
||||
ZeroMemory((void*)&(queue->array[old_capacity]),
|
||||
(new_capacity - old_capacity) * sizeof(void*));
|
||||
ZeroMemory(&(queue->array[old_capacity]),
|
||||
(new_capacity - old_capacity) * sizeof(uintptr_t));
|
||||
|
||||
/* rearrange wrapped entries */
|
||||
if (queue->tail <= queue->head)
|
||||
{
|
||||
CopyMemory((void*)&(queue->array[old_capacity]), (void*)queue->array,
|
||||
queue->tail * sizeof(void*));
|
||||
queue->tail += old_capacity;
|
||||
const size_t tocopy = queue->tail;
|
||||
const size_t slots = new_capacity - old_capacity;
|
||||
const size_t batch = (tocopy < slots) ? tocopy : slots;
|
||||
|
||||
CopyMemory(&(queue->array[old_capacity]), queue->array, batch * sizeof(uintptr_t));
|
||||
ZeroMemory(queue->array, batch * sizeof(uintptr_t));
|
||||
|
||||
/* Tail is decremented. if the whole thing is appended
|
||||
* just move the existing tail by old_capacity */
|
||||
if (tocopy < slots)
|
||||
queue->tail += old_capacity;
|
||||
else
|
||||
{
|
||||
const size_t movesize = (queue->tail - batch) * sizeof(uintptr_t);
|
||||
memmove_s(queue->array, queue->tail * sizeof(uintptr_t), &queue->array[batch],
|
||||
movesize);
|
||||
ZeroMemory(&queue->array[batch], movesize);
|
||||
queue->tail -= batch;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
@@ -205,17 +242,10 @@ BOOL Queue_Enqueue(wQueue* queue, const void* obj)
|
||||
goto out;
|
||||
|
||||
if (queue->object.fnObjectNew)
|
||||
queue->array[queue->tail] = queue->object.fnObjectNew(obj);
|
||||
queue->array[queue->tail] = void2uptr(queue->object.fnObjectNew(obj));
|
||||
else
|
||||
{
|
||||
union
|
||||
{
|
||||
const void* cv;
|
||||
void* v;
|
||||
} cnv;
|
||||
cnv.cv = obj;
|
||||
queue->array[queue->tail] = cnv.v;
|
||||
}
|
||||
queue->array[queue->tail] = void2uptr(obj);
|
||||
|
||||
queue->tail = (queue->tail + 1) % queue->capacity;
|
||||
|
||||
{
|
||||
@@ -244,8 +274,8 @@ void* Queue_Dequeue(wQueue* queue)
|
||||
|
||||
if (queue->size > 0)
|
||||
{
|
||||
obj = queue->array[queue->head];
|
||||
queue->array[queue->head] = NULL;
|
||||
obj = uptr2void(queue->array[queue->head]);
|
||||
queue->array[queue->head] = 0;
|
||||
queue->head = (queue->head + 1) % queue->capacity;
|
||||
queue->size--;
|
||||
}
|
||||
@@ -265,11 +295,10 @@ void* Queue_Dequeue(wQueue* queue)
|
||||
void* Queue_Peek(wQueue* queue)
|
||||
{
|
||||
void* obj = NULL;
|
||||
|
||||
Queue_Lock(queue);
|
||||
|
||||
if (queue->size > 0)
|
||||
obj = queue->array[queue->head];
|
||||
obj = uptr2void(queue->array[queue->head]);
|
||||
|
||||
Queue_Unlock(queue);
|
||||
|
||||
@@ -299,9 +328,7 @@ static BOOL default_queue_equals(const void* obj1, const void* obj2)
|
||||
|
||||
wQueue* Queue_New(BOOL synchronized, SSIZE_T capacity, SSIZE_T growthFactor)
|
||||
{
|
||||
wObject* obj = NULL;
|
||||
wQueue* queue = NULL;
|
||||
queue = (wQueue*)calloc(1, sizeof(wQueue));
|
||||
wQueue* queue = (wQueue*)calloc(1, sizeof(wQueue));
|
||||
|
||||
if (!queue)
|
||||
return NULL;
|
||||
@@ -325,9 +352,10 @@ wQueue* Queue_New(BOOL synchronized, SSIZE_T capacity, SSIZE_T growthFactor)
|
||||
if (!queue->event)
|
||||
goto fail;
|
||||
|
||||
obj = Queue_Object(queue);
|
||||
obj->fnObjectEquals = default_queue_equals;
|
||||
|
||||
{
|
||||
wObject* obj = Queue_Object(queue);
|
||||
obj->fnObjectEquals = default_queue_equals;
|
||||
}
|
||||
return queue;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
@@ -348,6 +376,6 @@ void Queue_Free(wQueue* queue)
|
||||
DeleteCriticalSection(&queue->lock);
|
||||
}
|
||||
(void)CloseHandle(queue->event);
|
||||
free((void*)queue->array);
|
||||
free(queue->array);
|
||||
free(queue);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user