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 newArray = (wBufferPoolItem*)winpr_aligned_recalloc(
96 pool->aArray, sizeof(wBufferPoolItem),
97 WINPR_ASSERTING_INT_CAST(size_t, newCapacity), pool->alignment);
98 if (!newArray)
99 return FALSE;
100 pool->aArray = newArray;
101 pool->aCapacity = newCapacity;
102 }
103
104 MoveMemory(
105 &pool->aArray[index + WINPR_ASSERTING_INT_CAST(size_t, count)], &pool->aArray[index],
106 (WINPR_ASSERTING_INT_CAST(size_t, pool->aSize) - index) * sizeof(wBufferPoolItem));
107 pool->aSize += count;
108 }
109 else if (count < 0)
110 {
111 MoveMemory(
112 &pool->aArray[index], &pool->aArray[index + WINPR_ASSERTING_INT_CAST(size_t, -count)],
113 (WINPR_ASSERTING_INT_CAST(size_t, pool->aSize) - index) * sizeof(wBufferPoolItem));
114 pool->aSize += count;
115 }
116 return TRUE;
117}
118
119static BOOL BufferPool_ShiftUsed(wBufferPool* pool, SSIZE_T index, SSIZE_T count)
120{
121 if (count > 0)
122 {
123 const SSIZE_T required = pool->uSize + count;
124 // check for overflow
125 if ((required < count) || (required < pool->uSize))
126 return FALSE;
127
128 if (required > pool->uCapacity)
129 {
130 SSIZE_T newUCapacity = pool->uCapacity;
131 do
132 {
133 if (newUCapacity > SSIZE_MAX - 128ll)
134 return FALSE;
135 newUCapacity += 128ll;
136 } while (newUCapacity <= required);
137 wBufferPoolItem* newUArray = nullptr;
138 newUArray = (wBufferPoolItem*)winpr_aligned_realloc(
139 pool->uArray,
140 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newUCapacity),
141 pool->alignment);
142
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 = nullptr;
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 buffer = winpr_aligned_calloc(WINPR_ASSERTING_INT_CAST(size_t, pool->fixedSize), 1,
249 pool->alignment);
250 }
251
252 if (!buffer)
253 goto out_error;
254 }
255 else
256 {
257 /* variable size buffers */
258
259 maxSize = 0;
260 maxIndex = 0;
261
262 if (size < 1)
263 size = pool->fixedSize;
264
265 for (SSIZE_T index = 0; index < pool->aSize; index++)
266 {
267 if (pool->aArray[index].size > maxSize)
268 {
269 maxIndex = index;
270 maxSize = pool->aArray[index].size;
271 }
272
273 if (pool->aArray[index].size >= size)
274 {
275 foundIndex = index;
276 found = TRUE;
277 break;
278 }
279 }
280
281 if (!found && maxSize)
282 {
283 foundIndex = maxIndex;
284 found = TRUE;
285 }
286
287 if (!found)
288 {
289 if (!size)
290 buffer = nullptr;
291 else
292 {
293 buffer = winpr_aligned_calloc(WINPR_ASSERTING_INT_CAST(size_t, size), 1,
294 pool->alignment);
295
296 if (!buffer)
297 goto out_error;
298 }
299 }
300 else
301 {
302 buffer = pool->aArray[foundIndex].buffer;
303
304 if (maxSize < size)
305 {
306 void* newBuffer = nullptr;
307 newBuffer = winpr_aligned_realloc(buffer, WINPR_ASSERTING_INT_CAST(size_t, size),
308 pool->alignment);
309
310 if (!newBuffer)
311 goto out_error_no_free;
312
313 buffer = newBuffer;
314 }
315
316 if (!BufferPool_ShiftAvailable(pool, WINPR_ASSERTING_INT_CAST(size_t, foundIndex), -1))
317 goto out_error;
318 }
319
320 if (!buffer)
321 goto out_error;
322
323 if (pool->uSize + 1 > pool->uCapacity)
324 {
325 size_t newUCapacity = WINPR_ASSERTING_INT_CAST(size_t, pool->uCapacity);
326 newUCapacity += (newUCapacity + 2) / 2;
327 if (newUCapacity > SSIZE_MAX)
328 goto out_error;
329 wBufferPoolItem* newUArray =
330 (wBufferPoolItem*)realloc(pool->uArray, sizeof(wBufferPoolItem) * newUCapacity);
331 if (!newUArray)
332 goto out_error;
333
334 pool->uCapacity = (SSIZE_T)newUCapacity;
335 pool->uArray = newUArray;
336 }
337
338 pool->uArray[pool->uSize].buffer = buffer;
339 pool->uArray[pool->uSize].size = size;
340 (pool->uSize)++;
341 }
342
343 BufferPool_Unlock(pool);
344
345 return buffer;
346
347out_error:
348 winpr_aligned_free(buffer);
349out_error_no_free:
350 BufferPool_Unlock(pool);
351 return nullptr;
352}
353
358BOOL BufferPool_Return(wBufferPool* pool, void* buffer)
359{
360 BOOL rc = FALSE;
361 SSIZE_T size = 0;
362 BOOL found = FALSE;
363
364 BufferPool_Lock(pool);
365
366 if (pool->fixedSize)
367 {
368 /* fixed size buffers */
369
370 if ((pool->size + 1) >= pool->capacity)
371 {
372 SSIZE_T newCapacity = MAX(2, pool->size + (pool->size + 2) / 2 + 1);
373 void** newArray = (void**)realloc(
374 (void*)pool->array, sizeof(void*) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
375 if (!newArray)
376 goto out_error;
377
378 pool->capacity = newCapacity;
379 pool->array = newArray;
380 }
381
382 pool->array[(pool->size)++] = buffer;
383 }
384 else
385 {
386 /* variable size buffers */
387
388 SSIZE_T index = 0;
389 for (; index < pool->uSize; index++)
390 {
391 if (pool->uArray[index].buffer == buffer)
392 {
393 found = TRUE;
394 break;
395 }
396 }
397
398 if (found)
399 {
400 size = pool->uArray[index].size;
401 if (!BufferPool_ShiftUsed(pool, index, -1))
402 goto out_error;
403 }
404
405 if (size)
406 {
407 if ((pool->aSize + 1) >= pool->aCapacity)
408 {
409 SSIZE_T newCapacity = MAX(2, pool->aSize + (pool->aSize + 2) / 2 + 1);
410 wBufferPoolItem* newArray = (wBufferPoolItem*)realloc(
411 pool->aArray,
412 sizeof(wBufferPoolItem) * WINPR_ASSERTING_INT_CAST(size_t, newCapacity));
413 if (!newArray)
414 goto out_error;
415
416 pool->aCapacity = newCapacity;
417 pool->aArray = newArray;
418 }
419
420 pool->aArray[pool->aSize].buffer = buffer;
421 pool->aArray[pool->aSize].size = size;
422 (pool->aSize)++;
423 }
424 }
425
426 rc = TRUE;
427out_error:
428 BufferPool_Unlock(pool);
429 return rc;
430}
431
436void BufferPool_Clear(wBufferPool* pool)
437{
438 BufferPool_Lock(pool);
439
440 if (pool->fixedSize)
441 {
442 /* fixed size buffers */
443
444 while (pool->size > 0)
445 {
446 (pool->size)--;
447
448 winpr_aligned_free(pool->array[pool->size]);
449 }
450 }
451 else
452 {
453 /* variable size buffers */
454
455 while (pool->aSize > 0)
456 {
457 (pool->aSize)--;
458
459 winpr_aligned_free(pool->aArray[pool->aSize].buffer);
460 }
461
462 while (pool->uSize > 0)
463 {
464 (pool->uSize)--;
465
466 winpr_aligned_free(pool->uArray[pool->uSize].buffer);
467 }
468 }
469
470 BufferPool_Unlock(pool);
471}
472
477wBufferPool* BufferPool_New(BOOL synchronized, SSIZE_T fixedSize, DWORD alignment)
478{
479 wBufferPool* pool = nullptr;
480
481 pool = (wBufferPool*)calloc(1, sizeof(wBufferPool));
482
483 if (pool)
484 {
485 pool->fixedSize = fixedSize;
486
487 if (pool->fixedSize < 0)
488 pool->fixedSize = 0;
489
490 pool->alignment = alignment;
491 pool->synchronized = synchronized;
492
493 if (pool->synchronized)
494 {
495 if (!InitializeCriticalSectionAndSpinCount(&pool->lock, 4000))
496 goto out_error;
497 }
498
499 if (pool->fixedSize)
500 {
501 /* fixed size buffers */
502
503 pool->size = 0;
504 pool->capacity = 32;
505 pool->array =
506 (void**)calloc(WINPR_ASSERTING_INT_CAST(size_t, pool->capacity), sizeof(void*));
507 if (!pool->array)
508 goto out_error;
509 }
510 else
511 {
512 /* variable size buffers */
513
514 pool->aSize = 0;
515 pool->aCapacity = 32;
516 pool->aArray = (wBufferPoolItem*)calloc(
517 WINPR_ASSERTING_INT_CAST(size_t, pool->aCapacity), sizeof(wBufferPoolItem));
518 if (!pool->aArray)
519 goto out_error;
520
521 pool->uSize = 0;
522 pool->uCapacity = 32;
523 pool->uArray = (wBufferPoolItem*)calloc(
524 WINPR_ASSERTING_INT_CAST(size_t, pool->uCapacity), sizeof(wBufferPoolItem));
525 if (!pool->uArray)
526 goto out_error;
527 }
528 }
529
530 return pool;
531
532out_error:
533 WINPR_PRAGMA_DIAG_PUSH
534 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
535 BufferPool_Free(pool);
536 WINPR_PRAGMA_DIAG_POP
537 return nullptr;
538}
539
540void BufferPool_Free(wBufferPool* pool)
541{
542 if (pool)
543 {
544 BufferPool_Clear(pool);
545
546 if (pool->synchronized)
547 DeleteCriticalSection(&pool->lock);
548
549 if (pool->fixedSize)
550 {
551 /* fixed size buffers */
552
553 free((void*)pool->array);
554 }
555 else
556 {
557 /* variable size buffers */
558
559 free(pool->aArray);
560 free(pool->uArray);
561 }
562
563 free(pool);
564 }
565}