Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 100 additions & 13 deletions src/libpool.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,46 @@ PoolAllocFuncPtr pool_ext_alloc = malloc;
PoolFreeFuncPtr pool_ext_free = free;
#endif /* !defined(LIBPOOL_NO_STDLIB) */

/*
* External multithreading functions.
*/
#if defined(LIBPOOL_THREAD_SAFE)
#if defined(LIBPOOL_NO_STDLIB)
PoolMutexInitFuncPtr pool_ext_mutex_init = NULL;
PoolMutexLockFuncPtr pool_ext_mutex_lock = NULL;
PoolMutexUnlockFuncPtr pool_ext_mutex_unlock = NULL;
PoolMutexDestroyFuncPtr pool_ext_mutex_destroy = NULL;
#else /* !defined(LIBPOOL_NO_STDLIB) */
#include <pthread.h>
static bool pool_ext_mutex_init_impl(pool_ext_mutex_t* mutex) {
return pthread_mutex_init(mutex, NULL) == 0;
}
static bool pool_ext_mutex_lock_impl(pool_ext_mutex_t* mutex) {
return pthread_mutex_lock(mutex) == 0;
}
static bool pool_ext_mutex_unlock_impl(pool_ext_mutex_t* mutex) {
return pthread_mutex_unlock(mutex) == 0;
}
static bool pool_ext_mutex_destroy_impl(pool_ext_mutex_t* mutex) {
return pthread_mutex_destroy(mutex) == 0;
}
PoolMutexInitFuncPtr pool_ext_mutex_init = pool_ext_mutex_init_impl;
PoolMutexLockFuncPtr pool_ext_mutex_lock = pool_ext_mutex_lock_impl;
PoolMutexUnlockFuncPtr pool_ext_mutex_unlock = pool_ext_mutex_unlock_impl;
PoolMutexDestroyFuncPtr pool_ext_mutex_destroy = pool_ext_mutex_destroy_impl;
#endif /* !defined(LIBPOOL_NO_STDLIB) */
#endif /* defined(LIBPOOL_THEAD_SAFE) */

/*
* External valgrind macros.
*/
#if defined(LIBPOOL_NO_VALGRIND)
#define VALGRIND_CREATE_MEMPOOL(a, b, c) ((void)0)
#define VALGRIND_DESTROY_MEMPOOL(a) ((void)0)
#define VALGRIND_MEMPOOL_ALLOC(a, b, c) ((void)0)
#define VALGRIND_MEMPOOL_FREE(a, b) ((void)0)
#define VALGRIND_MAKE_MEM_DEFINED(a, b) ((void)0)
#define VALGRIND_MAKE_MEM_NOACCESS(a, b) ((void)0)
#define VALGRIND_CREATE_MEMPOOL(A, B, C) ((void)0)
#define VALGRIND_DESTROY_MEMPOOL(A) ((void)0)
#define VALGRIND_MEMPOOL_ALLOC(A, B, C) ((void)0)
#define VALGRIND_MEMPOOL_FREE(A, B) ((void)0)
#define VALGRIND_MAKE_MEM_DEFINED(A, B) ((void)0)
#define VALGRIND_MAKE_MEM_NOACCESS(A, B) ((void)0)
#else /* !defined(LIBPOOL_NO_VALGRIND) */
#include <valgrind/valgrind.h>
#include <valgrind/memcheck.h>
Expand All @@ -60,7 +90,7 @@ PoolFreeFuncPtr pool_ext_free = free;
#define ALIGN2BOUNDARY(ADDR, BOUND) (ADDR)
#else /* !defined(LIBPOOL_NO_ALIGNMENT) */
#define ALIGN2BOUNDARY(SIZE, BOUNDARY) \
(((SIZE) + (BOUNDARY) - 1) & ~((BOUNDARY) - 1))
(((SIZE) + (BOUNDARY)-1) & ~((BOUNDARY)-1))
#endif /* !defined(LIBPOOL_NO_ALIGNMENT) */

