FreeRDP
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 
28 typedef struct
29 {
30  SSIZE_T size;
31  void* buffer;
32 } wBufferPoolItem;
33 
34 struct s_wBufferPool
35 {
36  SSIZE_T fixedSize;
37  DWORD alignment;
38  BOOL synchronized;
39  CRITICAL_SECTION lock;
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 
54 static 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 
64 static 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 
83 static 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 
124 static 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 
164 SSIZE_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 
190 SSIZE_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 
227 void* 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 
354 out_error:
355  if (pool->alignment)
356  winpr_aligned_free(buffer);
357  else
358  free(buffer);
359 out_error_no_free:
360  BufferPool_Unlock(pool);
361  return NULL;
362 }
363 
368 BOOL 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(1, 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(1, 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;
437 out_error:
438  BufferPool_Unlock(pool);
439  return rc;
440 }
441 
446 void 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 
496 wBufferPool* 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 
548 out_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 
556 void 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 }