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)
106 const size_t increment = 128;
109 const size_t required = queue->size + count;
111 if ((required < queue->size) || (required < count) ||
112 (required > (SIZE_MAX - increment) /
sizeof(wMessage)))
115 if (required > queue->capacity)
117 const size_t old_capacity = queue->capacity;
118 const size_t new_capacity = required + increment;
120 wMessage* new_arr = (wMessage*)realloc(queue->array,
sizeof(wMessage) * new_capacity);
123 queue->array = new_arr;
124 queue->capacity = new_capacity;
125 ZeroMemory(&(queue->array[old_capacity]), (new_capacity - old_capacity) *
sizeof(wMessage));
132 if (queue->tail <= queue->head)
134 size_t tocopy = queue->tail;
135 size_t slots = new_capacity - old_capacity;
136 const size_t batch = (tocopy < slots) ? tocopy : slots;
137 CopyMemory(&(queue->array[old_capacity]), queue->array, batch *
sizeof(wMessage));
143 ZeroMemory(queue->array, batch *
sizeof(wMessage));
144 queue->tail += old_capacity;
148 const size_t remain = queue->tail - batch;
149 const size_t movesize = remain *
sizeof(wMessage);
150 memmove_s(queue->array, queue->tail *
sizeof(wMessage), &queue->array[batch],
153 const size_t zerooffset = remain;
154 const size_t zerosize = (queue->tail - remain) *
sizeof(wMessage);
155 ZeroMemory(&queue->array[zerooffset], zerosize);
156 queue->tail -= batch;
164BOOL MessageQueue_Dispatch(wMessageQueue* queue,
const wMessage* message)
166 wMessage* dst = NULL;
174 EnterCriticalSection(&queue->lock);
179 if (!MessageQueue_EnsureCapacity(queue, 1))
182 dst = &(queue->array[queue->tail]);
184 dst->time = GetTickCount64();
186 queue->tail = (queue->tail + 1) % queue->capacity;
190 (void)SetEvent(queue->event);
192 if (message->id == WMQ_QUIT)
193 queue->closed = TRUE;
197 LeaveCriticalSection(&queue->lock);
201BOOL MessageQueue_Post(wMessageQueue* queue,
void* context, UINT32 type,
void* wParam,
void* lParam)
203 wMessage message = { 0 };
205 message.context = context;
207 message.wParam = wParam;
208 message.lParam = lParam;
211 return MessageQueue_Dispatch(queue, &message);
214BOOL MessageQueue_PostQuit(wMessageQueue* queue,
int nExitCode)
216 return MessageQueue_Post(queue, NULL, WMQ_QUIT, (
void*)(
size_t)nExitCode, NULL);
219int MessageQueue_Get(wMessageQueue* queue, wMessage* message)
223 if (!MessageQueue_Wait(queue))
226 EnterCriticalSection(&queue->lock);
230 CopyMemory(message, &(queue->array[queue->head]),
sizeof(wMessage));
231 ZeroMemory(&(queue->array[queue->head]),
sizeof(wMessage));
232 queue->head = (queue->head + 1) % queue->capacity;
236 (void)ResetEvent(queue->event);
238 status = (message->id != WMQ_QUIT) ? 1 : 0;
241 LeaveCriticalSection(&queue->lock);
246int MessageQueue_Peek(wMessageQueue* queue, wMessage* message, BOOL remove)
251 EnterCriticalSection(&queue->lock);
255 CopyMemory(message, &(queue->array[queue->head]),
sizeof(wMessage));
260 ZeroMemory(&(queue->array[queue->head]),
sizeof(wMessage));
261 queue->head = (queue->head + 1) % queue->capacity;
265 (void)ResetEvent(queue->event);
269 LeaveCriticalSection(&queue->lock);
278wMessageQueue* MessageQueue_New(
const wObject* callback)
280 wMessageQueue* queue = NULL;
282 queue = (wMessageQueue*)calloc(1,
sizeof(wMessageQueue));
286 if (!InitializeCriticalSectionAndSpinCount(&queue->lock, 4000))
289 if (!MessageQueue_EnsureCapacity(queue, 32))
292 queue->event = CreateEvent(NULL, TRUE, FALSE, NULL);
297 queue->object = *callback;
302 WINPR_PRAGMA_DIAG_PUSH
303 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
304 MessageQueue_Free(queue);
305 WINPR_PRAGMA_DIAG_POP
309void MessageQueue_Free(wMessageQueue* queue)
315 MessageQueue_Clear(queue);
317 (void)CloseHandle(queue->event);
318 DeleteCriticalSection(&queue->lock);
324int MessageQueue_Clear(wMessageQueue* queue)
329 WINPR_ASSERT(queue->event);
331 EnterCriticalSection(&queue->lock);
333 while (queue->size > 0)
335 wMessage* msg = &(queue->array[queue->head]);
338 if (queue->object.fnObjectUninit)
339 queue->object.fnObjectUninit(msg);
340 if (queue->object.fnObjectFree)
341 queue->object.fnObjectFree(msg);
343 ZeroMemory(msg,
sizeof(wMessage));
345 queue->head = (queue->head + 1) % queue->capacity;
348 (void)ResetEvent(queue->event);
349 queue->closed = FALSE;
351 LeaveCriticalSection(&queue->lock);
This struct contains function pointer to initialize/free objects.