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