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 */
44PoolThread *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{
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);
82 if (e->pool == NULL) {
83 SCLogDebug("error");
84 goto error;
85 }
86 }
87
88 return pt;
89error:
90 if (pt != NULL)
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
174void *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
193void 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
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
234
235static void *PoolThreadTestAlloc(void)
236{
237 void *data = SCMalloc(sizeof(struct PoolThreadTestData));
238 return data;
239}
240
241static
242int 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
253static
254void PoolThreadTestFree(void *data)
255{
256}
257
258static 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
268static 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
281static 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
298static 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
319static 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
346static 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
358static 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
372static 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 */
uint32_t id
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
void PoolThreadUnlock(PoolThread *pt, PoolThreadId id)
void PoolThreadFree(PoolThread *pt)
destroy the thread pool
int PoolThreadExpand(PoolThread *pt)
expand pool by one for a new thread
void PoolFree(Pool *p)
Definition util-pool.c:223
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 PoolReturn(Pool *p, void *data)
Definition util-pool.c:329
void PoolThreadRegisterTests(void)
void * PoolThreadGetById(PoolThread *pt, uint16_t id)
get data from thread pool by thread id
void PoolThreadReturn(PoolThread *pt, void *data)
return data to thread pool
int PoolThreadSize(PoolThread *pt)
get size of PoolThread (number of 'threads', so array elements)
void * PoolGet(Pool *p)
Definition util-pool.c:271
void PoolThreadReturnRaw(PoolThread *pt, PoolThreadId id, void *data)
void PoolThreadLock(PoolThread *pt, PoolThreadId id)
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
PoolThreadElement * array
uint32_t max_buckets
Definition util-pool.h:44
void(* Cleanup)(void *)
Definition util-pool.h:63
int(* Init)(void *, void *)
Definition util-pool.h:61
uint32_t preallocated
Definition util-pool.h:45
uint32_t elt_size
Definition util-pool.h:66
void * InitData
Definition util-pool.h:62
uint32_t outstanding
Definition util-pool.h:67
void *(* Alloc)(void)
Definition util-pool.h:60
void(* Free)(void *)
Definition util-pool.h:64
#define SCMutexDestroy
#define SCMutexUnlock(mut)
#define SCMutexInit(mut, mutattrs)
#define SCMutexLock(mut)
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
thread_local SCError sc_errno
Definition util-error.c:31
@ SC_EINVAL
Definition util-error.h:30
@ SC_ENOMEM
Definition util-error.h:29
@ SC_OK
Definition util-error.h:27
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCRealloc(ptr, sz)
Definition util-mem.h:50
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
uint16_t PoolThreadId
#define DEBUG_VALIDATE_BUG_ON(exp)