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