20#include <winpr/config.h>
23#include <winpr/sysinfo.h>
24#include <winpr/assert.h>
26#include <winpr/collections.h>
51wObject* MessageQueue_Object(wMessageQueue* queue)
54 return &queue->object;
61HANDLE MessageQueue_Event(wMessageQueue* queue)
71size_t MessageQueue_Size(wMessageQueue* queue)
74 EnterCriticalSection(&queue->lock);
75 const size_t ret = queue->size;
76 LeaveCriticalSection(&queue->lock);
80size_t MessageQueue_Capacity(wMessageQueue* queue)
83 EnterCriticalSection(&queue->lock);
84 const size_t ret = queue->capacity;
85 LeaveCriticalSection(&queue->lock);
93BOOL MessageQueue_Wait(wMessageQueue* queue)
98 if (WaitForSingleObject(queue->event, INFINITE) == WAIT_OBJECT_0)
104static BOOL MessageQueue_EnsureCapacity(wMessageQueue* queue,
size_t count)
107 const size_t increment = 128;
110 const size_t required = queue->size + count;
112 if ((required < queue->size) || (required < count) ||
113 (required > (SIZE_MAX - increment) /
sizeof(wMessage)))
116 if (required > queue->capacity)
118 const size_t old_capacity = queue->capacity;
119 const size_t new_capacity = required + increment;
121 wMessage* new_arr = (wMessage*)realloc(queue->array,
sizeof(wMessage) * new_capacity);
124 queue->array = new_arr;
125 queue->capacity = new_capacity;
126 ZeroMemory(&(queue->array[old_capacity]), (new_capacity - old_capacity) *
sizeof(wMessage));
133 if (queue->tail <= queue->head)
135 size_t tocopy = queue->tail;
136 size_t slots = new_capacity - old_capacity;
137 const size_t batch = (tocopy < slots) ? tocopy : slots;
138 CopyMemory(&(queue->array[old_capacity]), queue->array, batch *
sizeof(wMessage));
144 ZeroMemory(queue->array, batch *
sizeof(wMessage));
145 queue->tail += old_capacity;
149 const size_t remain = queue->tail - batch;
150 const size_t movesize = remain *
sizeof(wMessage);
151 res = memmove_s(queue->array, queue->tail *
sizeof(wMessage), &queue->array[batch],
154 const size_t zerooffset = remain;
155 const size_t zerosize = (queue->tail - remain) *
sizeof(wMessage);
156 ZeroMemory(&queue->array[zerooffset], zerosize);
157 queue->tail -= batch;
165BOOL MessageQueue_Dispatch(wMessageQueue* queue,
const wMessage* message)
167 wMessage* dst =
nullptr;
175 EnterCriticalSection(&queue->lock);
180 if (!MessageQueue_EnsureCapacity(queue, 1))
183 dst = &(queue->array[queue->tail]);
185 dst->time = GetTickCount64();
187 queue->tail = (queue->tail + 1) % queue->capacity;
191 (void)SetEvent(queue->event);
193 if (message->id == WMQ_QUIT)
194 queue->closed = TRUE;
198 LeaveCriticalSection(&queue->lock);
202BOOL MessageQueue_Post(wMessageQueue* queue,
void* context, UINT32 type,
void* wParam,
void* lParam)
204 wMessage message = WINPR_C_ARRAY_INIT;
206 message.context = context;
208 message.wParam = wParam;
209 message.lParam = lParam;
210 message.Free =
nullptr;
212 return MessageQueue_Dispatch(queue, &message);
215BOOL MessageQueue_PostQuit(wMessageQueue* queue,
int nExitCode)
217 return MessageQueue_Post(queue,
nullptr, WMQ_QUIT, (
void*)(
size_t)nExitCode,
nullptr);
220int MessageQueue_Get(wMessageQueue* queue, wMessage* message)
224 if (!MessageQueue_Wait(queue))
227 EnterCriticalSection(&queue->lock);
231 CopyMemory(message, &(queue->array[queue->head]),
sizeof(wMessage));
232 ZeroMemory(&(queue->array[queue->head]),
sizeof(wMessage));
233 queue->head = (queue->head + 1) % queue->capacity;
237 (void)ResetEvent(queue->event);
239 status = (message->id != WMQ_QUIT) ? 1 : 0;
242 LeaveCriticalSection(&queue->lock);
247int MessageQueue_Peek(wMessageQueue* queue, wMessage* message, BOOL remove)
252 EnterCriticalSection(&queue->lock);
256 CopyMemory(message, &(queue->array[queue->head]),
sizeof(wMessage));
261 ZeroMemory(&(queue->array[queue->head]),
sizeof(wMessage));
262 queue->head = (queue->head + 1) % queue->capacity;
267 if (!ResetEvent(queue->event))
273 LeaveCriticalSection(&queue->lock);
282wMessageQueue* MessageQueue_New(
const wObject* callback)
284 wMessageQueue* queue =
nullptr;
286 queue = (wMessageQueue*)calloc(1,
sizeof(wMessageQueue));
290 if (!InitializeCriticalSectionAndSpinCount(&queue->lock, 4000))
293 if (!MessageQueue_EnsureCapacity(queue, 32))
296 queue->event = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
301 queue->object = *callback;
306 WINPR_PRAGMA_DIAG_PUSH
307 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
308 MessageQueue_Free(queue);
309 WINPR_PRAGMA_DIAG_POP
313void MessageQueue_Free(wMessageQueue* queue)
319 MessageQueue_Clear(queue);
321 (void)CloseHandle(queue->event);
322 DeleteCriticalSection(&queue->lock);
328int MessageQueue_Clear(wMessageQueue* queue)
333 WINPR_ASSERT(queue->event);
335 EnterCriticalSection(&queue->lock);
337 while (queue->size > 0)
339 wMessage* msg = &(queue->array[queue->head]);
342 if (queue->object.fnObjectUninit)
343 queue->object.fnObjectUninit(msg);
344 if (queue->object.fnObjectFree)
345 queue->object.fnObjectFree(msg);
347 ZeroMemory(msg,
sizeof(wMessage));
349 queue->head = (queue->head + 1) % queue->capacity;
352 if (!ResetEvent(queue->event))
354 queue->closed = FALSE;
356 LeaveCriticalSection(&queue->lock);
This struct contains function pointer to initialize/free objects.