suricata
util-pool.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2010 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \defgroup utilpool Pool
20  *
21  * ::Pool are an effective way to maintain a set of ready to use
22  * structures.
23  *
24  * To create a ::Pool, you need to use PoolInit(). You can
25  * get an item from the ::Pool by using PoolGet(). When you're
26  * done with it call PoolReturn().
27  * To destroy the ::Pool, call PoolFree(), it will free all used
28  * memory.
29  *
30  * @{
31  */
32 
33 /**
34  * \file
35  *
36  * \author Victor Julien <victor@inliniac.net>
37  *
38  * Pool utility functions
39  */
40 
41 #include "suricata-common.h"
42 #include "util-pool.h"
43 #include "util-pool-thread.h"
44 #include "util-unittest.h"
45 #include "util-debug.h"
46 
47 static int PoolMemset(void *pitem, void *initdata)
48 {
49  Pool *p = (Pool *) initdata;
50 
51  memset(pitem, 0, p->elt_size);
52  return 1;
53 }
54 
55 /**
56  * \brief Check if data is preallocated
57  * \retval 0 if not inside the prealloc'd block, 1 if inside */
58 static int PoolDataPreAllocated(Pool *p, void *data)
59 {
60  ptrdiff_t delta = data - p->data_buffer;
61  if ((delta < 0) || (delta > p->data_buffer_size)) {
62  return 0;
63  }
64  return 1;
65 }
66 
67 /** \brief Init a Pool
68  *
69  * PoolInit() creates a ::Pool. The Alloc function must only do
70  * allocation stuff. The Cleanup function must not try to free
71  * the PoolBucket::data. This is done by the ::Pool management
72  * system.
73  *
74  * \param size
75  * \param prealloc_size
76  * \param elt_size Memory size of an element
77  * \param Alloc An allocation function or NULL to use a standard SCMalloc
78  * \param Init An init function or NULL to use a standard memset to 0
79  * \param InitData Init data
80  * \param Cleanup a free function or NULL if no special treatment is needed
81  * \param Free free func
82  * \retval the allocated Pool
83  */
84 Pool *PoolInit(uint32_t size, uint32_t prealloc_size, uint32_t elt_size,
85  void *(*Alloc)(void), int (*Init)(void *, void *), void *InitData,
86  void (*Cleanup)(void *), void (*Free)(void *))
87 {
88  Pool *p = NULL;
89 
90  if (size != 0 && prealloc_size > size) {
91  SCLogError(SC_ERR_POOL_INIT, "size error");
92  goto error;
93  }
94  if (size != 0 && elt_size == 0) {
95  SCLogError(SC_ERR_POOL_INIT, "size != 0 && elt_size == 0");
96  goto error;
97  }
98  if (elt_size && Free) {
99  SCLogError(SC_ERR_POOL_INIT, "elt_size && Free");
100  goto error;
101  }
102 
103  /* setup the filter */
104  p = SCMalloc(sizeof(Pool));
105  if (unlikely(p == NULL)) {
106  SCLogError(SC_ERR_POOL_INIT, "alloc error");
107  goto error;
108  }
109 
110  memset(p,0,sizeof(Pool));
111 
112  p->max_buckets = size;
113  p->preallocated = prealloc_size;
114  p->elt_size = elt_size;
115  p->data_buffer_size = prealloc_size * elt_size;
116  p->Alloc = Alloc;
117  p->Init = Init;
118  p->InitData = InitData;
119  p->Cleanup = Cleanup;
120  p->Free = Free;
121  if (p->Init == NULL) {
122  p->Init = PoolMemset;
123  p->InitData = p;
124  }
125 
126  /* alloc the buckets and place them in the empty list */
127  uint32_t u32 = 0;
128  if (size > 0) {
129  PoolBucket *pb = SCCalloc(size, sizeof(PoolBucket));
130  if (unlikely(pb == NULL)) {
131  SCLogError(SC_ERR_POOL_INIT, "alloc error");
132  goto error;
133  }
134  memset(pb, 0, size * sizeof(PoolBucket));
135  p->pb_buffer = pb;
136  for (u32 = 0; u32 < size; u32++) {
137  /* populate pool */
138  pb->next = p->empty_stack;
140  p->empty_stack = pb;
141  p->empty_stack_size++;
142  pb++;
143  }
144 
145  p->data_buffer = SCCalloc(prealloc_size, elt_size);
146  /* FIXME better goto */
147  if (p->data_buffer == NULL) {
148  SCLogError(SC_ERR_POOL_INIT, "alloc error");
149  goto error;
150  }
151  }
152  /* prealloc the buckets and requeue them to the alloc list */
153  for (u32 = 0; u32 < prealloc_size; u32++) {
154  if (size == 0) { /* unlimited */
155  PoolBucket *pb = SCMalloc(sizeof(PoolBucket));
156  if (unlikely(pb == NULL)) {
157  SCLogError(SC_ERR_POOL_INIT, "alloc error");
158  goto error;
159  }
160  memset(pb, 0, sizeof(PoolBucket));
161 
162  if (p->Alloc) {
163  pb->data = p->Alloc();
164  } else {
165  pb->data = SCMalloc(p->elt_size);
166  }
167  if (pb->data == NULL) {
168  SCLogError(SC_ERR_POOL_INIT, "alloc error");
169  SCFree(pb);
170  goto error;
171  }
172  if (p->Init(pb->data, p->InitData) != 1) {
173  SCLogError(SC_ERR_POOL_INIT, "init error");
174  if (p->Cleanup)
175  p->Cleanup(pb->data);
176  if (p->Free)
177  p->Free(pb->data);
178  else
179  SCFree(pb->data);
180  SCFree(pb);
181  goto error;
182  }
183  p->allocated++;
184 
185  pb->next = p->alloc_stack;
186  p->alloc_stack = pb;
187  p->alloc_stack_size++;
188  } else {
189  PoolBucket *pb = p->empty_stack;
190  if (pb == NULL) {
191  SCLogError(SC_ERR_POOL_INIT, "alloc error");
192  goto error;
193  }
194 
195  pb->data = (char *)p->data_buffer + u32 * elt_size;
196  if (p->Init(pb->data, p->InitData) != 1) {
197  SCLogError(SC_ERR_POOL_INIT, "init error");
198  if (p->Cleanup)
199  p->Cleanup(pb->data);
200  pb->data = NULL;
201  goto error;
202  }
203 
204  p->empty_stack = pb->next;
205  p->empty_stack_size--;
206 
207  p->allocated++;
208 
209  pb->next = p->alloc_stack;
210  p->alloc_stack = pb;
211  p->alloc_stack_size++;
212  }
213  }
214 
215  return p;
216 
217 error:
218  if (p != NULL) {
219  PoolFree(p);
220  }
221  return NULL;
222 }
223 
224 void PoolFree(Pool *p)
225 {
226  if (p == NULL)
227  return;
228 
229  while (p->alloc_stack != NULL) {
230  PoolBucket *pb = p->alloc_stack;
231  p->alloc_stack = pb->next;
232  if (p->Cleanup)
233  p->Cleanup(pb->data);
234  if (PoolDataPreAllocated(p, pb->data) == 0) {
235  if (p->Free)
236  p->Free(pb->data);
237  else
238  SCFree(pb->data);
239  }
240  pb->data = NULL;
241  if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) {
242  SCFree(pb);
243  }
244  }
245 
246  while (p->empty_stack != NULL) {
247  PoolBucket *pb = p->empty_stack;
248  p->empty_stack = pb->next;
249  if (pb->data!= NULL) {
250  if (p->Cleanup)
251  p->Cleanup(pb->data);
252  if (PoolDataPreAllocated(p, pb->data) == 0) {
253  if (p->Free)
254  p->Free(pb->data);
255  else
256  SCFree(pb->data);
257  }
258  pb->data = NULL;
259  }
260  if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) {
261  SCFree(pb);
262  }
263  }
264 
265  if (p->pb_buffer)
266  SCFree(p->pb_buffer);
267  if (p->data_buffer)
268  SCFree(p->data_buffer);
269  SCFree(p);
270 }
271 
272 void PoolPrint(Pool *p)
273 {
274  printf("\n----------- Hash Table Stats ------------\n");
275  printf("Buckets: %" PRIu32 "\n", p->empty_stack_size + p->alloc_stack_size);
276  printf("-----------------------------------------\n");
277 }
278 
279 void *PoolGet(Pool *p)
280 {
281  SCEnter();
282 
283  PoolBucket *pb = p->alloc_stack;
284  if (pb != NULL) {
285  /* pull from the alloc list */
286  p->alloc_stack = pb->next;
287  p->alloc_stack_size--;
288 
289  /* put in the empty list */
290  pb->next = p->empty_stack;
291  p->empty_stack = pb;
292  p->empty_stack_size++;
293  } else {
294  if (p->max_buckets == 0 || p->allocated < p->max_buckets) {
295  void *pitem;
296  SCLogDebug("max_buckets %"PRIu32"", p->max_buckets);
297 
298  if (p->Alloc != NULL) {
299  pitem = p->Alloc();
300  } else {
301  pitem = SCMalloc(p->elt_size);
302  }
303 
304  if (pitem != NULL) {
305  if (p->Init(pitem, p->InitData) != 1) {
306  if (p->Cleanup)
307  p->Cleanup(pitem);
308  if (p->Free != NULL)
309  p->Free(pitem);
310  else
311  SCFree(pitem);
312  SCReturnPtr(NULL, "void");
313  }
314 
315  p->allocated++;
316  p->outstanding++;
317 #ifdef DEBUG
318  if (p->outstanding > p->max_outstanding)
319  p->max_outstanding = p->outstanding;
320 #endif
321  }
322 
323  SCReturnPtr(pitem, "void");
324  } else {
325  SCReturnPtr(NULL, "void");
326  }
327  }
328 
329  void *ptr = pb->data;
330  pb->data = NULL;
331  p->outstanding++;
332 #ifdef DEBUG
333  if (p->outstanding > p->max_outstanding)
334  p->max_outstanding = p->outstanding;
335 #endif
336  SCReturnPtr(ptr,"void");
337 }
338 
339 void PoolReturn(Pool *p, void *data)
340 {
341  SCEnter();
342 
343  PoolBucket *pb = p->empty_stack;
344 
345  SCLogDebug("pb %p", pb);
346 
347  if (pb == NULL) {
348  p->allocated--;
349  p->outstanding--;
350  if (p->Cleanup != NULL) {
351  p->Cleanup(data);
352  }
353  if (PoolDataPreAllocated(p, data) == 0) {
354  if (p->Free)
355  p->Free(data);
356  else
357  SCFree(data);
358  }
359 
360  SCLogDebug("tried to return data %p to the pool %p, but no more "
361  "buckets available. Just freeing the data.", data, p);
362  SCReturn;
363  }
364 
365  /* pull from the alloc list */
366  p->empty_stack = pb->next;
367  p->empty_stack_size--;
368 
369  /* put in the alloc list */
370  pb->next = p->alloc_stack;
371  p->alloc_stack = pb;
372  p->alloc_stack_size++;
373 
374  pb->data = data;
375  p->outstanding--;
376  SCReturn;
377 }
378 
380 {
381  SCLogDebug("pool %p is using %"PRIu32" out of %"PRIu32" items (%02.1f%%), max %"PRIu32" (%02.1f%%): pool struct memory %"PRIu64".", p, p->outstanding, p->max_buckets, (float)(p->outstanding/(float)(p->max_buckets))*100, p->max_outstanding, (float)(p->max_outstanding/(float)(p->max_buckets))*100, (uint64_t)(p->max_buckets * sizeof(PoolBucket)));
382 }
383 
384 /*
385  * ONLY TESTS BELOW THIS COMMENT
386  */
387 
388 #ifdef UNITTESTS
389 static void *PoolTestAlloc(void)
390 {
391  void *ptr = SCMalloc(10);
392  if (unlikely(ptr == NULL))
393  return NULL;
394  return ptr;
395 }
396 static int PoolTestInitArg(void *data, void *allocdata)
397 {
398  size_t len = strlen((char *)allocdata) + 1;
399  char *str = data;
400  if (str != NULL)
401  strlcpy(str,(char *)allocdata,len);
402  return 1;
403 }
404 
405 static void PoolTestFree(void *ptr)
406 {
407  return;
408 }
409 
410 static int PoolTestInit01 (void)
411 {
412  Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
413  if (p == NULL)
414  return 0;
415 
416  PoolFree(p);
417  return 1;
418 }
419 
420 static int PoolTestInit02 (void)
421 {
422  int retval = 0;
423 
424  Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
425  if (p == NULL)
426  goto end;
427 
428  if (p->alloc_stack == NULL || p->empty_stack == NULL) {
429  printf("list(s) not properly initialized (a:%p e:%p): ",
430  p->alloc_stack, p->empty_stack);
431  retval = 0;
432  goto end;
433  }
434 
435  if (p->Alloc != PoolTestAlloc) {
436  printf("Alloc func ptr %p != %p: ",
437  p->Alloc, PoolTestAlloc);
438  retval = 0;
439  goto end;
440  }
441 
442  if (p->Cleanup != PoolTestFree) {
443  printf("Free func ptr %p != %p: ",
444  p->Cleanup, PoolTestFree);
445  retval = 0;
446  goto end;
447  }
448 
449  retval = 1;
450 end:
451  if (p != NULL)
452  PoolFree(p);
453  return retval;
454 }
455 
456 static int PoolTestInit03 (void)
457 {
458  int retval = 0;
459  void *data = NULL;
460 
461  Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
462  if (p == NULL)
463  goto end;
464 
465  data = PoolGet(p);
466  if (data == NULL) {
467  printf("PoolGet returned NULL: ");
468  retval = 0;
469  goto end;
470  }
471 
472  if (p->alloc_stack_size != 4) {
473  printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size);
474  retval = 0;
475  goto end;
476  }
477 
478  if (p->empty_stack_size != 6) {
479  printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size);
480  retval = 0;
481  goto end;
482  }
483 
484  retval = 1;
485 end:
486  if (p != NULL)
487  PoolFree(p);
488  return retval;
489 }
490 
491 static int PoolTestInit04 (void)
492 {
493  int retval = 0;
494  char *str = NULL;
495 
496  Pool *p = PoolInit(10,5,strlen("test") + 1,NULL, PoolTestInitArg,(void *)"test",PoolTestFree, NULL);
497  if (p == NULL)
498  goto end;
499 
500  str = PoolGet(p);
501  if (str == NULL) {
502  printf("PoolGet returned NULL: ");
503  retval = 0;
504  goto end;
505  }
506 
507  if (strcmp(str, "test") != 0) {
508  printf("Memory not properly initialized: ");
509  retval = 0;
510  goto end;
511  }
512 
513  if (p->alloc_stack_size != 4) {
514  printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size);
515  retval = 0;
516  goto end;
517  }
518 
519  if (p->empty_stack_size != 6) {
520  printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size);
521  retval = 0;
522  goto end;
523  }
524 
525  retval = 1;
526 end:
527  if (p != NULL)
528  PoolFree(p);
529  return retval;
530 }
531 
532 static int PoolTestInit05 (void)
533 {
534  int retval = 0;
535  void *data = NULL;
536 
537  Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL, NULL,PoolTestFree, NULL);
538  if (p == NULL)
539  goto end;
540 
541  data = PoolGet(p);
542  if (data == NULL) {
543  printf("PoolGet returned NULL: ");
544  retval = 0;
545  goto end;
546  }
547 
548  if (p->alloc_stack_size != 4) {
549  printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size);
550  retval = 0;
551  goto end;
552  }
553 
554  if (p->empty_stack_size != 6) {
555  printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size);
556  retval = 0;
557  goto end;
558  }
559 
560  PoolReturn(p, data);
561  data = NULL;
562 
563  if (p->alloc_stack_size != 5) {
564  printf("p->alloc_stack_size 5 != %" PRIu32 ": ", p->alloc_stack_size);
565  retval = 0;
566  goto end;
567  }
568 
569  if (p->empty_stack_size != 5) {
570  printf("p->empty_stack_size 5 != %" PRIu32 ": ", p->empty_stack_size);
571  retval = 0;
572  goto end;
573  }
574 
575  retval = 1;
576 end:
577  if (p != NULL)
578  PoolFree(p);
579  return retval;
580 }
581 
582 static int PoolTestInit06 (void)
583 {
584  int retval = 0;
585  void *data = NULL;
586  void *data2 = NULL;
587 
588  Pool *p = PoolInit(1,0,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
589  if (p == NULL)
590  goto end;
591 
592  if (p->allocated != 0) {
593  printf("p->allocated 0 != %" PRIu32 ": ", p->allocated);
594  retval = 0;
595  goto end;
596  }
597 
598  data = PoolGet(p);
599  if (data == NULL) {
600  printf("PoolGet returned NULL: ");
601  retval = 0;
602  goto end;
603  }
604 
605  if (p->allocated != 1) {
606  printf("p->allocated 1 != %" PRIu32 ": ", p->allocated);
607  retval = 0;
608  goto end;
609  }
610 
611  data2 = PoolGet(p);
612  if (data2 != NULL) {
613  printf("PoolGet returned %p, expected NULL: ", data2);
614  retval = 0;
615  goto end;
616  }
617 
618  PoolReturn(p,data);
619  data = NULL;
620 
621  if (p->allocated != 1) {
622  printf("p->allocated 1 != %" PRIu32 ": ", p->allocated);
623  retval = 0;
624  goto end;
625  }
626 
627  if (p->alloc_stack_size != 1) {
628  printf("p->alloc_stack_size 1 != %" PRIu32 ": ", p->alloc_stack_size);
629  retval = 0;
630  goto end;
631  }
632 
633  retval = 1;
634 end:
635  if (p != NULL)
636  PoolFree(p);
637  return retval;
638 }
639 
640 /** \test pool with unlimited size */
641 static int PoolTestInit07 (void)
642 {
643  int retval = 0;
644  void *data = NULL;
645  void *data2 = NULL;
646 
647  Pool *p = PoolInit(0,1,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
648  if (p == NULL)
649  goto end;
650 
651  if (p->max_buckets != 0) {
652  printf("p->max_buckets 0 != %" PRIu32 ": ", p->max_buckets);
653  retval = 0;
654  goto end;
655  }
656 
657  if (p->allocated != 1) {
658  printf("p->allocated 1 != %" PRIu32 ": ", p->allocated);
659  retval = 0;
660  goto end;
661  }
662 
663  data = PoolGet(p);
664  if (data == NULL) {
665  printf("PoolGet returned NULL: ");
666  retval = 0;
667  goto end;
668  }
669 
670  if (p->allocated != 1) {
671  printf("(2) p->allocated 1 != %" PRIu32 ": ", p->allocated);
672  retval = 0;
673  goto end;
674  }
675 
676  data2 = PoolGet(p);
677  if (data2 == NULL) {
678  printf("PoolGet returned NULL: ");
679  retval = 0;
680  goto end;
681  }
682 
683  if (p->allocated != 2) {
684  printf("(3) p->allocated 2 != %" PRIu32 ": ", p->allocated);
685  retval = 0;
686  goto end;
687  }
688 
689  PoolReturn(p,data);
690  data = NULL;
691 
692  if (p->allocated != 2) {
693  printf("(4) p->allocated 2 != %" PRIu32 ": ", p->allocated);
694  retval = 0;
695  goto end;
696  }
697 
698  if (p->alloc_stack_size != 1) {
699  printf("p->alloc_stack_size 1 != %" PRIu32 ": ", p->alloc_stack_size);
700  retval = 0;
701  goto end;
702  }
703 
704  PoolReturn(p,data2);
705  data2 = NULL;
706 
707  if (p->allocated != 1) {
708  printf("(5) p->allocated 1 != %" PRIu32 ": ", p->allocated);
709  retval = 0;
710  goto end;
711  }
712 
713  retval = 1;
714 end:
715  if (p != NULL)
716  PoolFree(p);
717  return retval;
718 }
719 #endif /* UNITTESTS */
720 
722 {
723 #ifdef UNITTESTS
724  UtRegisterTest("PoolTestInit01", PoolTestInit01);
725  UtRegisterTest("PoolTestInit02", PoolTestInit02);
726  UtRegisterTest("PoolTestInit03", PoolTestInit03);
727  UtRegisterTest("PoolTestInit04", PoolTestInit04);
728  UtRegisterTest("PoolTestInit05", PoolTestInit05);
729  UtRegisterTest("PoolTestInit06", PoolTestInit06);
730  UtRegisterTest("PoolTestInit07", PoolTestInit07);
731 
733 #endif /* UNITTESTS */
734 }
735 
736 
737 /**
738  * @}
739  */
#define SCLogDebug(...)
Definition: util-debug.h:335
uint32_t empty_stack_size
Definition: util-pool.h:54
uint32_t allocated
Definition: util-pool.h:46
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
#define unlikely(expr)
Definition: util-optimize.h:35
#define POOL_BUCKET_PREALLOCATED
Definition: util-pool.h:33
void PoolRegisterTests(void)
Definition: util-pool.c:721
uint32_t elt_size
Definition: util-pool.h:66
void PoolPrintSaturation(Pool *p)
Definition: util-pool.c:379
void * data_buffer
Definition: util-pool.h:57
uint32_t alloc_stack_size
Definition: util-pool.h:49
void * data
Definition: util-pool.h:37
#define str(s)
#define SCCalloc(nm, a)
Definition: util-mem.h:197
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
uint32_t preallocated
Definition: util-pool.h:45
#define SCEnter(...)
Definition: util-debug.h:337
uint8_t flags
Definition: util-pool.h:38
int(* Init)(void *, void *)
Definition: util-pool.h:61
void(* Free)(void *)
Definition: util-pool.h:64
uint32_t outstanding
Definition: util-pool.h:67
void(* Cleanup)(void *)
Definition: util-pool.h:63
PoolBucket * alloc_stack
Definition: util-pool.h:51
void PoolReturn(Pool *p, void *data)
Definition: util-pool.c:339
void PoolFree(Pool *p)
Definition: util-pool.c:224
void PoolThreadRegisterTests(void)
#define SCMalloc(a)
Definition: util-mem.h:166
#define SCFree(a)
Definition: util-mem.h:228
uint32_t max_buckets
Definition: util-pool.h:44
PoolBucket * empty_stack
Definition: util-pool.h:53
#define SCReturnPtr(x, type)
Definition: util-debug.h:353
void * PoolGet(Pool *p)
Definition: util-pool.c:279
struct PoolBucket_ * next
Definition: util-pool.h:39
int data_buffer_size
Definition: util-pool.h:56
#define SCReturn
Definition: util-debug.h:339
uint8_t len
Pool * PoolInit(uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), int(*Init)(void *, void *), void *InitData, void(*Cleanup)(void *), void(*Free)(void *))
Init a Pool.
Definition: util-pool.c:84
void *(* Alloc)(void)
Definition: util-pool.h:60
void * InitData
Definition: util-pool.h:62
void PoolPrint(Pool *p)
Definition: util-pool.c:272
PoolBucket * pb_buffer
Definition: util-pool.h:58