suricata
util-pool-thread.c
Go to the documentation of this file.
1 /* Copyright (C) 2013 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  * @{
22  */
23 
24 /**
25  * \file
26  *
27  * \author Victor Julien <victor@inliniac.net>
28  *
29  * Pool utility functions
30  */
31 
32 #include "suricata-common.h"
33 #include "util-pool.h"
34 #include "util-pool-thread.h"
35 #include "util-unittest.h"
36 #include "util-debug.h"
37 
38 /**
39  * \brief per thread Pool, initialization function
40  * \param thread number of threads this is for. Can start with 1 and be expanded.
41  * Other params are as for PoolInit()
42  */
43 PoolThread *PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size,
44  uint32_t elt_size, void *(*Alloc)(void), int (*Init)(void *, void *),
45  void *InitData, void (*Cleanup)(void *), void (*Free)(void *))
46 {
47  if (threads <= 0) {
48  SCLogDebug("error");
49  return NULL;
50  }
51 
52  PoolThread *pt = SCCalloc(1, sizeof(*pt));
53  if (unlikely(pt == NULL)) {
54  SCLogDebug("memory alloc error");
55  goto error;
56  }
57 
58  SCLogDebug("size %d", threads);
59  pt->array = SCMalloc(threads * sizeof(PoolThreadElement));
60  if (pt->array == NULL) {
61  SCLogDebug("memory alloc error");
62  goto error;
63  }
64  pt->size = threads;
65 
66  for (int i = 0; i < threads; i++) {
67  PoolThreadElement *e = &pt->array[i];
68 
69  SCMutexInit(&e->lock, NULL);
70  SCMutexLock(&e->lock);
71 // SCLogDebug("size %u prealloc_size %u elt_size %u Alloc %p Init %p InitData %p Cleanup %p Free %p",
72 // size, prealloc_size, elt_size,
73 // Alloc, Init, InitData, Cleanup, Free);
74  e->pool = PoolInit(size, prealloc_size, elt_size, Alloc, Init, InitData, Cleanup, Free);
75  SCMutexUnlock(&e->lock);
76  if (e->pool == NULL) {
77  SCLogDebug("error");
78  goto error;
79  }
80  }
81 
82  return pt;
83 error:
84  if (pt != NULL)
85  PoolThreadFree(pt);
86  return NULL;
87 }
88 
89 /** \brief expand pool by one for a new thread
90  * \retval -1 or pool thread id
91  */
93 {
94  if (pt == NULL || pt->array == NULL || pt->size == 0) {
95  SCLogError(SC_ERR_POOL_INIT, "pool grow failed");
96  return -1;
97  }
98 
99  size_t newsize = pt->size + 1;
100  SCLogDebug("newsize %"PRIuMAX, (uintmax_t)newsize);
101 
102  void *ptmp = SCRealloc(pt->array, (newsize * sizeof(PoolThreadElement)));
103  if (ptmp == NULL) {
104  SCFree(pt->array);
105  pt->array = NULL;
106  SCLogError(SC_ERR_POOL_INIT, "pool grow failed");
107  return -1;
108  }
109  pt->array = ptmp;
110  pt->size = newsize;
111 
112  /* copy settings from first thread that registered the pool */
113  Pool settings;
114  memset(&settings, 0x0, sizeof(settings));
115  PoolThreadElement *e = &pt->array[0];
116  SCMutexLock(&e->lock);
117  settings.max_buckets = e->pool->max_buckets;
118  settings.preallocated = e->pool->preallocated;
119  settings.elt_size = e->pool->elt_size;
120  settings.Alloc = e->pool->Alloc;
121  settings.Init = e->pool->Init;
122  settings.InitData = e->pool->InitData;
123  settings.Cleanup = e->pool->Cleanup;
124  settings.Free = e->pool->Free;
125  SCMutexUnlock(&e->lock);
126 
127  e = &pt->array[newsize - 1];
128  memset(e, 0x00, sizeof(*e));
129  SCMutexInit(&e->lock, NULL);
130  SCMutexLock(&e->lock);
131  e->pool = PoolInit(settings.max_buckets, settings.preallocated,
132  settings.elt_size, settings.Alloc, settings.Init, settings.InitData,
133  settings.Cleanup, settings.Free);
134  SCMutexUnlock(&e->lock);
135  if (e->pool == NULL) {
136  SCLogError(SC_ERR_POOL_INIT, "pool grow failed");
137  return -1;
138  }
139 
140  return (int)(newsize - 1);
141 }
142 
144 {
145  if (pt == NULL)
146  return -1;
147  return (int)pt->size;
148 }
149 
151 {
152  if (pt == NULL)
153  return;
154 
155  if (pt->array != NULL) {
156  for (int i = 0; i < (int)pt->size; i++) {
157  PoolThreadElement *e = &pt->array[i];
158  SCMutexLock(&e->lock);
159  PoolFree(e->pool);
160  SCMutexUnlock(&e->lock);
161  SCMutexDestroy(&e->lock);
162  }
163  SCFree(pt->array);
164  }
165  SCFree(pt);
166 }
167 
168 void *PoolThreadGetById(PoolThread *pt, uint16_t id)
169 {
170  void *data = NULL;
171 
172  if (pt == NULL || id >= pt->size)
173  return NULL;
174 
175  PoolThreadElement *e = &pt->array[id];
176  SCMutexLock(&e->lock);
177  data = PoolGet(e->pool);
178  SCMutexUnlock(&e->lock);
179  if (data) {
180  PoolThreadReserved *did = data;
181  *did = id;
182  }
183 
184  return data;
185 }
186 
187 void PoolThreadReturn(PoolThread *pt, void *data)
188 {
189  PoolThreadReserved *id = data;
190 
191  if (pt == NULL || *id >= pt->size)
192  return;
193 
194  SCLogDebug("returning to id %u", *id);
195 
196  PoolThreadElement *e = &pt->array[*id];
197  SCMutexLock(&e->lock);
198  PoolReturn(e->pool, data);
199  SCMutexUnlock(&e->lock);
200 }
201 
202 #ifdef UNITTESTS
205  int abc;
206 };
207 
208 static void *PoolThreadTestAlloc(void)
209 {
210  void *data = SCMalloc(sizeof(struct PoolThreadTestData));
211  return data;
212 }
213 
214 static
215 int PoolThreadTestInit(void *data, void *allocdata)
216 {
217  if (!data)
218  return 0;
219 
220  memset(data,0x00,sizeof(allocdata));
221  struct PoolThreadTestData *pdata = data;
222  pdata->abc = *(int *)allocdata;
223  return 1;
224 }
225 
226 static
227 void PoolThreadTestFree(void *data)
228 {
229 }
230 
231 static int PoolThreadTestInit01(void)
232 {
233  PoolThread *pt = PoolThreadInit(4, /* threads */
234  10, 5, 10, PoolThreadTestAlloc,
235  NULL, NULL, NULL, NULL);
236  FAIL_IF(pt == NULL);
237  PoolThreadFree(pt);
238  PASS;
239 }
240 
241 static int PoolThreadTestInit02(void)
242 {
243  int i = 123;
244 
245  PoolThread *pt = PoolThreadInit(4, /* threads */
246  10, 5, 10,
247  PoolThreadTestAlloc, PoolThreadTestInit,
248  &i, PoolThreadTestFree, NULL);
249  FAIL_IF(pt == NULL);
250  PoolThreadFree(pt);
251  PASS;
252 }
253 
254 static int PoolThreadTestGet01(void)
255 {
256  PoolThread *pt = PoolThreadInit(4, /* threads */
257  10, 5, 10, PoolThreadTestAlloc,
258  NULL, NULL, NULL, NULL);
259  FAIL_IF(pt == NULL);
260 
261  void *data = PoolThreadGetById(pt, 3);
262  FAIL_IF_NULL(data);
263 
264  struct PoolThreadTestData *pdata = data;
265  FAIL_IF(pdata->res != 3);
266 
267  PoolThreadFree(pt);
268  PASS;
269 }
270 
271 static int PoolThreadTestGet02(void)
272 {
273  int i = 123;
274 
275  PoolThread *pt = PoolThreadInit(4, /* threads */
276  10, 5, 10, PoolThreadTestAlloc,
277  PoolThreadTestInit, &i, PoolThreadTestFree, NULL);
278  FAIL_IF_NULL(pt);
279 
280  void *data = PoolThreadGetById(pt, 3);
281  FAIL_IF_NULL(data);
282 
283  struct PoolThreadTestData *pdata = data;
284  FAIL_IF_NOT (pdata->res == 3);
285 
286  FAIL_IF_NOT (pdata->abc == 123);
287 
288  PoolThreadFree(pt);
289  PASS;
290 }
291 
292 static int PoolThreadTestReturn01(void)
293 {
294  int i = 123;
295 
296  PoolThread *pt = PoolThreadInit(4, /* threads */
297  10, 5, 10, PoolThreadTestAlloc,
298  PoolThreadTestInit, &i, PoolThreadTestFree, NULL);
299  FAIL_IF_NULL(pt);
300 
301  void *data = PoolThreadGetById(pt, 3);
302  FAIL_IF_NULL(data);
303 
304  struct PoolThreadTestData *pdata = data;
305  FAIL_IF_NOT (pdata->res == 3);
306 
307  FAIL_IF_NOT (pdata->abc == 123);
308 
309  FAIL_IF_NOT (pt->array[3].pool->outstanding == 1);
310 
311  PoolThreadReturn(pt, data);
312 
313  FAIL_IF_NOT (pt->array[3].pool->outstanding == 0);
314 
315  PoolThreadFree(pt);
316  PASS;
317 }
318 
319 static int PoolThreadTestGrow01(void)
320 {
321  PoolThread *pt = PoolThreadInit(4, /* threads */
322  10, 5, 10, PoolThreadTestAlloc,
323  NULL, NULL, NULL, NULL);
324  FAIL_IF_NULL(pt);
325  FAIL_IF(PoolThreadExpand(pt) < 0);
326 
327  PoolThreadFree(pt);
328  PASS;
329 }
330 
331 static int PoolThreadTestGrow02(void)
332 {
333  int i = 123;
334 
335  PoolThread *pt = PoolThreadInit(4, /* threads */
336  10, 5, 10, PoolThreadTestAlloc,
337  PoolThreadTestInit, &i, PoolThreadTestFree, NULL);
338  FAIL_IF_NULL(pt);
339  FAIL_IF(PoolThreadExpand(pt) < 0);
340 
341  PoolThreadFree(pt);
342  PASS;
343 }
344 
345 static int PoolThreadTestGrow03(void)
346 {
347  int i = 123;
348 
349  PoolThread *pt = PoolThreadInit(4, /* threads */
350  10, 5, 10, PoolThreadTestAlloc,
351  PoolThreadTestInit, &i, PoolThreadTestFree, NULL);
352  FAIL_IF_NULL(pt);
353  FAIL_IF(PoolThreadExpand(pt) < 0);
354 
355  void *data = PoolThreadGetById(pt, 4);
356  FAIL_IF_NULL(data);
357 
358  struct PoolThreadTestData *pdata = data;
359  FAIL_IF_NOT(pdata->res == 4);
360 
361  FAIL_IF_NOT(pdata->abc == 123);
362 
363  FAIL_IF_NOT(pt->array[4].pool->outstanding == 1);
364 
365  PoolThreadReturn(pt, data);
366 
367  FAIL_IF_NOT(pt->array[4].pool->outstanding == 0);
368 
369  PoolThreadFree(pt);
370  PASS;
371 }
372 
373 #endif
374 
376 {
377 #ifdef UNITTESTS
378  UtRegisterTest("PoolThreadTestInit01", PoolThreadTestInit01);
379  UtRegisterTest("PoolThreadTestInit02", PoolThreadTestInit02);
380 
381  UtRegisterTest("PoolThreadTestGet01", PoolThreadTestGet01);
382  UtRegisterTest("PoolThreadTestGet02", PoolThreadTestGet02);
383 
384  UtRegisterTest("PoolThreadTestReturn01", PoolThreadTestReturn01);
385 
386  UtRegisterTest("PoolThreadTestGrow01", PoolThreadTestGrow01);
387  UtRegisterTest("PoolThreadTestGrow02", PoolThreadTestGrow02);
388  UtRegisterTest("PoolThreadTestGrow03", PoolThreadTestGrow03);
389 #endif
390 }
391 
392 /**
393  * @}
394  */
int PoolThreadExpand(PoolThread *pt)
expand pool by one for a new thread
PoolThreadElement * array
#define SCLogDebug(...)
Definition: util-debug.h:335
#define PASS
Pass the test.
#define unlikely(expr)
Definition: util-optimize.h:35
uint32_t elt_size
Definition: util-pool.h:66
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
PoolThreadReserved res
#define SCMutexLock(mut)
void PoolThreadFree(PoolThread *pt)
destroy the thread pool
#define SCCalloc(nm, a)
Definition: util-mem.h:253
#define SCMutexUnlock(mut)
#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.
void PoolThreadReturn(PoolThread *pt, void *data)
return data to thread pool
uint32_t preallocated
Definition: util-pool.h:45
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
#define SCMutexInit(mut, mutattrs)
void PoolReturn(Pool *p, void *data)
Definition: util-pool.c:333
void PoolFree(Pool *p)
Definition: util-pool.c:220
#define SCRealloc(x, a)
Definition: util-mem.h:238
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
void * PoolThreadGetById(PoolThread *pt, uint16_t id)
get data from thread pool by thread id
void * PoolGet(Pool *p)
Definition: util-pool.c:275
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
uint16_t PoolThreadReserved
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
int PoolThreadSize(PoolThread *pt)
get size of PoolThread (number of &#39;threads&#39;, so array elements)
void *(* Alloc)(void)
Definition: util-pool.h:60
void * InitData
Definition: util-pool.h:62
PoolThread * PoolThreadInit(int threads, 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 *))
per thread Pool, initialization function
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
#define SCMutexDestroy