diff options
Diffstat (limited to 'src/util-pool-thread.c')
-rw-r--r-- | src/util-pool-thread.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/src/util-pool-thread.c b/src/util-pool-thread.c new file mode 100644 index 0000000..162b523 --- /dev/null +++ b/src/util-pool-thread.c @@ -0,0 +1,420 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \defgroup utilpool Pool + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien <victor@inliniac.net> + * + * Pool utility functions + */ + +#include "suricata-common.h" +#include "util-pool.h" +#include "util-pool-thread.h" +#include "util-unittest.h" +#include "util-debug.h" + +/** + * \brief per thread Pool, initialization function + * \param thread number of threads this is for. Can start with 1 and be expanded. + * Other params are as for PoolInit() + */ +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 *)) +{ + sc_errno = SC_OK; + + if (threads <= 0) { + SCLogDebug("error"); + sc_errno = SC_EINVAL; + return NULL; + } + + PoolThread *pt = SCCalloc(1, sizeof(*pt)); + if (unlikely(pt == NULL)) { + SCLogDebug("memory alloc error"); + sc_errno = SC_ENOMEM; + goto error; + } + + SCLogDebug("size %d", threads); + pt->array = SCMalloc(threads * sizeof(PoolThreadElement)); + if (pt->array == NULL) { + SCLogDebug("memory alloc error"); + sc_errno = SC_ENOMEM; + goto error; + } + pt->size = threads; + + for (int i = 0; i < threads; i++) { + PoolThreadElement *e = &pt->array[i]; + + SCMutexInit(&e->lock, NULL); + SCMutexLock(&e->lock); +// SCLogDebug("size %u prealloc_size %u elt_size %u Alloc %p Init %p InitData %p Cleanup %p Free %p", +// size, prealloc_size, elt_size, +// Alloc, Init, InitData, Cleanup, Free); + e->pool = PoolInit(size, prealloc_size, elt_size, Alloc, Init, InitData, Cleanup, Free); + SCMutexUnlock(&e->lock); + if (e->pool == NULL) { + SCLogDebug("error"); + goto error; + } + } + + return pt; +error: + if (pt != NULL) + PoolThreadFree(pt); + return NULL; +} + +/** \brief expand pool by one for a new thread + * \retval -1 or pool thread id + */ +int PoolThreadExpand(PoolThread *pt) +{ + if (pt == NULL || pt->array == NULL || pt->size == 0) { + SCLogError("pool grow failed"); + return -1; + } + + size_t newsize = pt->size + 1; + SCLogDebug("newsize %"PRIuMAX, (uintmax_t)newsize); + + void *ptmp = SCRealloc(pt->array, (newsize * sizeof(PoolThreadElement))); + if (ptmp == NULL) { + SCFree(pt->array); + pt->array = NULL; + SCLogError("pool grow failed"); + return -1; + } + pt->array = ptmp; + pt->size = newsize; + + /* copy settings from first thread that registered the pool */ + Pool settings; + memset(&settings, 0x0, sizeof(settings)); + PoolThreadElement *e = &pt->array[0]; + SCMutexLock(&e->lock); + settings.max_buckets = e->pool->max_buckets; + settings.preallocated = e->pool->preallocated; + settings.elt_size = e->pool->elt_size; + settings.Alloc = e->pool->Alloc; + settings.Init = e->pool->Init; + settings.InitData = e->pool->InitData; + settings.Cleanup = e->pool->Cleanup; + settings.Free = e->pool->Free; + SCMutexUnlock(&e->lock); + + e = &pt->array[newsize - 1]; + memset(e, 0x00, sizeof(*e)); + SCMutexInit(&e->lock, NULL); + SCMutexLock(&e->lock); + e->pool = PoolInit(settings.max_buckets, settings.preallocated, + settings.elt_size, settings.Alloc, settings.Init, settings.InitData, + settings.Cleanup, settings.Free); + SCMutexUnlock(&e->lock); + if (e->pool == NULL) { + SCLogError("pool grow failed"); + return -1; + } + + return (int)(newsize - 1); +} + +int PoolThreadSize(PoolThread *pt) +{ + if (pt == NULL) + return -1; + return (int)pt->size; +} + +void PoolThreadFree(PoolThread *pt) +{ + if (pt == NULL) + return; + + if (pt->array != NULL) { + for (int i = 0; i < (int)pt->size; i++) { + PoolThreadElement *e = &pt->array[i]; + SCMutexLock(&e->lock); + PoolFree(e->pool); + SCMutexUnlock(&e->lock); + SCMutexDestroy(&e->lock); + } + SCFree(pt->array); + } + SCFree(pt); +} + +void *PoolThreadGetById(PoolThread *pt, uint16_t id) +{ + void *data = NULL; + + if (pt == NULL || id >= pt->size) + return NULL; + + PoolThreadElement *e = &pt->array[id]; + SCMutexLock(&e->lock); + data = PoolGet(e->pool); + SCMutexUnlock(&e->lock); + if (data) { + PoolThreadId *did = data; + *did = id; + } + + return data; +} + +void PoolThreadReturn(PoolThread *pt, void *data) +{ + PoolThreadId *id = data; + + if (pt == NULL || *id >= pt->size) + return; + + SCLogDebug("returning to id %u", *id); + + PoolThreadElement *e = &pt->array[*id]; + SCMutexLock(&e->lock); + PoolReturn(e->pool, data); + SCMutexUnlock(&e->lock); +} + +void PoolThreadLock(PoolThread *pt, PoolThreadId id) +{ + BUG_ON(pt == NULL || id >= pt->size); + PoolThreadElement *e = &pt->array[id]; + SCMutexLock(&e->lock); +} + +void PoolThreadReturnRaw(PoolThread *pt, PoolThreadId id, void *data) +{ + BUG_ON(pt == NULL || id >= pt->size); + PoolThreadElement *e = &pt->array[id]; + PoolReturn(e->pool, data); +} + +void PoolThreadUnlock(PoolThread *pt, PoolThreadId id) +{ + BUG_ON(pt == NULL || id >= pt->size); + PoolThreadElement *e = &pt->array[id]; + SCMutexUnlock(&e->lock); +} + +#ifdef UNITTESTS +struct PoolThreadTestData { + PoolThreadId res; + int abc; +}; + +static void *PoolThreadTestAlloc(void) +{ + void *data = SCMalloc(sizeof(struct PoolThreadTestData)); + return data; +} + +static +int PoolThreadTestInit(void *data, void *allocdata) +{ + if (!data) + return 0; + + memset(data,0x00,sizeof(allocdata)); + struct PoolThreadTestData *pdata = data; + pdata->abc = *(int *)allocdata; + return 1; +} + +static +void PoolThreadTestFree(void *data) +{ +} + +static int PoolThreadTestInit01(void) +{ + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, + NULL, NULL, NULL, NULL); + FAIL_IF(pt == NULL); + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestInit02(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, + PoolThreadTestAlloc, PoolThreadTestInit, + &i, PoolThreadTestFree, NULL); + FAIL_IF(pt == NULL); + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGet01(void) +{ + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, + NULL, NULL, NULL, NULL); + FAIL_IF(pt == NULL); + + void *data = PoolThreadGetById(pt, 3); + FAIL_IF_NULL(data); + + struct PoolThreadTestData *pdata = data; + FAIL_IF(pdata->res != 3); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGet02(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, + PoolThreadTestInit, &i, PoolThreadTestFree, NULL); + FAIL_IF_NULL(pt); + + void *data = PoolThreadGetById(pt, 3); + FAIL_IF_NULL(data); + + struct PoolThreadTestData *pdata = data; + FAIL_IF_NOT (pdata->res == 3); + + FAIL_IF_NOT (pdata->abc == 123); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestReturn01(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, + PoolThreadTestInit, &i, PoolThreadTestFree, NULL); + FAIL_IF_NULL(pt); + + void *data = PoolThreadGetById(pt, 3); + FAIL_IF_NULL(data); + + struct PoolThreadTestData *pdata = data; + FAIL_IF_NOT (pdata->res == 3); + + FAIL_IF_NOT (pdata->abc == 123); + + FAIL_IF_NOT (pt->array[3].pool->outstanding == 1); + + PoolThreadReturn(pt, data); + + FAIL_IF_NOT (pt->array[3].pool->outstanding == 0); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGrow01(void) +{ + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, + NULL, NULL, NULL, NULL); + FAIL_IF_NULL(pt); + FAIL_IF(PoolThreadExpand(pt) < 0); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGrow02(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, + PoolThreadTestInit, &i, PoolThreadTestFree, NULL); + FAIL_IF_NULL(pt); + FAIL_IF(PoolThreadExpand(pt) < 0); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGrow03(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, + PoolThreadTestInit, &i, PoolThreadTestFree, NULL); + FAIL_IF_NULL(pt); + FAIL_IF(PoolThreadExpand(pt) < 0); + + void *data = PoolThreadGetById(pt, 4); + FAIL_IF_NULL(data); + + struct PoolThreadTestData *pdata = data; + FAIL_IF_NOT(pdata->res == 4); + + FAIL_IF_NOT(pdata->abc == 123); + + FAIL_IF_NOT(pt->array[4].pool->outstanding == 1); + + PoolThreadReturn(pt, data); + + FAIL_IF_NOT(pt->array[4].pool->outstanding == 0); + + PoolThreadFree(pt); + PASS; +} + +#endif + +void PoolThreadRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("PoolThreadTestInit01", PoolThreadTestInit01); + UtRegisterTest("PoolThreadTestInit02", PoolThreadTestInit02); + + UtRegisterTest("PoolThreadTestGet01", PoolThreadTestGet01); + UtRegisterTest("PoolThreadTestGet02", PoolThreadTestGet02); + + UtRegisterTest("PoolThreadTestReturn01", PoolThreadTestReturn01); + + UtRegisterTest("PoolThreadTestGrow01", PoolThreadTestGrow01); + UtRegisterTest("PoolThreadTestGrow02", PoolThreadTestGrow02); + UtRegisterTest("PoolThreadTestGrow03", PoolThreadTestGrow03); +#endif +} + +/** + * @} + */ |