Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/winpr/libwinpr/utils/collections/Queue.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * System.Collections.Queue
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
22
#include <winpr/crt.h>
23
#include <winpr/assert.h>
24
25
#include <winpr/collections.h>
26
27
struct 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
  void** array;
39
  CRITICAL_SECTION lock;
40
  HANDLE event;
41
42
  wObject object;
43
  BOOL haveLock;
44
45
  BYTE padding2[4];
46
};
47
48
/**
49
 * C equivalent of the C# Queue Class:
50
 * http://msdn.microsoft.com/en-us/library/system.collections.queue.aspx
51
 */
52
53
/**
54
 * Properties
55
 */
56
57
/**
58
 * Gets the number of elements contained in the Queue.
59
 */
60
61
size_t Queue_Count(wQueue* queue)
62
0
{
63
0
  size_t ret = 0;
64
65
0
  Queue_Lock(queue);
66
67
0
  ret = queue->size;
68
69
0
  Queue_Unlock(queue);
70
71
0
  return ret;
72
0
}
73
74
/**
75
 * Lock access to the ArrayList
76
 */
77
78
void Queue_Lock(wQueue* queue)
79
0
{
80
0
  WINPR_ASSERT(queue);
81
0
  if (queue->synchronized)
82
0
    EnterCriticalSection(&queue->lock);
83
0
}
84
85
/**
86
 * Unlock access to the ArrayList
87
 */
88
89
void Queue_Unlock(wQueue* queue)
90
0
{
91
0
  WINPR_ASSERT(queue);
92
0
  if (queue->synchronized)
93
0
    LeaveCriticalSection(&queue->lock);
94
0
}
95
96
/**
97
 * Gets an event which is set when the queue is non-empty
98
 */
99
100
HANDLE Queue_Event(wQueue* queue)
101
0
{
102
0
  WINPR_ASSERT(queue);
103
0
  return queue->event;
104
0
}
105
106
wObject* Queue_Object(wQueue* queue)
107
0
{
108
0
  WINPR_ASSERT(queue);
109
0
  return &queue->object;
110
0
}
111
112
/**
113
 * Methods
114
 */
115
116
/**
117
 * Removes all objects from the Queue.
118
 */
119
120
void Queue_Clear(wQueue* queue)
121
0
{
122
0
  Queue_Lock(queue);
123
124
0
  for (size_t index = queue->head; index != queue->tail; index = (index + 1) % queue->capacity)
125
0
  {
126
0
    if (queue->object.fnObjectFree)
127
0
      queue->object.fnObjectFree(queue->array[index]);
128
129
0
    queue->array[index] = NULL;
130
0
  }
131
132
0
  queue->size = 0;
133
0
  queue->head = queue->tail = 0;
134
0
  (void)ResetEvent(queue->event);
135
0
  Queue_Unlock(queue);
136
0
}
137
138
/**
139
 * Determines whether an element is in the Queue.
140
 */
141
142
BOOL Queue_Contains(wQueue* queue, const void* obj)
143
0
{
144
0
  BOOL found = FALSE;
145
146
0
  Queue_Lock(queue);
147
148
0
  for (size_t index = 0; index < queue->tail; index++)
149
0
  {
150
0
    if (queue->object.fnObjectEquals(queue->array[index], obj))
151
0
    {
152
0
      found = TRUE;
153
0
      break;
154
0
    }
155
0
  }
156
157
0
  Queue_Unlock(queue);
158
159
0
  return found;
160
0
}
161
162
static BOOL Queue_EnsureCapacity(wQueue* queue, size_t count)
163
0
{
164
0
  WINPR_ASSERT(queue);
165
166
0
  if (queue->size + count >= queue->capacity)
167
0
  {
168
0
    const size_t old_capacity = queue->capacity;
169
0
    size_t new_capacity = queue->capacity * queue->growthFactor;
170
0
    void** newArray = NULL;
171
0
    if (new_capacity < queue->size + count)
172
0
      new_capacity = queue->size + count;
173
0
    newArray = (void**)realloc((void*)queue->array, sizeof(void*) * new_capacity);
174
175
0
    if (!newArray)
176
0
      return FALSE;
177
178
0
    queue->capacity = new_capacity;
179
0
    queue->array = newArray;
180
0
    ZeroMemory((void*)&(queue->array[old_capacity]),
181
0
               (new_capacity - old_capacity) * sizeof(void*));
182
183
    /* rearrange wrapped entries */
184
0
    if (queue->tail <= queue->head)
185
0
    {
186
0
      CopyMemory((void*)&(queue->array[old_capacity]), (void*)queue->array,
187
0
                 queue->tail * sizeof(void*));
188
0
      queue->tail += old_capacity;
189
0
    }
190
0
  }
191
0
  return TRUE;
192
0
}
193
194
/**
195
 * Adds an object to the end of the Queue.
196
 */
