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