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