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 = nullptr;
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 const SSIZE_T required = pool->uSize + count;
131 // check for overflow
132 if ((required < count) || (required < pool->uSize))
133 return FALSE;
134
135 if (required > pool->uCapacity)
136 {
137 SSIZE_T newUCapacity = pool->uCapacity;
138 do
139 {
140 if (newUCapacity > SSIZE_MAX - 128ll)
141 return FALSE;
142 newUCapacity += 128ll;
143 } while (newUCapacity <= required);
144 wBufferPoolItem* newUArray = nullptr;
145 if (pool->alignment > 0)
146 newUArray = (wBufferPoolItem*)winpr_aligned_realloc(
147 pool->uArray,
148 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newUCapacity),
149 pool->alignment);
150 else
151 newUArray = (wBufferPoolItem*)realloc(
152 pool->uArray,
153 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newUCapacity));
154 if (!newUArray)
155 return FALSE;
156 pool->uCapacity = newUCapacity;
157 pool->uArray = newUArray;
158 }
159
160 MoveMemory(&pool->uArray[index + count], &pool->uArray[index],
161 WINPR_ASSERTING_INT_CAST(size_t, pool->uSize - index) * sizeof(wBufferPoolItem));
162 pool->uSize += count;
163 }
164 else if (count < 0)
165 {
166 MoveMemory(&pool->uArray[index], &pool->uArray[index - count],
167 WINPR_ASSERTING_INT_CAST(size_t, pool->uSize - index) * sizeof(wBufferPoolItem));
168 pool->uSize += count;
169 }
170 return TRUE;
171}
172
177SSIZE_T BufferPool_GetPoolSize(wBufferPool* pool)
178{
179 SSIZE_T size = 0;
180
181 BufferPool_Lock(pool);
182
183 if (pool->fixedSize)
184 {
185 /* fixed size buffers */
186 size = pool->size;
187 }
188 else
189 {
190 /* variable size buffers */
191 size = pool->uSize;
192 }
193
194 BufferPool_Unlock(pool);
195
196 return size;
197}
198
203SSIZE_T BufferPool_GetBufferSize(wBufferPool* pool, const void* buffer)
204{
205 SSIZE_T size = 0;
206 BOOL found = FALSE;
207
208 BufferPool_Lock(pool);
209
210 if (pool->fixedSize)
211 {
212 /* fixed size buffers */
213 size = pool->fixedSize;
214 found = TRUE;
215 }
216 else
217 {
218 /* variable size buffers */
219
220 for (SSIZE_T index = 0; index < pool->uSize; index++)
221 {
222 if (pool->uArray[index].buffer == buffer)
223 {
224 size = pool->uArray[index].size;
225 found = TRUE;
226 break;
227 }
228 }
229 }
230
231 BufferPool_Unlock(pool);
232
233 return (found) ? size : -1;
234}
235
240void* BufferPool_Take(wBufferPool* pool, SSIZE_T size)
241{
242 SSIZE_T maxSize = 0;
243 SSIZE_T maxIndex = 0;
244 SSIZE_T foundIndex = -1;
245 BOOL found = FALSE;
246 void* buffer = nullptr;
247
248 BufferPool_Lock(pool);
249
250 if (pool->fixedSize)
251 {
252 /* fixed size buffers */
253
254 if (pool->size > 0)
255 buffer = pool->array[--(pool->size)];
256
257 if (!buffer)
258 {
259 if (pool->alignment)
260 buffer = winpr_aligned_malloc(WINPR_ASSERTING_INT_CAST(size_t, pool->fixedSize),
261 pool->alignment);
262 else
263 buffer = malloc(WINPR_ASSERTING_INT_CAST(size_t, pool->fixedSize));
264 }
265
266 if (!buffer)
267 goto out_error;
268 }
269 else
270 {
271 /* variable size buffers */
272
273 maxSize = 0;
274 maxIndex = 0;
275
276 if (size < 1)
277 size = pool->fixedSize;
278
279 for (SSIZE_T index = 0; index < pool->aSize; index++)
280 {
281 if (pool->aArray[index].size > maxSize)
282 {
283 maxIndex = index;
284 maxSize = pool->aArray[index].size;
285 }
286
287 if (pool->aArray[index].size >= size)
288 {
289 foundIndex = index;
290 found = TRUE;
291 break;
292 }
293 }
294
295 if (!found && maxSize)
296 {
297 foundIndex = maxIndex;
298 found = TRUE;
299 }
300
301 if (!found)
302 {
303 if (!size)
304 buffer = nullptr;
305 else
306 {
307 if (pool->alignment)
308 buffer = winpr_aligned_malloc(WINPR_ASSERTING_INT_CAST(size_t, size),
309 pool->alignment);
310 else
311 buffer = malloc(WINPR_ASSERTING_INT_CAST(size_t, size));
312
313 if (!buffer)
314 goto out_error;
315 }
316 }
317 else
318 {
319 buffer = pool->aArray[foundIndex].buffer;
320
321 if (maxSize < size)
322 {
323 void* newBuffer = nullptr;
324 if (pool->alignment)
325 newBuffer = winpr_aligned_realloc(
326 buffer, WINPR_ASSERTING_INT_CAST(size_t, size), pool->alignment);
327 else
328 newBuffer = realloc(buffer, WINPR_ASSERTING_INT_CAST(size_t, size));
329
330 if (!newBuffer)
331 goto out_error_no_free;
332
333 buffer = newBuffer;
334 }
335
336 if (!BufferPool_ShiftAvailable(pool, WINPR_ASSERTING_INT_CAST(size_t, foundIndex), -1))
337 goto out_error;
338 }
339
340 if (!buffer)
341 goto out_error;
342
343 if (pool->uSize + 1 > pool->uCapacity)
344 {
345 size_t newUCapacity = WINPR_ASSERTING_INT_CAST(size_t, pool->uCapacity);
346 newUCapacity += (newUCapacity + 2) / 2;
347 if (newUCapacity > SSIZE_MAX)
348 goto out_error;
349 wBufferPoolItem* newUArray =
350 (wBufferPoolItem*)realloc(pool->uArray, sizeof(wBufferPoolItem) * newUCapacity);
351 if (!newUArray)
352 goto out_error;
353
354 pool->uCapacity = (SSIZE_T)newUCapacity;
355 pool->uArray = newUArray;
356 }
357
358 pool->uArray[pool->uSize].buffer = buffer;
359 pool->uArray[pool->uSize].size = size;
360 (pool->uSize)++;
361 }
362
363 BufferPool_Unlock(pool);
364
365 return buffer;
366
367out_error:
368 if (pool->alignment)
369 winpr_aligned_free(buffer);
370 else
371 free(buffer);
372out_error_no_free:
373 BufferPool_Unlock(pool);
374 return nullptr;
375}
376
381BOOL BufferPool_Return(wBufferPool* pool, void* buffer)
382{
383 BOOL rc = FALSE;
384 SSIZE_T size = 0;
385 BOOL found = FALSE;
386
387 BufferPool_Lock(pool);
388
389 if (pool->fixedSize)
390 {
391 /* fixed size buffers */
392
393 if ((pool->size + 1) >= pool->capacity)
394 {
395 SSIZE_T newCapacity = MAX(2, pool->size + (pool->size + 2) / 2 + 1);
396 void** newArray = (void**)realloc(
397 (void*)pool->array, sizeof(void*) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
398 if (!newArray)
399 goto out_error;
400
401 pool->capacity = newCapacity;
402 pool->array = newArray;
403 }
404
405 pool->array[(pool->size)++] = buffer;
406 }
407 else
408 {
409 /* variable size buffers */
410
411 SSIZE_T index = 0;
412 for (; index < pool->uSize; index++)
413 {
414 if (pool->uArray[index].buffer == buffer)
415 {
416 found = TRUE;
417 break;
418 }
419 }
420
421 if (found)
422 {
423 size = pool->uArray[index].size;
424 if (!BufferPool_ShiftUsed(pool, index, -1))
425 goto out_error;
426 }
427
428 if (size)
429 {
430 if ((pool->aSize + 1) >= pool->aCapacity)
431 {
432 SSIZE_T newCapacity = MAX(2, pool->aSize + (pool->aSize + 2) / 2 + 1);
433 wBufferPoolItem* newArray = (wBufferPoolItem*)realloc(
434 pool->aArray,
435 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
436 if (!newArray)
437 goto out_error;
438
439 pool->aCapacity = newCapacity;
440 pool->aArray = newArray;
441 }
442
443 pool->aArray[pool->aSize].buffer = buffer;
444 pool->aArray[pool->aSize].size = size;
445 (pool->aSize)++;
446 }
447 }
448
449 rc = TRUE;
450out_error:
451 BufferPool_Unlock(pool);
452 return rc;
453}
454
459void BufferPool_Clear(wBufferPool* pool)
460{
461 BufferPool_Lock(pool);
462
463 if (pool->fixedSize)
464 {
465 /* fixed size buffers */
466
467 while (pool->size > 0)
468 {
469 (pool->size)--;
470
471 if (pool->alignment)
472 winpr_aligned_free(pool->array[pool->size]);
473 else
474 free(pool->array[pool->size]);
475 }
476 }
477 else
478 {
479 /* variable size buffers */
480
481 while (pool->aSize > 0)
482 {
483 (pool->aSize)--;
484
485 if (pool->alignment)
486 winpr_aligned_free(pool->aArray[pool->aSize].buffer);
487 else
488 free(pool->aArray[pool->aSize].buffer);
489 }
490
491 while (pool->uSize > 0)
492 {
493 (pool->uSize)--;
494
495 if (pool->alignment)
496 winpr_aligned_free(pool->uArray[pool->uSize].buffer);
497 else
498 free(pool->uArray[pool->uSize].buffer);
499 }
500 }
501
502 BufferPool_Unlock(pool);
503}
504
509wBufferPool* BufferPool_New(BOOL synchronized, SSIZE_T fixedSize, DWORD alignment)
510{
511 wBufferPool* pool = nullptr;
512
513 pool = (wBufferPool*)calloc(1, sizeof(wBufferPool));
514
515 if (pool)
516 {
517 pool->fixedSize = fixedSize;
518
519 if (pool->fixedSize < 0)
520 pool->fixedSize = 0;
521
522 pool->alignment = alignment;
523 pool->synchronized = synchronized;
524
525 if (pool->synchronized)
526 {
527 if (!InitializeCriticalSectionAndSpinCount(&pool->lock, 4000))
528 goto out_error;
529 }
530
531 if (pool->fixedSize)
532 {
533 /* fixed size buffers */
534
535 pool->size = 0;
536 pool->capacity = 32;
537 pool->array =
538 (void**)calloc(WINPR_ASSERTING_INT_CAST(size_t, pool->capacity), sizeof(void*));
539 if (!pool->array)
540 goto out_error;
541 }
542 else
543 {
544 /* variable size buffers */
545
546 pool->aSize = 0;
547 pool->aCapacity = 32;
548 pool->aArray = (wBufferPoolItem*)calloc(
549 WINPR_ASSERTING_INT_CAST(size_t, pool->aCapacity), sizeof(wBufferPoolItem));
550 if (!pool->aArray)
551 goto out_error;
552
553 pool->uSize = 0;
554 pool->uCapacity = 32;
555 pool->uArray = (wBufferPoolItem*)calloc(
556 WINPR_ASSERTING_INT_CAST(size_t, pool->uCapacity), sizeof(wBufferPoolItem));
557 if (!pool->uArray)
558 goto out_error;
559 }
560 }
561
562 return pool;
563
564out_error:
565 WINPR_PRAGMA_DIAG_PUSH
566 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
567 BufferPool_Free(pool);
568 WINPR_PRAGMA_DIAG_POP
569 return nullptr;
570}
571
572void BufferPool_Free(wBufferPool* pool)
573{
574 if (pool)
575 {
576 BufferPool_Clear(pool);
577
578 if (pool->synchronized)
579 DeleteCriticalSection(&pool->lock);
580
581 if (pool->fixedSize)
582 {
583 /* fixed size buffers */
584
585 free((void*)pool->array);
586 }
587 else
588 {
589 /* variable size buffers */
590
591 free(pool->aArray);
592 free(pool->uArray);
593 }
594
595 free(pool);
596 }
597}