152 lines
5.0 KiB
C
152 lines
5.0 KiB
C
/**
|
|||
|
|
* @file kMsgQueue.x.h
|
||
|
|
*
|
||
|
|
* @internal
|
||
|
|
* Copyright (C) 2011-2021 by LMI Technologies Inc.
|
||
|
|
* Licensed under the MIT License.
|
||
|
|
* Redistributed files must retain the above copyright notice.
|
||
|
|
*/
|
||
|
|
#ifndef K_API_MSG_QUEUE_X_H
|
||
|
|
#define K_API_MSG_QUEUE_X_H
|
||
|
|
|
||
|
|
#include <kApi/Threads/kLock.h>
|
||
|
|
|
||
|
|
#define xkMSG_QUEUE_GROWTH_FACTOR (2)
|
||
|
|
#define xkMSG_QUEUE_MIN_CAPACITY (16)
|
||
|
|
|
||
|
|
#define xkMSG_QUEUE_NORMAL_PRUNE_OPTIONS (kMSG_QUEUE_PURGE_OPTION_PRESERVE_CRITICAL | \
|
||
|
|
kMSG_QUEUE_PURGE_OPTION_USE_HANDLER | \
|
||
|
|
kMSG_QUEUE_PURGE_OPTION_DISPOSE_ITEMS | \
|
||
|
|
kMSG_QUEUE_PURGE_OPTION_COUNT_DROPS)
|
||
|
|
|
||
|
|
kDeclareEnumEx(k, kMsgQueueItemOption, kValue)
|
||
|
|
kDeclareEnumEx(k, kMsgQueuePurgeOption, kValue)
|
||
|
|
|
||
|
|
typedef void* xkMsgQueueEntry;
|
||
|
|
|
||
|
|
typedef struct xkMsgQueueEntryStruct//<T>
|
||
|
|
{
|
||
|
|
kSize size; //cached item size (for ref types, kObject_Size result)
|
||
|
|
kMsgQueueItemOption options; //item flags
|
||
|
|
//T item; //queue item
|
||
|
|
} xkMsgQueueEntryStruct;
|
||
|
|
|
||
|
|
typedef struct kMsgQueueClass
|
||
|
|
{
|
||
|
|
kObjectClass base;
|
||
|
|
void* entries; //data buffer
|
||
|
|
kSize entrySize; //size of xkMsgQueueEntry<T> instance
|
||
|
|
xkStructField itemField; //information about generic item field
|
||
|
|
kSize entryCapacity; //maximum count of items before reallocation
|
||
|
|
kSize entryDivisor; //use for index calculation
|
||
|
|
kSize count; //current count of items
|
||
|
|
kSize pruneCount; //current count of pruned items
|
||
|
|
kSize size; //total size of current items
|
||
|
|
kSize maxCount; //maximum count of items
|
||
|
|
kSize maxSize; //maximum total size of items
|
||
|
|
kSize head; //current read index
|
||
|
|
kSemaphore canRemove; //counts available items
|
||
|
|
kLock lock; //mutual exclusion lock
|
||
|
|
kCallback onDrop; //drop handler
|
||
|
|
k64u dropCount; //number of items dropped
|
||
|
|
} kMsgQueueClass;
|
||
|
|
|
||
|
|
kDeclareClassEx(k, kMsgQueue, kObject)
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Forward declarations.
|
||
|
|
*/
|
||
|
|
|
||
|
|
kFx(kStatus) kMsgQueue_Add(kMsgQueue queue, void* item);
|
||
|
|
kFx(kStatus) kMsgQueue_AddEx(kMsgQueue queue, void* item, kMsgQueueItemOption options);
|
||
|
|
kFx(kStatus) kMsgQueue_Remove(kMsgQueue queue, void* item, k64u timeout);
|
||
|
|
kFx(kType) kMsgQueue_ItemType(kMsgQueue queue);
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Private methods.
|
||
|
|
*/
|
||
|
|
|
||
|
|
kFx(kStatus) xkMsgQueue_Init(kMsgQueue queue, kType type, kType itemType, kAlloc allocator);
|
||
|
|
kFx(kStatus) xkMsgQueue_VRelease(kMsgQueue queue);
|
||
|
|
kFx(kStatus) xkMsgQueue_VDisposeItems(kMsgQueue queue);
|
||
|
|
kFx(kSize) xkMsgQueue_VSize(kMsgQueue queue);
|
||
|
|
|
||
|
|
kFx(kStatus) xkMsgQueue_Layout(kMsgQueue queue, kType itemType);
|
||
|
|
|
||
|
|
kFx(kStatus) xkMsgQueue_Prune(kMsgQueue queue, kMsgQueuePurgeOption options, kSize maxCount, kSize maxSize);
|
||
|
|
|
||
|
|
kInlineFx(kBool) xkMsgQueue_IsSplit(kMsgQueue queue)
|
||
|
|
{
|
||
|
|
kObj(kMsgQueue, queue);
|
||
|
|
|
||
|
|
return (obj->head + obj->count) > obj->entryCapacity;
|
||
|
|
}
|
||
|
|
|
||
|
|
kInlineFx(kSize) xkMsgQueue_HeadCount(kMsgQueue queue)
|
||
|
|
{
|
||
|
|
kObj(kMsgQueue, queue);
|
||
|
|
|
||
|
|
if (xkMsgQueue_IsSplit(queue)) return obj->entryCapacity - obj->head;
|
||
|
|
else return obj->count;
|
||
|
|
}
|
||
|
|
|
||
|
|
kInlineFx(kSize) xkMsgQueue_TailCount(kMsgQueue queue)
|
||
|
|
{
|
||
|
|
kObj(kMsgQueue, queue);
|
||
|
|
|
||
|
|
if (xkMsgQueue_IsSplit(queue)) return obj->head + obj->count - obj->entryCapacity;
|
||
|
|
else return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
kInlineFx(kBool) xkMsgQueue_ItemIsRef(kMsgQueue queue)
|
||
|
|
{
|
||
|
|
kObj(kMsgQueue, queue);
|
||
|
|
|
||
|
|
return kType_IsReference(obj->itemField.type);
|
||
|
|
}
|
||
|
|
|
||
|
|
kInlineFx(xkMsgQueueEntryStruct*) xkMsgQueue_EntryAt(kMsgQueue queue, kSize index)
|
||
|
|
{
|
||
|
|
kObj(kMsgQueue, queue);
|
||
|
|
kSize entryIndex = (obj->head + index) % obj->entryDivisor;
|
||
|
|
|
||
|
|
return (xkMsgQueueEntryStruct*) kPointer_ItemOffset(obj->entries, (kSSize)entryIndex, obj->entrySize);
|
||
|
|
}
|
||
|
|
|
||
|
|
kInlineFx(kPointer) xkMsgQueueEntry_Item(kMsgQueue queue, xkMsgQueueEntryStruct* entry)
|
||
|
|
{
|
||
|
|
kObj(kMsgQueue, queue);
|
||
|
|
|
||
|
|
return kPointer_ByteOffset(entry, (kSSize)obj->itemField.offset);
|
||
|
|
}
|
||
|
|
|
||
|
|
kInlineFx(kCallback) xkMsgQueue_DropHandler(kMsgQueue queue)
|
||
|
|
{
|
||
|
|
kObj(kMsgQueue, queue);
|
||
|
|
|
||
|
|
return obj->onDrop;
|
||
|
|
}
|
||
|
|
|
||
|
|
kInlineFx(kStatus) xkMsgQueue_AddT(kMsgQueue queue, void* item, kSize itemSize)
|
||
|
|
{
|
||
|
|
kAssert(xkType_IsPointerCompatible(kMsgQueue_ItemType(queue), itemSize));
|
||
|
|
|
||
|
|
return kMsgQueue_Add(queue, item);
|
||
|
|
}
|
||
|
|
|
||
|
|
kInlineFx(kStatus) xkMsgQueue_AddExT(kMsgQueue queue, void* item, kMsgQueueItemOption options, kSize itemSize)
|
||
|
|
{
|
||
|
|
kAssert(xkType_IsPointerCompatible(kMsgQueue_ItemType(queue), itemSize));
|
||
|
|
|
||
|
|
return kMsgQueue_AddEx(queue, item, options);
|
||
|
|
}
|
||
|
|
|
||
|
|
kInlineFx(kStatus) xkMsgQueue_RemoveT(kMsgQueue queue, void* item, k64u timeout, kSize itemSize)
|
||
|
|
{
|
||
|
|
kAssert(xkType_IsPointerCompatible(kMsgQueue_ItemType(queue), itemSize));
|
||
|
|
|
||
|
|
return kMsgQueue_Remove(queue, item, timeout);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|