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->Free)
175  p->Free(pb->data);
176  else
177  SCFree(pb->data);
178  SCFree(pb);
179  goto error;
180  }
181  p->allocated++;
182 
183  pb->next = p->alloc_stack;
184  p->alloc_stack = pb;
185  p->alloc_stack_size++;
186  } else {
187  PoolBucket *pb = p->empty_stack;
188  if (pb == NULL) {
189  SCLogError(SC_ERR_POOL_INIT, "alloc error");
190  goto error;
191  }
192 
193  pb->data = (char *)p->data_buffer + u32 * elt_size;
194  if (p->Init(pb->data, p->InitData) != 1) {
195  SCLogError(SC_ERR_POOL_INIT, "init error");
196  pb->data = NULL;
197  goto error;
198  }
199 
200  p->empty_stack = pb->next;
201  p->empty_stack_size--;
202 
203  p->allocated++;
204 
205  pb->next = p->alloc_stack;
206  p->alloc_stack = pb;
207  p->alloc_stack_size++;
208  }
209  }
210 
211  return p;
212 
213 error:
214  if (p != NULL) {
215  PoolFree(p);
216  }
217  return NULL;
218 }
219 
220 void PoolFree(Pool *p)
221 {
222  if (p == NULL)
223  return;
224 
225  while (p->alloc_stack != NULL) {
226  PoolBucket *pb = p->alloc_stack;
227  p->alloc_stack = pb->next;
228  if (p->Cleanup)
229  p->Cleanup(pb->data);
230  if (PoolDataPreAllocated(p, pb->data) == 0) {
231  if (p->Free)
232  p->Free(pb->data);
233  else
234  SCFree(pb->data);
235  }
236  pb->data = NULL;
237  if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) {
238  SCFree(pb);
239  }
240  }
241 
242  while (p->empty_stack != NULL) {
243  PoolBucket *pb = p->empty_stack;
244  p->empty_stack = pb->next;
245  if (pb->data!= NULL) {
246  if (p->Cleanup)
247  p->Cleanup(pb->data);
248  if (PoolDataPreAllocated(p, pb->data) == 0) {
249  if (p->Free)
250  p->Free(pb->data);
251  else
252  SCFree(pb->data);
253  }
254  pb->data = NULL;
255  }
256  if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) {
257  SCFree(pb);
258  }
259  }
260 
261  if (p->pb_buffer)
262  SCFree(p->pb_buffer);
263  if (p->data_buffer)
264  SCFree(p->data_buffer);
265  SCFree(p);
266 }
267 
268 void PoolPrint(Pool *p)
269 {
270  printf("\n----------- Hash Table Stats ------------\n");
271  printf("Buckets: %" PRIu32 "\n", p->empty_stack_size + p->alloc_stack_size);
272  printf("-----------------------------------------\n");
273 }
274 
275 void *PoolGet(Pool *p)
276 {
277  SCEnter();
278 
279  PoolBucket *pb = p->alloc_stack;
280  if (pb != NULL) {
281  /* pull from the alloc list */
282  p->alloc_stack = pb->next;
283  p->alloc_stack_size--;
284 
285  /* put in the empty list */
286  pb->next = p->empty_stack;
287  p->empty_stack = pb;
288  p->empty_stack_size++;
289  } else {
290  if (p->max_buckets == 0 || p->allocated < p->max_buckets) {
291  void *pitem;
292  SCLogDebug("max_buckets %"PRIu32"", p->max_buckets);
293 
294  if (p->Alloc != NULL) {
295  pitem = p->Alloc();
296  } else {
297  pitem = SCMalloc(p->elt_size);
298  }
299 
300  if (pitem != NULL) {
301  if (p->Init(pitem, p->InitData) != 1) {
302  if (p->Free != NULL)
303  p->Free(pitem);
304  else
305  SCFree(pitem);
306  SCReturnPtr(NULL, "void");
307  }
308 
309  p->allocated++;
310  p->outstanding++;
311 #ifdef DEBUG
312  if (p->outstanding > p->max_outstanding)
313  p->max_outstanding = p->outstanding;
314 #endif
315  }
316 
317  SCReturnPtr(pitem, "void");
318  } else {
319  SCReturnPtr(NULL, "void");
320  }
321  }
322 
323  void *ptr = pb->data;
324  pb->data = NULL;
325  p->outstanding++;
326 #ifdef DEBUG
327  if (p->outstanding > p->max_outstanding)
328  p->max_outstanding = p->outstanding;
329 #endif
330  SCReturnPtr(ptr,"void");
331 }
332 
333 void PoolReturn(Pool *p, void *data)
334 {
335  SCEnter();
336 
337  PoolBucket *pb = p->empty_stack;
338 
339  SCLogDebug("pb %p", pb);
340 
341  if (pb == NULL) {
342  p->allocated--;
343  p->outstanding--;
344  if (p->Cleanup != NULL) {
345  p->Cleanup(data);
346  }
347  if (PoolDataPreAllocated(p, data) == 0) {
348  if (p->Free)
349  p->Free(data);
350  else
351  SCFree(data);
352  }
353 
354  SCLogDebug("tried to return data %p to the pool %p, but no more "
355  "buckets available. Just freeing the data.", data, p);
356  SCReturn;
357  }
358 
359  /* pull from the alloc list */
360  p->empty_stack = pb->next;
361  p->empty_stack_size--;
362 
363  /* put in the alloc list */
364  pb->next = p->alloc_stack;
365  p->alloc_stack = pb;
366  p->alloc_stack_size++;
367 
368  pb->data = data;
369  p->outstanding--;
370  SCReturn;
371 }
372 
374 {
375  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)));
376 }
377 
378 /*
379  * ONLY TESTS BELOW THIS COMMENT
380  */
381 
382 #ifdef UNITTESTS
383 static void *PoolTestAlloc(void)
384 {
385  void *ptr = SCMalloc(10);
386  if (unlikely(ptr == NULL))
387  return NULL;
388  return ptr;
389 }
390 static int PoolTestInitArg(void *data, void *allocdata)
391 {
392  size_t len = strlen((char *)allocdata) + 1;
393  char *str = data;
394  if (str != NULL)
395  strlcpy(str,(char *)allocdata,len);
396  return 1;
397 }
398 
399 static void PoolTestFree(void *ptr)
400 {
401  return;
402 }
403 
404 static int PoolTestInit01 (void)
405 {
406  Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
407  if (p == NULL)
408  return 0;
409 
410  PoolFree(p);
411  return 1;
412 }
413 
414 static int PoolTestInit02 (void)
415 {
416  int retval = 0;
417 
418  Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
419  if (p == NULL)
420  goto end;
421 
422  if (p->alloc_stack == NULL || p->empty_stack == NULL) {
423  printf("list(s) not properly initialized (a:%p e:%p): ",
424  p->alloc_stack, p->empty_stack);
425  retval = 0;
426  goto end;
427  }
428 
429  if (p->Alloc != PoolTestAlloc) {
430  printf("Alloc func ptr %p != %p: ",
431  p->Alloc, PoolTestAlloc);
432  retval = 0;
433  goto end;
434  }
435 
436  if (p->Cleanup != PoolTestFree) {
437  printf("Free func ptr %p != %p: ",
438  p->Cleanup, PoolTestFree);
439  retval = 0;
440  goto end;
441  }
442 
443  retval = 1;
444 end:
445  if (p != NULL)
446  PoolFree(p);
447  return retval;
448 }
449 
450 static int PoolTestInit03 (void)
451 {
452  int retval = 0;
453  void *data = NULL;
454 
455  Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
456  if (p == NULL)
457  goto end;
458 
459  data = PoolGet(p);
460  if (data == NULL) {
461  printf("PoolGet returned NULL: ");
462  retval = 0;
463  goto end;
464  }
465 
466  if (p->alloc_stack_size != 4) {
467  printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size);
468  retval = 0;
469  goto end;
470  }
471 
472  if (p->empty_stack_size != 6) {
473  printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size);
474  retval = 0;
475  goto end;
476  }
477 
478  retval = 1;
479 end:
480  if (p != NULL)
481  PoolFree(p);
482  return retval;
483 }
484 
485 static int PoolTestInit04 (void)
486 {
487  int retval = 0;
488  char *str = NULL;
489 
490  Pool *p = PoolInit(10,5,strlen("test") + 1,NULL, PoolTestInitArg,(void *)"test",PoolTestFree, NULL);
491  if (p == NULL)
492  goto end;
493 
494  str = PoolGet(p);
495  if (str == NULL) {
496  printf("PoolGet returned NULL: ");
497  retval = 0;
498  goto end;
499  }
500 
501  if (strcmp(str, "test") != 0) {
502  printf("Memory not properly initialized: ");
503  retval = 0;
504  goto end;
505  }
506 
507  if (p->alloc_stack_size != 4) {
508  printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size);
509  retval = 0;
510  goto end;
511  }
512 
513  if (p->empty_stack_size != 6) {
514  printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size);
515  retval = 0;
516  goto end;
517  }
518 
519  retval = 1;
520 end:
521  if (p != NULL)
522  PoolFree(p);
523  return retval;
524 }
525 
526 static int PoolTestInit05 (void)
527 {
528  int retval = 0;
529  void *data = NULL;
530 
531  Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL, NULL,PoolTestFree, NULL);
532  if (p == NULL)
533  goto end;
534 
535  data = PoolGet(p);
536  if (data == NULL) {
537  printf("PoolGet returned NULL: ");
538  retval = 0;
539  goto end;
540  }
541 
542  if (p->alloc_stack_size != 4) {
543  printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size);
544  retval = 0;
545  goto end;
546  }
547 
548  if (p->empty_stack_size != 6) {
549  printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size);
550  retval = 0;
551  goto end;
552  }
553 
554  PoolReturn(p, data);
555  data = NULL;
556 
557  if (p->alloc_stack_size != 5) {
558  printf("p->alloc_stack_size 5 != %" PRIu32 ": ", p->alloc_stack_size);
559  retval = 0;
560  goto end;
561  }
562 
563  if (p->empty_stack_size != 5) {
564  printf("p->empty_stack_size 5 != %" PRIu32 ": ", p->empty_stack_size);
565  retval = 0;
566  goto end;
567  }
568 
569  retval = 1;
570 end:
571  if (p != NULL)
572  PoolFree(p);
573  return retval;
574 }
575 
576 static int PoolTestInit06 (void)
577 {
578  int retval = 0;
579  void *data = NULL;
580  void *data2 = NULL;
581 
582  Pool *p = PoolInit(1,0,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
583  if (p == NULL)
584  goto end;
585 
586  if (p->allocated != 0) {
587  printf("p->allocated 0 != %" PRIu32 ": ", p->allocated);
588  retval = 0;
589  goto end;
590  }
591 
592  data = PoolGet(p);
593  if (data == NULL) {
594  printf("PoolGet returned NULL: ");
595  retval = 0;
596  goto end;
597  }
598 
599  if (p->allocated != 1) {
600  printf("p->allocated 1 != %" PRIu32 ": ", p->allocated);
601  retval = 0;
602  goto end;
603  }
604 
605  data2 = PoolGet(p);
606  if (data2 != NULL) {
607  printf("PoolGet returned %p, expected NULL: ", data2);
608  retval = 0;
609  goto end;
610  }
611 
612  PoolReturn(p,data);
613  data = NULL;
614 
615  if (p->allocated != 1) {
616  printf("p->allocated 1 != %" PRIu32 ": ", p->allocated);
617  retval = 0;
618  goto end;
619  }
620 
621  if (p->alloc_stack_size != 1) {
622  printf("p->alloc_stack_size 1 != %" PRIu32 ": ", p->alloc_stack_size);
623  retval = 0;
624  goto end;
625  }
626 
627  retval = 1;
628 end:
629  if (p != NULL)
630  PoolFree(p);
631  return retval;
632 }
633 
634 /** \test pool with unlimited size */
635 static int PoolTestInit07 (void)
636 {
637  int retval = 0;
638  void *data = NULL;
639  void *data2 = NULL;
640 
641  Pool *p = PoolInit(0,1,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL);
642  if (p == NULL)
643  goto end;
644 
645  if (p->max_buckets != 0) {
646  printf("p->max_buckets 0 != %" PRIu32 ": ", p->max_buckets);
647  retval = 0;
648  goto end;
649  }
650 
651  if (p->allocated != 1) {
652  printf("p->allocated 1 != %" PRIu32 ": ", p->allocated);
653  retval = 0;
654  goto end;
655  }
656 
657  data = PoolGet(p);
658  if (data == NULL) {
659  printf("PoolGet returned NULL: ");
660  retval = 0;
661  goto end;
662  }
663 
664  if (p->allocated != 1) {
665  printf("(2) p->allocated 1 != %" PRIu32 ": ", p->allocated);
666  retval = 0;
667  goto end;
668  }
669 
670  data2 = PoolGet(p);
671  if (data2 == NULL) {
672  printf("PoolGet returned NULL: ");
673  retval = 0;
674  goto end;
675  }
676 
677  if (p->allocated != 2) {
678  printf("(3) p->allocated 2 != %" PRIu32 ": ", p->allocated);
679  retval = 0;
680  goto end;
681  }
682 
683  PoolReturn(p,data);
684  data = NULL;
685 
686  if (p->allocated != 2) {
687  printf("(4) p->allocated 2 != %" PRIu32 ": ", p->allocated);
688  retval = 0;
689  goto end;
690  }
691 
692  if (p->alloc_stack_size != 1) {
693  printf("p->alloc_stack_size 1 != %" PRIu32 ": ", p->alloc_stack_size);
694  retval = 0;
695  goto end;
696  }
697 
698  PoolReturn(p,data2);
699  data2 = NULL;
700 
701  if (p->allocated != 1) {
702  printf("(5) p->allocated 1 != %" PRIu32 ": ", p->allocated);
703  retval = 0;
704  goto end;
705  }
706 
707  retval = 1;
708 end:
709  if (p != NULL)
710  PoolFree(p);
711  return retval;
712 }
713 #endif /* UNITTESTS */
714 
716 {
717 #ifdef UNITTESTS
718  UtRegisterTest("PoolTestInit01", PoolTestInit01);
719  UtRegisterTest("PoolTestInit02", PoolTestInit02);
720  UtRegisterTest("PoolTestInit03", PoolTestInit03);
721  UtRegisterTest("PoolTestInit04", PoolTestInit04);
722  UtRegisterTest("PoolTestInit05", PoolTestInit05);
723  UtRegisterTest("PoolTestInit06", PoolTestInit06);
724  UtRegisterTest("PoolTestInit07", PoolTestInit07);
725 
727 #endif /* UNITTESTS */
728 }
729 
730 
731 /**
732  * @}
733  */
#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:715
uint32_t elt_size
Definition: util-pool.h:66
void PoolPrintSaturation(Pool *p)
Definition: util-pool.c:373
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:253
#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:333
void PoolFree(Pool *p)
Definition: util-pool.c:220
void PoolThreadRegisterTests(void)
#define SCMalloc(a)
Definition: util-mem.h:222
#define SCFree(a)
Definition: util-mem.h:322
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:275
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:268
PoolBucket * pb_buffer
Definition: util-pool.h:58