197
198
BOOL Queue_Enqueue(wQueue* queue, const void* obj)
199
0
{
200
0
  BOOL ret = TRUE;
201
202
0
  Queue_Lock(queue);
203
204
0
  if (!Queue_EnsureCapacity(queue, 1))
205
0
    goto out;
206
207
0
  if (queue->object.fnObjectNew)
208
0
    queue->array[queue->tail] = queue->object.fnObjectNew(obj);
209
0
  else
210
0
  {
211
0
    union
212
0
    {
213
0
      const void* cv;
214
0
      void* v;
215
0
    } cnv;
216
0
    cnv.cv = obj;
217
0
    queue->array[queue->tail] = cnv.v;
218
0
  }
219
0
  queue->tail = (queue->tail + 1) % queue->capacity;
220
221
0
  const BOOL signalSet = queue->size == 0;
222
0
  queue->size++;
223
224
0
  if (signalSet)
225
0
    (void)SetEvent(queue->event);
226
0
out:
227
228
0
  Queue_Unlock(queue);
229
230
0
  return ret;
231
0
}
232
233
/**
234
 * Removes and returns the object at the beginning of the Queue.
235
 */
236
237
void* Queue_Dequeue(wQueue* queue)
238
0
{
239
0
  void* obj = NULL;
240
241
0
  Queue_Lock(queue);
242
243
0
  if (queue->size > 0)
244
0
  {
245
0
    obj = queue->array[queue->head];
246
0
    queue->array[queue->head] = NULL;
247
0
    queue->head = (queue->head + 1) % queue->capacity;
248
0
    queue->size--;
249
0
  }
250
251
0
  if (queue->size < 1)
252
0
    (void)ResetEvent(queue->event);
253
254
0
  Queue_Unlock(queue);
255
256
0
  return obj;
257
0
}
258
259
/**
260
 * Returns the object at the beginning of the Queue without removing it.
261
 */
262
263
void* Queue_Peek(wQueue* queue)
264
0
{
265
0
  void* obj = NULL;
266
267
0
  Queue_Lock(queue);
268
269
0
  if (queue->size > 0)
270
0
    obj = queue->array[queue->head];
271
272
0
  Queue_Unlock(queue);
273
274
0
  return obj;
275
0
}
276
277
void Queue_Discard(wQueue* queue)
278
0
{
279
0
  void* obj = NULL;
280
281
0
  Queue_Lock(queue);
282
0
  obj = Queue_Dequeue(queue);
283
284
0
  if (queue->object.fnObjectFree)
285
0
    queue->object.fnObjectFree(obj);
286
0
  Queue_Unlock(queue);
287
0
}
288
289
static BOOL default_queue_equals(const void* obj1, const void* obj2)
290
0
{
291
0
  return (obj1 == obj2);
292
0
}
293
294
/**
295
 * Construction, Destruction
296
 */
297
298
wQueue* Queue_New(BOOL synchronized, SSIZE_T capacity, SSIZE_T growthFactor)
299
0
{
300
0
  wObject* obj = NULL;
301
0
  wQueue* queue = NULL;
302
0
  queue = (wQueue*)calloc(1, sizeof(wQueue));
303
304
0
  if (!queue)
305
0
    return NULL;
306
307
0
  queue->synchronized = synchronized;
308
309
0
  queue->growthFactor = 2;
310
0
  if (growthFactor > 0)
311
0
    queue->growthFactor = (size_t)growthFactor;
312
313
0
  if (capacity <= 0)
314
0
    capacity = 32;
315
0
  if (!InitializeCriticalSectionAndSpinCount(&queue->lock, 4000))
316
0
    goto fail;
317
0
  queue->haveLock = TRUE;
318
0
  if (!Queue_EnsureCapacity(queue, (size_t)capacity))
319
0
    goto fail;
320
321
0
  queue->event = CreateEvent(NULL, TRUE, FALSE, NULL);
322
323
0
  if (!queue->event)
324
0
    goto fail;
325
326
0
  obj = Queue_Object(queue);
327
0
  obj->fnObjectEquals = default_queue_equals;
328
329
0
  return queue;
330
0
fail:
331
0
  WINPR_PRAGMA_DIAG_PUSH
332
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
333
0
  Queue_Free(queue);
334
0
  WINPR_PRAGMA_DIAG_POP
335
0
  return NULL;
336
0
}
337
338
void Queue_Free(wQueue* queue)
339
0
{
340
0
  if (!queue)
341
0
    return;
342
343
0
  if (queue->haveLock)
344
0
  {
345
0
    Queue_Clear(queue);
346
0
    DeleteCriticalSection(&queue->lock);
347
0
  }
348
0
  (void)CloseHandle(queue->event);
349
0
  free((void*)queue->array);
350
0
  free(queue);
351
0
}