FreeRDP
Loading...
Searching...
No Matches
Queue.c
1
20#include <winpr/config.h>
21
22#include <winpr/crt.h>
23#include <winpr/assert.h>
24
25#include <winpr/collections.h>
26
27struct s_wQueue
28{
29 size_t capacity;
30 size_t growthFactor;
31 BOOL synchronized;
32
33 BYTE padding[4];
34
35 size_t head;
36 size_t tail;
37 size_t size;
38 uintptr_t* array;
40 HANDLE event;
41
42 wObject object;
43 BOOL haveLock;
44
45 BYTE padding2[4];
46};
47
48static inline void* uptr2void(uintptr_t ptr)
49{
50 return (void*)ptr;
51}
52
53static inline uintptr_t void2uptr(const void* ptr)
54{
55 return (uintptr_t)ptr;
56}
57
71size_t Queue_Count(wQueue* queue)
72{
73 size_t ret = 0;
74
75 Queue_Lock(queue);
76
77 ret = queue->size;
78
79 Queue_Unlock(queue);
80
81 return ret;
82}
83
84size_t Queue_Capacity(wQueue* queue)
85{
86 WINPR_ASSERT(queue);
87
88 Queue_Lock(queue);
89
90 const size_t ret = queue->capacity;
91
92 Queue_Unlock(queue);
93
94 return ret;
95}
96
101void Queue_Lock(wQueue* queue)
102{
103 WINPR_ASSERT(queue);
104 if (queue->synchronized)
105 EnterCriticalSection(&queue->lock);
106}
107
112void Queue_Unlock(wQueue* queue)
113{
114 WINPR_ASSERT(queue);
115 if (queue->synchronized)
116 LeaveCriticalSection(&queue->lock);
117}
118
123HANDLE Queue_Event(wQueue* queue)
124{
125 WINPR_ASSERT(queue);
126 return queue->event;
127}
128
129wObject* Queue_Object(wQueue* queue)
130{
131 WINPR_ASSERT(queue);
132 return &queue->object;
133}
134
143void Queue_Clear(wQueue* queue)
144{
145 Queue_Lock(queue);
146
147 for (size_t index = queue->head; index != queue->tail; index = (index + 1) % queue->capacity)
148 {
149 if (queue->object.fnObjectFree)
150 {
151 void* obj = uptr2void(queue->array[index]);
152 queue->object.fnObjectFree(obj);
153 }
154
155 queue->array[index] = 0;
156 }
157
158 queue->size = 0;
159 queue->head = queue->tail = 0;
160 (void)ResetEvent(queue->event);
161 Queue_Unlock(queue);
162}
163
168BOOL Queue_Contains(wQueue* queue, const void* obj)
169{
170 BOOL found = FALSE;
171
172 Queue_Lock(queue);
173
174 for (size_t index = 0; index < queue->tail; index++)
175 {
176 void* ptr = uptr2void(queue->array[index]);
177 if (queue->object.fnObjectEquals(ptr, obj))
178 {
179 found = TRUE;
180 break;
181 }
182 }
183
184 Queue_Unlock(queue);
185
186 return found;
187}
188
189static BOOL Queue_EnsureCapacity(wQueue* queue, size_t count)
190{
191 BOOL res = TRUE;
192 const size_t blocksize = 32ull;
193 WINPR_ASSERT(queue);
194
195 if (queue->growthFactor > SIZE_MAX / blocksize)
196 return FALSE;
197
198 const size_t increment = blocksize * queue->growthFactor;
199 if (queue->size > SIZE_MAX - count)
200 return FALSE;
201
202 const size_t required = queue->size + count;
203 if (required > queue->capacity)
204 {
205 const size_t old_capacity = queue->capacity;
206 if (required > SIZE_MAX - increment)
207 return FALSE;
208
209 const size_t new_capacity = required + increment - required % increment;
210 if (new_capacity > SIZE_MAX / sizeof(BYTE*))
211 return FALSE;
212
213 uintptr_t* newArray = (uintptr_t*)realloc(queue->array, sizeof(uintptr_t) * new_capacity);
214
215 if (!newArray)
216 return FALSE;
217
218 queue->capacity = new_capacity;
219 queue->array = newArray;
220 ZeroMemory(&(queue->array[old_capacity]),
221 (new_capacity - old_capacity) * sizeof(uintptr_t));
222
223 /* rearrange wrapped entries */
224 if (queue->tail <= queue->head)
225 {
226 const size_t tocopy = queue->tail;
227 const size_t slots = new_capacity - old_capacity;
228 const size_t batch = (tocopy < slots) ? tocopy : slots;
229
230 CopyMemory(&(queue->array[old_capacity]), queue->array, batch * sizeof(uintptr_t));
231
232 /* Tail is decremented. if the whole thing is appended
233 * just move the existing tail by old_capacity */
234 if (tocopy < slots)
235 {
236 ZeroMemory(queue->array, batch * sizeof(uintptr_t));
237 queue->tail += old_capacity;
238 }
239 else
240 {
241 const size_t remain = queue->tail - batch;
242 const size_t movesize = remain * sizeof(uintptr_t);
243 res = memmove_s(queue->array, queue->tail * sizeof(uintptr_t), &queue->array[batch],
244 movesize) >= 0;
245
246 const size_t zerooffset = remain;
247 const size_t zerosize = (queue->tail - remain) * sizeof(uintptr_t);
248 ZeroMemory(&queue->array[zerooffset], zerosize);
249 queue->tail -= batch;
250 }
251 }
252 }
253 return res;
254}
255
260BOOL Queue_Enqueue(wQueue* queue, const void* obj)
261{
262 BOOL ret = TRUE;
263
264 Queue_Lock(queue);
265
266 if (!Queue_EnsureCapacity(queue, 1))
267 goto out;
268
269 if (queue->object.fnObjectNew)
270 queue->array[queue->tail] = void2uptr(queue->object.fnObjectNew(obj));
271 else
272 queue->array[queue->tail] = void2uptr(obj);
273
274 queue->tail = (queue->tail + 1) % queue->capacity;
275
276 {
277 const BOOL signalSet = queue->size == 0;
278 queue->size++;
279
280 if (signalSet)
281 {
282 if (!SetEvent(queue->event))
283 goto out;
284 }
285 }
286out:
287
288 Queue_Unlock(queue);
289
290 return ret;
291}
292
297void* Queue_Dequeue(wQueue* queue)
298{
299 void* obj = nullptr;
300
301 Queue_Lock(queue);
302
303 if (queue->size > 0)
304 {
305 obj = uptr2void(queue->array[queue->head]);
306 queue->array[queue->head] = 0;
307 queue->head = (queue->head + 1) % queue->capacity;
308 queue->size--;
309 }
310
311 if (queue->size < 1)
312 (void)ResetEvent(queue->event);
313
314 Queue_Unlock(queue);
315
316 return obj;
317}
318
323void* Queue_Peek(wQueue* queue)
324{
325 void* obj = nullptr;
326 Queue_Lock(queue);
327
328 if (queue->size > 0)
329 obj = uptr2void(queue->array[queue->head]);
330
331 Queue_Unlock(queue);
332
333 return obj;
334}
335
336void Queue_Discard(wQueue* queue)
337{
338 void* obj = nullptr;
339
340 Queue_Lock(queue);
341 obj = Queue_Dequeue(queue);
342
343 if (queue->object.fnObjectFree)
344 queue->object.fnObjectFree(obj);
345 Queue_Unlock(queue);
346}
347
348static BOOL default_queue_equals(const void* obj1, const void* obj2)
349{
350 return (obj1 == obj2);
351}
352
357wQueue* Queue_New(BOOL synchronized, SSIZE_T capacity, SSIZE_T growthFactor)
358{
359 wQueue* queue = (wQueue*)calloc(1, sizeof(wQueue));
360
361 if (!queue)
362 return nullptr;
363
364 queue->synchronized = synchronized;
365
366 queue->growthFactor = 2;
367 if (growthFactor > 0)
368 queue->growthFactor = (size_t)growthFactor;
369
370 if (capacity <= 0)
371 capacity = 32;
372 if (!InitializeCriticalSectionAndSpinCount(&queue->lock, 4000))
373 goto fail;
374 queue->haveLock = TRUE;
375 if (!Queue_EnsureCapacity(queue, (size_t)capacity))
376 goto fail;
377
378 queue->event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
379
380 if (!queue->event)
381 goto fail;
382
383 {
384 wObject* obj = Queue_Object(queue);
385 obj->fnObjectEquals = default_queue_equals;
386 }
387 return queue;
388fail:
389 WINPR_PRAGMA_DIAG_PUSH
390 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
391 Queue_Free(queue);
392 WINPR_PRAGMA_DIAG_POP
393 return nullptr;
394}
395
396void Queue_Free(wQueue* queue)
397{
398 if (!queue)
399 return;
400
401 if (queue->haveLock)
402 {
403 Queue_Clear(queue);
404 DeleteCriticalSection(&queue->lock);
405 }
406 (void)CloseHandle(queue->event);
407 free(queue->array);
408 free(queue);
409}
This struct contains function pointer to initialize/free objects.
Definition collections.h:52
OBJECT_EQUALS_FN fnObjectEquals
Definition collections.h:59