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