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