FreeRDP
StreamPool.c
1 
20 #include <winpr/config.h>
21 
22 #include <winpr/crt.h>
23 #include <winpr/wlog.h>
24 
25 #include <winpr/collections.h>
26 
27 #include "../stream.h"
28 
29 struct s_wStreamPool
30 {
31  size_t aSize;
32  size_t aCapacity;
33  wStream** aArray;
34 
35  size_t uSize;
36  size_t uCapacity;
37  wStream** uArray;
38 
39  CRITICAL_SECTION lock;
40  BOOL synchronized;
41  size_t defaultSize;
42 };
43 
48 static INLINE void StreamPool_Lock(wStreamPool* pool)
49 {
50  WINPR_ASSERT(pool);
51  if (pool->synchronized)
52  EnterCriticalSection(&pool->lock);
53 }
54 
59 static INLINE void StreamPool_Unlock(wStreamPool* pool)
60 {
61  WINPR_ASSERT(pool);
62  if (pool->synchronized)
63  LeaveCriticalSection(&pool->lock);
64 }
65 
66 static BOOL StreamPool_EnsureCapacity(wStreamPool* pool, size_t count, BOOL usedOrAvailable)
67 {
68  size_t new_cap = 0;
69  size_t* cap = NULL;
70  size_t* size = NULL;
71  wStream*** array = NULL;
72 
73  WINPR_ASSERT(pool);
74 
75  cap = (usedOrAvailable) ? &pool->uCapacity : &pool->aCapacity;
76  size = (usedOrAvailable) ? &pool->uSize : &pool->aSize;
77  array = (usedOrAvailable) ? &pool->uArray : &pool->aArray;
78  if (*cap == 0)
79  new_cap = *size + count;
80  else if (*size + count > *cap)
81  new_cap = *cap * 2;
82  else if ((*size + count) < *cap / 3)
83  new_cap = *cap / 2;
84 
85  if (new_cap > 0)
86  {
87  wStream** new_arr = NULL;
88 
89  if (*cap < *size + count)
90  *cap += count;
91 
92  new_arr = (wStream**)realloc(*array, sizeof(wStream*) * new_cap);
93  if (!new_arr)
94  return FALSE;
95  *cap = new_cap;
96  *array = new_arr;
97  }
98  return TRUE;
99 }
100 
105 static void StreamPool_ShiftUsed(wStreamPool* pool, size_t index, INT64 count)
106 {
107  WINPR_ASSERT(pool);
108  if (count > 0)
109  {
110  const size_t pcount = (size_t)count;
111  StreamPool_EnsureCapacity(pool, pcount, TRUE);
112 
113  MoveMemory(&pool->uArray[index + pcount], &pool->uArray[index],
114  (pool->uSize - index) * sizeof(wStream*));
115  pool->uSize += pcount;
116  }
117  else if (count < 0)
118  {
119  const size_t pcount = (size_t)-count;
120  const size_t off = index + pcount;
121  if (pool->uSize > off)
122  {
123  MoveMemory(&pool->uArray[index], &pool->uArray[index + pcount],
124  (pool->uSize - index - pcount) * sizeof(wStream*));
125  }
126 
127  pool->uSize -= pcount;
128  }
129 }
130 
135 static void StreamPool_AddUsed(wStreamPool* pool, wStream* s)
136 {
137  StreamPool_EnsureCapacity(pool, 1, TRUE);
138  pool->uArray[(pool->uSize)++] = s;
139 }
140 
145 static void StreamPool_RemoveUsed(wStreamPool* pool, wStream* s)
146 {
147  WINPR_ASSERT(pool);
148  for (size_t index = 0; index < pool->uSize; index++)
149  {
150  if (pool->uArray[index] == s)
151  {
152  StreamPool_ShiftUsed(pool, index, -1);
153  break;
154  }
155  }
156 }
157 
158 static void StreamPool_ShiftAvailable(wStreamPool* pool, size_t index, INT64 count)
159 {
160  WINPR_ASSERT(pool);
161  if (count > 0)
162  {
163  const size_t pcount = (size_t)count;
164 
165  StreamPool_EnsureCapacity(pool, pcount, FALSE);
166  MoveMemory(&pool->aArray[index + pcount], &pool->aArray[index],
167  (pool->aSize - index) * sizeof(wStream*));
168  pool->aSize += pcount;
169  }
170  else if (count < 0)
171  {
172  const size_t pcount = (size_t)-count;
173  const size_t off = index + pcount;
174  if (pool->aSize > off)
175  {
176  MoveMemory(&pool->aArray[index], &pool->aArray[index + pcount],
177  (pool->aSize - index - pcount) * sizeof(wStream*));
178  }
179 
180  pool->aSize -= pcount;
181  }
182 }
183 
188 wStream* StreamPool_Take(wStreamPool* pool, size_t size)
189 {
190  BOOL found = FALSE;
191  size_t foundIndex = 0;
192  wStream* s = NULL;
193 
194  StreamPool_Lock(pool);
195 
196  if (size == 0)
197  size = pool->defaultSize;
198 
199  for (size_t index = 0; index < pool->aSize; index++)
200  {
201  s = pool->aArray[index];
202 
203  if (Stream_Capacity(s) >= size)
204  {
205  found = TRUE;
206  foundIndex = index;
207  break;
208  }
209  }
210 
211  if (!found)
212  {
213  s = Stream_New(NULL, size);
214  if (!s)
215  goto out_fail;
216  }
217  else if (s)
218  {
219  Stream_SetPosition(s, 0);
220  Stream_SetLength(s, Stream_Capacity(s));
221  StreamPool_ShiftAvailable(pool, foundIndex, -1);
222  }
223 
224  if (s)
225  {
226  s->pool = pool;
227  s->count = 1;
228  StreamPool_AddUsed(pool, s);
229  }
230 
231 out_fail:
232  StreamPool_Unlock(pool);
233 
234  return s;
235 }
236 
241 static void StreamPool_Remove(wStreamPool* pool, wStream* s)
242 {
243  StreamPool_EnsureCapacity(pool, 1, FALSE);
244  Stream_EnsureValidity(s);
245  for (size_t x = 0; x < pool->aSize; x++)
246  {
247  wStream* cs = pool->aArray[x];
248  if (cs == s)
249  return;
250  }
251  pool->aArray[(pool->aSize)++] = s;
252  StreamPool_RemoveUsed(pool, s);
253 }
254 
255 static void StreamPool_ReleaseOrReturn(wStreamPool* pool, wStream* s)
256 {
257  StreamPool_Lock(pool);
258  if (s->count > 0)
259  s->count--;
260  if (s->count == 0)
261  StreamPool_Remove(pool, s);
262  StreamPool_Unlock(pool);
263 }
264 
265 void StreamPool_Return(wStreamPool* pool, wStream* s)
266 {
267  WINPR_ASSERT(pool);
268  if (!s)
269  return;
270 
271  StreamPool_Lock(pool);
272  StreamPool_Remove(pool, s);
273  StreamPool_Unlock(pool);
274 }
275 
280 void Stream_AddRef(wStream* s)
281 {
282  WINPR_ASSERT(s);
283  if (s->pool)
284  {
285  StreamPool_Lock(s->pool);
286  s->count++;
287  StreamPool_Unlock(s->pool);
288  }
289 }
290 
295 void Stream_Release(wStream* s)
296 {
297  WINPR_ASSERT(s);
298  if (s->pool)
299  StreamPool_ReleaseOrReturn(s->pool, s);
300 }
301 
306 wStream* StreamPool_Find(wStreamPool* pool, const BYTE* ptr)
307 {
308  wStream* s = NULL;
309 
310  StreamPool_Lock(pool);
311 
312  for (size_t index = 0; index < pool->uSize; index++)
313  {
314  wStream* cur = pool->uArray[index];
315 
316  if ((ptr >= Stream_Buffer(cur)) && (ptr < (Stream_Buffer(cur) + Stream_Capacity(cur))))
317  {
318  s = cur;
319  break;
320  }
321  }
322 
323  StreamPool_Unlock(pool);
324 
325  return s;
326 }
327 
332 void StreamPool_Clear(wStreamPool* pool)
333 {
334  StreamPool_Lock(pool);
335 
336  while (pool->aSize > 0)
337  {
338  wStream* s = pool->aArray[--pool->aSize];
339  Stream_Free(s, s->isAllocatedStream);
340  }
341 
342  while (pool->uSize > 0)
343  {
344  wStream* s = pool->uArray[--pool->uSize];
345  Stream_Free(s, s->isAllocatedStream);
346  }
347 
348  StreamPool_Unlock(pool);
349 }
350 
355 wStreamPool* StreamPool_New(BOOL synchronized, size_t defaultSize)
356 {
357  wStreamPool* pool = NULL;
358 
359  pool = (wStreamPool*)calloc(1, sizeof(wStreamPool));
360 
361  if (pool)
362  {
363  pool->synchronized = synchronized;
364  pool->defaultSize = defaultSize;
365 
366  if (!StreamPool_EnsureCapacity(pool, 32, FALSE))
367  goto fail;
368  if (!StreamPool_EnsureCapacity(pool, 32, TRUE))
369  goto fail;
370 
371  InitializeCriticalSectionAndSpinCount(&pool->lock, 4000);
372  }
373 
374  return pool;
375 fail:
376  WINPR_PRAGMA_DIAG_PUSH
377  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
378  StreamPool_Free(pool);
379  WINPR_PRAGMA_DIAG_POP
380  return NULL;
381 }
382 
383 void StreamPool_Free(wStreamPool* pool)
384 {
385  if (pool)
386  {
387  StreamPool_Clear(pool);
388 
389  DeleteCriticalSection(&pool->lock);
390 
391  free(pool->aArray);
392  free(pool->uArray);
393 
394  free(pool);
395  }
396 }
397 
398 char* StreamPool_GetStatistics(wStreamPool* pool, char* buffer, size_t size)
399 {
400  WINPR_ASSERT(pool);
401 
402  if (!buffer || (size < 1))
403  return NULL;
404  (void)_snprintf(buffer, size - 1,
405  "aSize =%" PRIuz ", uSize =%" PRIuz "aCapacity=%" PRIuz
406  ", uCapacity=%" PRIuz,
407  pool->aSize, pool->uSize, pool->aCapacity, pool->uCapacity);
408  buffer[size - 1] = '\0';
409  return buffer;
410 }