FreeRDP
Loading...
Searching...
No Matches
BufferPool.c
1
20#include <winpr/config.h>
21
22#include <winpr/crt.h>
23
24#include <winpr/collections.h>
25
26#ifndef MAX
27#define MAX(a, b) ((a) > (b)) ? (a) : (b)
28#endif
29
30typedef struct
31{
32 SSIZE_T size;
33 void* buffer;
34} wBufferPoolItem;
35
36struct s_wBufferPool
37{
38 SSIZE_T fixedSize;
39 DWORD alignment;
40 BOOL synchronized;
42
43 SSIZE_T size;
44 SSIZE_T capacity;
45 void** array;
46
47 SSIZE_T aSize;
48 SSIZE_T aCapacity;
49 wBufferPoolItem* aArray;
50
51 SSIZE_T uSize;
52 SSIZE_T uCapacity;
53 wBufferPoolItem* uArray;
54};
55
56static BOOL BufferPool_Lock(wBufferPool* pool)
57{
58 if (!pool)
59 return FALSE;
60
61 if (pool->synchronized)
62 EnterCriticalSection(&pool->lock);
63 return TRUE;
64}
65
66static BOOL BufferPool_Unlock(wBufferPool* pool)
67{
68 if (!pool)
69 return FALSE;
70
71 if (pool->synchronized)
72 LeaveCriticalSection(&pool->lock);
73 return TRUE;
74}
75
85static BOOL BufferPool_ShiftAvailable(wBufferPool* pool, size_t index, int count)
86{
87 if (count > 0)
88 {
89 if (pool->aSize + count > pool->aCapacity)
90 {
91 wBufferPoolItem* newArray = NULL;
92 SSIZE_T newCapacity = pool->aSize + count;
93 newCapacity += (newCapacity + 2) / 2;
94
95 WINPR_ASSERT(newCapacity > 0);
96 if (pool->alignment > 0)
97 newArray = (wBufferPoolItem*)winpr_aligned_realloc(
98 pool->aArray,
99 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity),
100 pool->alignment);
101 else
102 newArray = (wBufferPoolItem*)realloc(
103 pool->aArray,
104 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
105 if (!newArray)
106 return FALSE;
107 pool->aArray = newArray;
108 pool->aCapacity = newCapacity;
109 }
110
111 MoveMemory(
112 &pool->aArray[index + WINPR_ASSERTING_INT_CAST(size_t, count)], &pool->aArray[index],
113 (WINPR_ASSERTING_INT_CAST(size_t, pool->aSize) - index) * sizeof(wBufferPoolItem));
114 pool->aSize += count;
115 }
116 else if (count < 0)
117 {
118 MoveMemory(
119 &pool->aArray[index], &pool->aArray[index + WINPR_ASSERTING_INT_CAST(size_t, -count)],
120 (WINPR_ASSERTING_INT_CAST(size_t, pool->aSize) - index) * sizeof(wBufferPoolItem));
121 pool->aSize += count;
122 }
123 return TRUE;
124}
125
126static BOOL BufferPool_ShiftUsed(wBufferPool* pool, SSIZE_T index, SSIZE_T count)
127{
128 if (count > 0)
129 {
130 if (pool->uSize + count > pool->uCapacity)
131 {
132 SSIZE_T newUCapacity = pool->uCapacity * 2;
133 wBufferPoolItem* newUArray = NULL;
134 if (pool->alignment > 0)
135 newUArray = (wBufferPoolItem*)winpr_aligned_realloc(
136 pool->uArray,
137 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newUCapacity),
138 pool->alignment);
139 else
140 newUArray = (wBufferPoolItem*)realloc(
141 pool->uArray,
142 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newUCapacity));
143 if (!newUArray)
144 return FALSE;
145 pool->uCapacity = newUCapacity;
146 pool->uArray = newUArray;
147 }
148
149 MoveMemory(&pool->uArray[index + count], &pool->uArray[index],
150 WINPR_ASSERTING_INT_CAST(size_t, pool->uSize - index) * sizeof(wBufferPoolItem));
151 pool->uSize += count;
152 }
153 else if (count < 0)
154 {
155 MoveMemory(&pool->uArray[index], &pool->uArray[index - count],
156 WINPR_ASSERTING_INT_CAST(size_t, pool->uSize - index) * sizeof(wBufferPoolItem));
157 pool->uSize += count;
158 }
159 return TRUE;
160}
161
166SSIZE_T BufferPool_GetPoolSize(wBufferPool* pool)
167{
168 SSIZE_T size = 0;
169
170 BufferPool_Lock(pool);
171
172 if (pool->fixedSize)
173 {
174 /* fixed size buffers */
175 size = pool->size;
176 }
177 else
178 {
179 /* variable size buffers */
180 size = pool->uSize;
181 }
182
183 BufferPool_Unlock(pool);
184
185 return size;
186}
187
192SSIZE_T BufferPool_GetBufferSize(wBufferPool* pool, const void* buffer)
193{
194 SSIZE_T size = 0;
195 BOOL found = FALSE;
196
197 BufferPool_Lock(pool);
198
199 if (pool->fixedSize)
200 {
201 /* fixed size buffers */
202 size = pool->fixedSize;
203 found = TRUE;
204 }
205 else
206 {
207 /* variable size buffers */
208
209 for (SSIZE_T index = 0; index < pool->uSize; index++)
210 {
211 if (pool->uArray[index].buffer == buffer)
212 {
213 size = pool->uArray[index].size;
214 found = TRUE;
215 break;
216 }
217 }
218 }
219
220 BufferPool_Unlock(pool);
221
222 return (found) ? size : -1;
223}
224
229void* BufferPool_Take(wBufferPool* pool, SSIZE_T size)
230{
231 SSIZE_T maxSize = 0;
232 SSIZE_T maxIndex = 0;
233 SSIZE_T foundIndex = -1;
234 BOOL found = FALSE;
235 void* buffer = NULL;
236
237 BufferPool_Lock(pool);
238
239 if (pool->fixedSize)
240 {
241 /* fixed size buffers */
242
243 if (pool->size > 0)
244 buffer = pool->array[--(pool->size)];
245
246 if (!buffer)
247 {
248 if (pool->alignment)
249 buffer = winpr_aligned_malloc(WINPR_ASSERTING_INT_CAST(size_t, pool->fixedSize),
250 pool->alignment);
251 else
252 buffer = malloc(WINPR_ASSERTING_INT_CAST(size_t, pool->fixedSize));
253 }
254
255 if (!buffer)
256 goto out_error;
257 }
258 else
259 {
260 /* variable size buffers */
261
262 maxSize = 0;
263 maxIndex = 0;
264
265 if (size < 1)
266 size = pool->fixedSize;
267
268 for (SSIZE_T index = 0; index < pool->aSize; index++)
269 {
270 if (pool->aArray[index].size > maxSize)
271 {
272 maxIndex = index;
273 maxSize = pool->aArray[index].size;
274 }
275
276 if (pool->aArray[index].size >= size)
277 {
278 foundIndex = index;
279 found = TRUE;
280 break;
281 }
282 }
283
284 if (!found && maxSize)
285 {
286 foundIndex = maxIndex;
287 found = TRUE;
288 }
289
290 if (!found)
291 {
292 if (!size)
293 buffer = NULL;
294 else
295 {
296 if (pool->alignment)
297 buffer = winpr_aligned_malloc(WINPR_ASSERTING_INT_CAST(size_t, size),
298 pool->alignment);
299 else
300 buffer = malloc(WINPR_ASSERTING_INT_CAST(size_t, size));
301
302 if (!buffer)
303 goto out_error;
304 }
305 }
306 else
307 {
308 buffer = pool->aArray[foundIndex].buffer;
309
310 if (maxSize < size)
311 {
312 void* newBuffer = NULL;
313 if (pool->alignment)
314 newBuffer = winpr_aligned_realloc(
315 buffer, WINPR_ASSERTING_INT_CAST(size_t, size), pool->alignment);
316 else
317 newBuffer = realloc(buffer, WINPR_ASSERTING_INT_CAST(size_t, size));
318
319 if (!newBuffer)
320 goto out_error_no_free;
321
322 buffer = newBuffer;
323 }
324
325 if (!BufferPool_ShiftAvailable(pool, WINPR_ASSERTING_INT_CAST(size_t, foundIndex), -1))
326 goto out_error;
327 }
328
329 if (!buffer)
330 goto out_error;
331
332 if (pool->uSize + 1 > pool->uCapacity)
333 {
334 size_t newUCapacity = WINPR_ASSERTING_INT_CAST(size_t, pool->uCapacity);
335 newUCapacity += (newUCapacity + 2) / 2;
336 if (newUCapacity > SSIZE_MAX)
337 goto out_error;
338 wBufferPoolItem* newUArray =
339 (wBufferPoolItem*)realloc(pool->uArray, sizeof(wBufferPoolItem) * newUCapacity);
340 if (!newUArray)
341 goto out_error;
342
343 pool->uCapacity = (SSIZE_T)newUCapacity;
344 pool->uArray = newUArray;
345 }
346
347 pool->uArray[pool->uSize].buffer = buffer;
348 pool->uArray[pool->uSize].size = size;
349 (pool->uSize)++;
350 }
351
352 BufferPool_Unlock(pool);
353
354 return buffer;
355
356out_error:
357 if (pool->alignment)
358 winpr_aligned_free(buffer);
359 else
360 free(buffer);
361out_error_no_free:
362 BufferPool_Unlock(pool);
363 return NULL;
364}
365
370BOOL BufferPool_Return(wBufferPool* pool, void* buffer)
371{
372 BOOL rc = FALSE;
373 SSIZE_T size = 0;
374 BOOL found = FALSE;
375
376 BufferPool_Lock(pool);
377
378 if (pool->fixedSize)
379 {
380 /* fixed size buffers */
381
382 if ((pool->size + 1) >= pool->capacity)
383 {
384 SSIZE_T newCapacity = MAX(2, pool->size + (pool->size + 2) / 2 + 1);
385 void** newArray = (void**)realloc(
386 (void*)pool->array, sizeof(void*) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
387 if (!newArray)
388 goto out_error;
389
390 pool->capacity = newCapacity;
391 pool->array = newArray;
392 }
393
394 pool->array[(pool->size)++] = buffer;
395 }
396 else
397 {
398 /* variable size buffers */
399
400 SSIZE_T index = 0;
401 for (; index < pool->uSize; index++)
402 {
403 if (pool->uArray[index].buffer == buffer)
404 {
405 found = TRUE;
406 break;
407 }
408 }
409
410 if (found)
411 {
412 size = pool->uArray[index].size;
413 if (!BufferPool_ShiftUsed(pool, index, -1))
414 goto out_error;
415 }
416
417 if (size)
418 {
419 if ((pool->aSize + 1) >= pool->aCapacity)
420 {
421 SSIZE_T newCapacity = MAX(2, pool->aSize + (pool->aSize + 2) / 2 + 1);
422 wBufferPoolItem* newArray = (wBufferPoolItem*)realloc(
423 pool->aArray,
424 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
425 if (!newArray)
426 goto out_error;
427
428 pool->aCapacity = newCapacity;
429 pool->aArray = newArray;
430 }
431
432 pool->aArray[pool->aSize].buffer = buffer;
433 pool->aArray[pool->aSize].size = size;
434 (pool->aSize)++;
435 }
436 }
437
438 rc = TRUE;
439out_error:
440 BufferPool_Unlock(pool);
441 return rc;
442}
443
448void BufferPool_Clear(wBufferPool* pool)
449{
450 BufferPool_Lock(pool);
451
452 if (pool->fixedSize)
453 {
454 /* fixed size buffers */
455
456 while (pool->size > 0)
457 {
458 (pool->size)--;
459
460 if (pool->alignment)
461 winpr_aligned_free(pool->array[pool->size]);
462 else
463 free(pool->array[pool->size]);
464 }
465 }
466 else
467 {
468 /* variable size buffers */
469
470 while (pool->aSize > 0)
471 {
472 (pool->aSize)--;
473
474 if (pool->alignment)
475 winpr_aligned_free(pool->aArray[pool->aSize].buffer);
476 else
477 free(pool->aArray[pool->aSize].buffer);
478 }
479
480 while (pool->uSize > 0)
481 {
482 (pool->uSize)--;
483
484 if (pool->alignment)
485 winpr_aligned_free(pool->uArray[pool->uSize].buffer);
486 else
487 free(pool->uArray[pool->uSize].buffer);
488 }
489 }
490
491 BufferPool_Unlock(pool);
492}
493
498wBufferPool* BufferPool_New(BOOL synchronized, SSIZE_T fixedSize, DWORD alignment)
499{
500 wBufferPool* pool = NULL;
501
502 pool = (wBufferPool*)calloc(1, sizeof(wBufferPool));
503
504 if (pool)
505 {
506 pool->fixedSize = fixedSize;
507
508 if (pool->fixedSize < 0)
509 pool->fixedSize = 0;
510
511 pool->alignment = alignment;
512 pool->synchronized = synchronized;
513
514 if (pool->synchronized)
515 InitializeCriticalSectionAndSpinCount(&pool->lock, 4000);
516
517 if (pool->fixedSize)
518 {
519 /* fixed size buffers */
520
521 pool->size = 0;
522 pool->capacity = 32;
523 pool->array =
524 (void**)calloc(WINPR_ASSERTING_INT_CAST(size_t, pool->capacity), sizeof(void*));
525 if (!pool->array)
526 goto out_error;
527 }
528 else
529 {
530 /* variable size buffers */
531
532 pool->aSize = 0;
533 pool->aCapacity = 32;
534 pool->aArray = (wBufferPoolItem*)calloc(
535 WINPR_ASSERTING_INT_CAST(size_t, pool->aCapacity), sizeof(wBufferPoolItem));
536 if (!pool->aArray)
537 goto out_error;
538
539 pool->uSize = 0;
540 pool->uCapacity = 32;
541 pool->uArray = (wBufferPoolItem*)calloc(
542 WINPR_ASSERTING_INT_CAST(size_t, pool->uCapacity), sizeof(wBufferPoolItem));
543 if (!pool->uArray)
544 goto out_error;
545 }
546 }
547
548 return pool;
549
550out_error:
551 WINPR_PRAGMA_DIAG_PUSH
552 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
553 BufferPool_Free(pool);
554 WINPR_PRAGMA_DIAG_POP
555 return NULL;
556}
557
558void BufferPool_Free(wBufferPool* pool)
559{
560 if (pool)
561 {
562 BufferPool_Clear(pool);
563
564 if (pool->synchronized)
565 DeleteCriticalSection(&pool->lock);
566
567 if (pool->fixedSize)
568 {
569 /* fixed size buffers */
570
571 free((void*)pool->array);
572 }
573 else
574 {
575 /* variable size buffers */
576
577 free(pool->aArray);
578 free(pool->uArray);
579 }
580
581 free(pool);
582 }
583}