/*----------------------------------------------------------------------------*/
Expand Down Expand Up @@ -93,6 +123,10 @@ struct Pool {
void* free_chunk;
ArrayStart* array_starts;
size_t chunk_sz;

#if defined(LIBPOOL_THREAD_SAFE)
pool_ext_mutex_t lock;
#endif /* defined(LIBPOOL_THREAD_SAFE) */
};

/*----------------------------------------------------------------------------*/
Expand Down Expand Up @@ -148,6 +182,15 @@ Pool* pool_new(size_t pool_sz, size_t chunk_sz) {
return NULL;
}

#if defined(LIBPOOL_THREAD_SAFE)
if (!pool_ext_mutex_init(&pool->lock)) {
pool_ext_free(arr);
pool_ext_free(pool->array_starts);
pool_ext_free(pool);
return NULL;
}
#endif /* defined(LIBPOOL_THREAD_SAFE) */

/*
* Build the linked list. Use the first N bytes of the free chunks for
* storing the (hypothetical) `.next' pointer. This is why `chunk_sz' must
Expand Down Expand Up @@ -181,23 +224,32 @@ Pool* pool_new(size_t pool_sz, size_t chunk_sz) {
* 5. Prepend the new `ArrayStart' to the existing linked list of array starts.
*/
bool pool_expand(Pool* pool, size_t extra_sz) {
bool result = true;
ArrayStart* array_start;
char* extra_arr;
size_t i;

if (pool == NULL || extra_sz <= 0)
return false;

#if defined(LIBPOOL_THREAD_SAFE)
if (!pool_ext_mutex_lock(&pool->lock))
return false;
#endif /* defined(LIBPOOL_THREAD_SAFE) */

VALGRIND_MAKE_MEM_DEFINED(pool, sizeof(Pool));

array_start = pool_ext_alloc(sizeof(ArrayStart));
if (array_start == NULL)
return false;
if (array_start == NULL) {
result = false;
goto alloc_err;
}

extra_arr = pool_ext_alloc(extra_sz * pool->chunk_sz);
if (extra_arr == NULL) {
pool_ext_free(array_start);
return false;
result = false;
goto alloc_err;
}

for (i = 0; i < extra_sz - 1; i++)
Expand All @@ -213,9 +265,14 @@ bool pool_expand(Pool* pool, size_t extra_sz) {

VALGRIND_MAKE_MEM_NOACCESS(extra_arr, extra_sz * pool->chunk_sz);
VALGRIND_MAKE_MEM_NOACCESS(array_start, sizeof(ArrayStart));
alloc_err:
VALGRIND_MAKE_MEM_NOACCESS(pool, sizeof(Pool));

return true;
#if defined(LIBPOOL_THREAD_SAFE)
pool_ext_mutex_unlock(&pool->lock);
#endif /* defined(LIBPOOL_THREAD_SAFE) */

return result;
}

/*
Expand All @@ -230,6 +287,11 @@ void pool_destroy(Pool* pool) {
if (pool == NULL)
return;

#if defined(LIBPOOL_THREAD_SAFE)
if (!pool_ext_mutex_lock(&pool->lock))
return;
#endif /* defined(LIBPOOL_THREAD_SAFE) */

VALGRIND_MAKE_MEM_DEFINED(pool, sizeof(Pool));

array_start = pool->array_starts;
Expand All @@ -242,6 +304,11 @@ void pool_destroy(Pool* pool) {
array_start = next;
}

#if defined(LIBPOOL_THREAD_SAFE)
pool_ext_mutex_unlock(&pool->lock);
pool_ext_mutex_destroy(&pool->lock);
#endif /* defined(LIBPOOL_THREAD_SAFE) */

VALGRIND_DESTROY_MEMPOOL(pool);
pool_ext_free(pool);
}
Expand All @@ -255,14 +322,20 @@ void pool_destroy(Pool* pool) {
* linked list to the second item of the old list.
*/
void* pool_alloc(Pool* pool) {
void* result;
void* result = NULL;

if (pool == NULL)
return NULL;

#if defined(LIBPOOL_THREAD_SAFE)
if (!pool_ext_mutex_lock(&pool->lock))
return NULL;
#endif /* defined(LIBPOOL_THREAD_SAFE) */

VALGRIND_MAKE_MEM_DEFINED(pool, sizeof(Pool));

if (pool->free_chunk == NULL)
return NULL;
goto done;
VALGRIND_MAKE_MEM_DEFINED(pool->free_chunk, sizeof(void**));

result = pool->free_chunk;
Expand All @@ -272,6 +345,11 @@ void* pool_alloc(Pool* pool) {
VALGRIND_MAKE_MEM_NOACCESS(pool->free_chunk, sizeof(void**));
VALGRIND_MAKE_MEM_NOACCESS(pool, sizeof(Pool));

done:
#if defined(LIBPOOL_THREAD_SAFE)
pool_ext_mutex_unlock(&pool->lock);
#endif /* defined(LIBPOOL_THREAD_SAFE) */

return result;
}

Expand All @@ -283,11 +361,20 @@ void pool_free(Pool* pool, void* ptr) {
if (pool == NULL || ptr == NULL)
return;

#if defined(LIBPOOL_THREAD_SAFE)
if (!pool_ext_mutex_lock(&pool->lock))
return;
#endif /* defined(LIBPOOL_THREAD_SAFE) */

VALGRIND_MAKE_MEM_DEFINED(pool, sizeof(Pool));

*(void**)ptr = pool->free_chunk;
pool->free_chunk = ptr;

VALGRIND_MAKE_MEM_NOACCESS(pool, sizeof(Pool));
VALGRIND_MEMPOOL_FREE(pool, ptr);

#if defined(LIBPOOL_THREAD_SAFE)
pool_ext_mutex_unlock(&pool->lock);
#endif /* defined(LIBPOOL_THREAD_SAFE) */
}
31 changes: 31 additions & 0 deletions src/libpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,37 @@ typedef void (*PoolFreeFuncPtr)(void*);
extern PoolAllocFuncPtr pool_ext_alloc;
extern PoolFreeFuncPtr pool_ext_free;

/*
* External functions for thread-safe operations, only used if
* 'LIBPOOL_THEAD_SAFE' is defined.
*
* If `LIBPOOL_NO_STDLIB' is defined, they are set to NULL, so the user must
* initialize them. Otherwise, their default value are POSIX Thread (pthread)
* functions.
*/
#if defined(LIBPOOL_THREAD_SAFE)
#if defined(LIBPOOL_NO_STDLIB)
#if !defined(POOL_EXT_MUTEX_TYPE)
#error \
"POOL_EXT_MUTEX_TYPE must be defined if LIBPOOL_THREAD_SAFE and LIBPOOL_NO_STDLIB are defined."
#endif /* !defined(POOL_EXT_MUTEX_TYPE) */
typedef POOL_EXT_MUTEX_TYPE pool_ext_mutex_t;
#else /* !defined(LIBPOOL_NO_STDLIB) */
#include <pthread.h>
typedef pthread_mutex_t pool_ext_mutex_t;
#endif /* !defined(LIBPOOL_NO_STDLIB) */
typedef bool (*PoolMutexInitFuncPtr)(pool_ext_mutex_t*);
typedef bool (*PoolMutexLockFuncPtr)(pool_ext_mutex_t*);
typedef bool (*PoolMutexUnlockFuncPtr)(pool_ext_mutex_t*);
typedef bool (*PoolMutexDestroyFuncPtr)(pool_ext_mutex_t*);
extern PoolMutexInitFuncPtr pool_ext_mutex_init;
extern PoolMutexLockFuncPtr pool_ext_mutex_lock;
extern PoolMutexUnlockFuncPtr pool_ext_mutex_unlock;
extern PoolMutexDestroyFuncPtr pool_ext_mutex_destroy;
#endif /* defined(LIBPOOL_THREAD_SAFE) */

/*----------------------------------------------------------------------------*/

/*
* Allocate and initialize a new `Pool' structure, with the specified number of
* chunks, each with the specified size.
Expand Down