|
@@ -1,7 +1,7 @@ |
|
|
/* |
|
|
/* |
|
|
* RealTime Memory Pool, heavily based on work by Nedko Arnaudov |
|
|
* RealTime Memory Pool, heavily based on work by Nedko Arnaudov |
|
|
* Copyright (C) 2006-2009 Nedko Arnaudov <nedko@arnaudov.name> |
|
|
* Copyright (C) 2006-2009 Nedko Arnaudov <nedko@arnaudov.name> |
|
|
* Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com> |
|
|
|
|
|
|
|
|
* Copyright (C) 2013-2016 Filipe Coelho <falktx@falktx.com> |
|
|
* |
|
|
* |
|
|
* This program is free software; you can redistribute it and/or |
|
|
* This program is free software; you can redistribute it and/or |
|
|
* modify it under the terms of the GNU General Public License as |
|
|
* modify it under the terms of the GNU General Public License as |
|
@@ -26,6 +26,16 @@ |
|
|
#include <stdlib.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
|
|
|
//#define RTMEMPOOL_THREAD_SAFETY 1 |
|
|
|
|
|
|
|
|
|
|
|
#if RTMEMPOOL_THREAD_SAFETY |
|
|
|
|
|
#define rtmempool_mutex_lock(m) pthread_mutex_lock(m) |
|
|
|
|
|
#define rtmempool_mutex_unlock(m) pthread_mutex_unlock(m) |
|
|
|
|
|
#else |
|
|
|
|
|
#define rtmempool_mutex_lock(...) |
|
|
|
|
|
#define rtmempool_mutex_unlock(...) |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
|
typedef struct list_head k_list_head; |
|
|
typedef struct list_head k_list_head; |
|
@@ -46,92 +56,57 @@ typedef struct _RtMemPool |
|
|
k_list_head unused; |
|
|
k_list_head unused; |
|
|
unsigned int unusedCount; |
|
|
unsigned int unusedCount; |
|
|
|
|
|
|
|
|
bool enforceThreadSafety; |
|
|
|
|
|
|
|
|
|
|
|
// next members are initialized/used only if enforceThreadSafety is true |
|
|
|
|
|
pthread_mutex_t mutex; |
|
|
pthread_mutex_t mutex; |
|
|
unsigned int unusedCount2; |
|
|
|
|
|
k_list_head pending; |
|
|
|
|
|
size_t usedSize; |
|
|
|
|
|
|
|
|
|
|
|
} RtMemPool; |
|
|
} RtMemPool; |
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
// adjust unused list size |
|
|
// adjust unused list size |
|
|
|
|
|
|
|
|
static void rtsafe_memory_pool_sleepy(RtMemPool* poolPtr) |
|
|
|
|
|
|
|
|
static void rtsafe_memory_pool_sleepy(RtMemPool* poolPtr, bool* overMaxOrMallocFailed) |
|
|
{ |
|
|
{ |
|
|
k_list_head* nodePtr; |
|
|
k_list_head* nodePtr; |
|
|
unsigned int count; |
|
|
|
|
|
|
|
|
|
|
|
if (poolPtr->enforceThreadSafety) |
|
|
|
|
|
{ |
|
|
|
|
|
pthread_mutex_lock(&poolPtr->mutex); |
|
|
|
|
|
|
|
|
|
|
|
count = poolPtr->unusedCount2; |
|
|
|
|
|
|
|
|
k_list_head unused; |
|
|
|
|
|
unsigned int unusedCount; |
|
|
|
|
|
|
|
|
assert(poolPtr->minPreallocated < poolPtr->maxPreallocated); |
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&unused); |
|
|
|
|
|
unusedCount = 0; |
|
|
|
|
|
|
|
|
while (count < poolPtr->minPreallocated) |
|
|
|
|
|
|
|
|
while (poolPtr->unusedCount + unusedCount < poolPtr->minPreallocated) |
|
|
|
|
|
{ |
|
|
|
|
|
if (poolPtr->usedCount + poolPtr->unusedCount + unusedCount >= poolPtr->maxPreallocated) |
|
|
{ |
|
|
{ |
|
|
nodePtr = malloc(sizeof(k_list_head) + poolPtr->dataSize); |
|
|
|
|
|
|
|
|
|
|
|
if (nodePtr == NULL) |
|
|
|
|
|
{ |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
list_add_tail(nodePtr, &poolPtr->pending); |
|
|
|
|
|
|
|
|
|
|
|
count++; |
|
|
|
|
|
|
|
|
|
|
|
poolPtr->usedSize += poolPtr->dataSize; |
|
|
|
|
|
|
|
|
*overMaxOrMallocFailed = true; |
|
|
|
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
while (count > poolPtr->maxPreallocated && ! list_empty(&poolPtr->pending)) |
|
|
|
|
|
{ |
|
|
|
|
|
nodePtr = poolPtr->pending.next; |
|
|
|
|
|
|
|
|
|
|
|
list_del(nodePtr); |
|
|
|
|
|
|
|
|
|
|
|
free(nodePtr); |
|
|
|
|
|
|
|
|
nodePtr = malloc(sizeof(k_list_head) + poolPtr->dataSize); |
|
|
|
|
|
|
|
|
count--; |
|
|
|
|
|
|
|
|
|
|
|
poolPtr->usedSize -= poolPtr->dataSize; |
|
|
|
|
|
|
|
|
if (nodePtr == NULL) |
|
|
|
|
|
{ |
|
|
|
|
|
*overMaxOrMallocFailed = true; |
|
|
|
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&poolPtr->mutex); |
|
|
|
|
|
|
|
|
list_add_tail(nodePtr, &unused); |
|
|
|
|
|
++unusedCount; |
|
|
} |
|
|
} |
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
while (poolPtr->unusedCount < poolPtr->minPreallocated) |
|
|
|
|
|
{ |
|
|
|
|
|
nodePtr = malloc(sizeof(k_list_head) + poolPtr->dataSize); |
|
|
|
|
|
|
|
|
|
|
|
if (nodePtr == NULL) |
|
|
|
|
|
{ |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
list_add_tail(nodePtr, &poolPtr->unused); |
|
|
|
|
|
poolPtr->unusedCount++; |
|
|
|
|
|
poolPtr->usedSize += poolPtr->dataSize; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while (poolPtr->unusedCount > poolPtr->maxPreallocated) |
|
|
|
|
|
{ |
|
|
|
|
|
assert(! list_empty(&poolPtr->unused)); |
|
|
|
|
|
|
|
|
rtmempool_mutex_lock(&poolPtr->mutex); |
|
|
|
|
|
|
|
|
nodePtr = poolPtr->unused.next; |
|
|
|
|
|
|
|
|
poolPtr->unusedCount += unusedCount; |
|
|
|
|
|
|
|
|
list_del(nodePtr); |
|
|
|
|
|
poolPtr->unusedCount--; |
|
|
|
|
|
|
|
|
while (unusedCount != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
assert(! list_empty(&unused)); |
|
|
|
|
|
|
|
|
free(nodePtr); |
|
|
|
|
|
poolPtr->usedSize -= poolPtr->dataSize; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
nodePtr = unused.next; |
|
|
|
|
|
list_del(nodePtr); |
|
|
|
|
|
list_add_tail(nodePtr, &poolPtr->unused); |
|
|
|
|
|
--unusedCount; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
rtmempool_mutex_unlock(&poolPtr->mutex); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
// ------------------------------------------------------------------------------------------------ |
|
@@ -140,12 +115,12 @@ static bool rtsafe_memory_pool_create2(RtMemPool_Handle* handlePtr, |
|
|
const char* poolName, |
|
|
const char* poolName, |
|
|
size_t dataSize, |
|
|
size_t dataSize, |
|
|
size_t minPreallocated, |
|
|
size_t minPreallocated, |
|
|
size_t maxPreallocated, |
|
|
|
|
|
int enforceThreadSafety) |
|
|
|
|
|
|
|
|
size_t maxPreallocated) |
|
|
{ |
|
|
{ |
|
|
assert(minPreallocated <= maxPreallocated); |
|
|
assert(minPreallocated <= maxPreallocated); |
|
|
assert(poolName == NULL || strlen(poolName) < RTSAFE_MEMORY_POOL_NAME_MAX); |
|
|
assert(poolName == NULL || strlen(poolName) < RTSAFE_MEMORY_POOL_NAME_MAX); |
|
|
|
|
|
|
|
|
|
|
|
k_list_head* nodePtr; |
|
|
RtMemPool* poolPtr; |
|
|
RtMemPool* poolPtr; |
|
|
|
|
|
|
|
|
poolPtr = malloc(sizeof(RtMemPool)); |
|
|
poolPtr = malloc(sizeof(RtMemPool)); |
|
@@ -174,23 +149,27 @@ static bool rtsafe_memory_pool_create2(RtMemPool_Handle* handlePtr, |
|
|
INIT_LIST_HEAD(&poolPtr->unused); |
|
|
INIT_LIST_HEAD(&poolPtr->unused); |
|
|
poolPtr->unusedCount = 0; |
|
|
poolPtr->unusedCount = 0; |
|
|
|
|
|
|
|
|
poolPtr->enforceThreadSafety = (enforceThreadSafety != 0); |
|
|
|
|
|
|
|
|
pthread_mutexattr_t atts; |
|
|
|
|
|
pthread_mutexattr_init(&atts); |
|
|
|
|
|
#ifdef __ARM_ARCH_7A__ |
|
|
|
|
|
pthread_mutexattr_setprotocol(&atts, PTHREAD_PRIO_INHERIT); |
|
|
|
|
|
#endif |
|
|
|
|
|
pthread_mutex_init(&poolPtr->mutex, &atts); |
|
|
|
|
|
pthread_mutexattr_destroy(&atts); |
|
|
|
|
|
|
|
|
if (poolPtr->enforceThreadSafety) |
|
|
|
|
|
|
|
|
while (poolPtr->unusedCount < poolPtr->minPreallocated) |
|
|
{ |
|
|
{ |
|
|
if (pthread_mutex_init(&poolPtr->mutex, NULL) != 0) |
|
|
|
|
|
|
|
|
nodePtr = malloc(sizeof(k_list_head) + poolPtr->dataSize); |
|
|
|
|
|
|
|
|
|
|
|
if (nodePtr == NULL) |
|
|
{ |
|
|
{ |
|
|
free(poolPtr); |
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&poolPtr->pending); |
|
|
|
|
|
|
|
|
list_add_tail(nodePtr, &poolPtr->unused); |
|
|
|
|
|
poolPtr->unusedCount++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
poolPtr->unusedCount2 = 0; |
|
|
|
|
|
poolPtr->usedSize = 0; |
|
|
|
|
|
|
|
|
|
|
|
rtsafe_memory_pool_sleepy(poolPtr); |
|
|
|
|
|
*handlePtr = (RtMemPool_Handle)poolPtr; |
|
|
*handlePtr = (RtMemPool_Handle)poolPtr; |
|
|
|
|
|
|
|
|
return true; |
|
|
return true; |
|
@@ -198,9 +177,13 @@ static bool rtsafe_memory_pool_create2(RtMemPool_Handle* handlePtr, |
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
|
static unsigned char rtsafe_memory_pool_create_old(const char* poolName, size_t dataSize, size_t minPreallocated, size_t maxPreallocated, RtMemPool_Handle* handlePtr) |
|
|
|
|
|
|
|
|
static unsigned char rtsafe_memory_pool_create_old(const char* poolName, |
|
|
|
|
|
size_t dataSize, |
|
|
|
|
|
size_t minPreallocated, |
|
|
|
|
|
size_t maxPreallocated, |
|
|
|
|
|
RtMemPool_Handle* handlePtr) |
|
|
{ |
|
|
{ |
|
|
return rtsafe_memory_pool_create2(handlePtr, poolName, dataSize, minPreallocated, maxPreallocated, 0); |
|
|
|
|
|
|
|
|
return rtsafe_memory_pool_create2(handlePtr, poolName, dataSize, minPreallocated, maxPreallocated); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
// ------------------------------------------------------------------------------------------------ |
|
@@ -211,18 +194,7 @@ bool rtsafe_memory_pool_create(RtMemPool_Handle* handlePtr, |
|
|
size_t minPreallocated, |
|
|
size_t minPreallocated, |
|
|
size_t maxPreallocated) |
|
|
size_t maxPreallocated) |
|
|
{ |
|
|
{ |
|
|
return rtsafe_memory_pool_create2(handlePtr, poolName, dataSize, minPreallocated, maxPreallocated, 0); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
|
|
|
|
bool rtsafe_memory_pool_create_safe(RtMemPool_Handle* handlePtr, |
|
|
|
|
|
const char* poolName, |
|
|
|
|
|
size_t dataSize, |
|
|
|
|
|
size_t minPreallocated, |
|
|
|
|
|
size_t maxPreallocated) |
|
|
|
|
|
{ |
|
|
|
|
|
return rtsafe_memory_pool_create2(handlePtr, poolName, dataSize, minPreallocated, maxPreallocated, 1); |
|
|
|
|
|
|
|
|
return rtsafe_memory_pool_create2(handlePtr, poolName, dataSize, minPreallocated, maxPreallocated); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
// ------------------------------------------------------------------------------------------------ |
|
@@ -254,26 +226,7 @@ void rtsafe_memory_pool_destroy(RtMemPool_Handle handle) |
|
|
|
|
|
|
|
|
assert(list_empty(&poolPtr->unused)); |
|
|
assert(list_empty(&poolPtr->unused)); |
|
|
|
|
|
|
|
|
if (poolPtr->enforceThreadSafety) |
|
|
|
|
|
{ |
|
|
|
|
|
while (! list_empty(&poolPtr->pending)) |
|
|
|
|
|
{ |
|
|
|
|
|
nodePtr = poolPtr->pending.next; |
|
|
|
|
|
|
|
|
|
|
|
list_del(nodePtr); |
|
|
|
|
|
|
|
|
|
|
|
free(nodePtr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ret = pthread_mutex_destroy(&poolPtr->mutex); |
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
|
assert(ret == 0); |
|
|
|
|
|
#else |
|
|
|
|
|
// unused |
|
|
|
|
|
(void)ret; |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
pthread_mutex_destroy(&poolPtr->mutex); |
|
|
|
|
|
|
|
|
free(poolPtr); |
|
|
free(poolPtr); |
|
|
} |
|
|
} |
|
@@ -288,8 +241,11 @@ void* rtsafe_memory_pool_allocate_atomic(RtMemPool_Handle handle) |
|
|
k_list_head* nodePtr; |
|
|
k_list_head* nodePtr; |
|
|
RtMemPool* poolPtr = (RtMemPool*)handle; |
|
|
RtMemPool* poolPtr = (RtMemPool*)handle; |
|
|
|
|
|
|
|
|
|
|
|
rtmempool_mutex_lock(&poolPtr->mutex); |
|
|
|
|
|
|
|
|
if (list_empty(&poolPtr->unused)) |
|
|
if (list_empty(&poolPtr->unused)) |
|
|
{ |
|
|
{ |
|
|
|
|
|
rtmempool_mutex_unlock(&poolPtr->mutex); |
|
|
return NULL; |
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -301,22 +257,7 @@ void* rtsafe_memory_pool_allocate_atomic(RtMemPool_Handle handle) |
|
|
|
|
|
|
|
|
list_add_tail(nodePtr, &poolPtr->used); |
|
|
list_add_tail(nodePtr, &poolPtr->used); |
|
|
|
|
|
|
|
|
if (poolPtr->enforceThreadSafety && pthread_mutex_trylock(&poolPtr->mutex) == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
while (poolPtr->unusedCount < poolPtr->minPreallocated && ! list_empty(&poolPtr->pending)) |
|
|
|
|
|
{ |
|
|
|
|
|
nodePtr = poolPtr->pending.next; |
|
|
|
|
|
|
|
|
|
|
|
list_del(nodePtr); |
|
|
|
|
|
list_add_tail(nodePtr, &poolPtr->unused); |
|
|
|
|
|
|
|
|
|
|
|
poolPtr->unusedCount++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
poolPtr->unusedCount2 = poolPtr->unusedCount; |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&poolPtr->mutex); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
rtmempool_mutex_unlock(&poolPtr->mutex); |
|
|
|
|
|
|
|
|
return (nodePtr + 1); |
|
|
return (nodePtr + 1); |
|
|
} |
|
|
} |
|
@@ -328,13 +269,14 @@ void* rtsafe_memory_pool_allocate_sleepy(RtMemPool_Handle handle) |
|
|
assert(handle); |
|
|
assert(handle); |
|
|
|
|
|
|
|
|
void* data; |
|
|
void* data; |
|
|
|
|
|
bool overMaxOrMallocFailed = false; |
|
|
RtMemPool* poolPtr = (RtMemPool*)handle; |
|
|
RtMemPool* poolPtr = (RtMemPool*)handle; |
|
|
|
|
|
|
|
|
do { |
|
|
do { |
|
|
rtsafe_memory_pool_sleepy(poolPtr); |
|
|
|
|
|
|
|
|
rtsafe_memory_pool_sleepy(poolPtr, &overMaxOrMallocFailed); |
|
|
data = rtsafe_memory_pool_allocate_atomic((RtMemPool_Handle)poolPtr); |
|
|
data = rtsafe_memory_pool_allocate_atomic((RtMemPool_Handle)poolPtr); |
|
|
} |
|
|
} |
|
|
while (data == NULL); |
|
|
|
|
|
|
|
|
while (data == NULL && ! overMaxOrMallocFailed); |
|
|
|
|
|
|
|
|
return data; |
|
|
return data; |
|
|
} |
|
|
} |
|
@@ -346,33 +288,21 @@ void rtsafe_memory_pool_deallocate(RtMemPool_Handle handle, void* memoryPtr) |
|
|
{ |
|
|
{ |
|
|
assert(handle); |
|
|
assert(handle); |
|
|
|
|
|
|
|
|
k_list_head* nodePtr; |
|
|
|
|
|
RtMemPool* poolPtr = (RtMemPool*)handle; |
|
|
RtMemPool* poolPtr = (RtMemPool*)handle; |
|
|
|
|
|
|
|
|
|
|
|
rtmempool_mutex_lock(&poolPtr->mutex); |
|
|
|
|
|
|
|
|
list_del((k_list_head*)memoryPtr - 1); |
|
|
list_del((k_list_head*)memoryPtr - 1); |
|
|
list_add_tail((k_list_head*)memoryPtr - 1, &poolPtr->unused); |
|
|
list_add_tail((k_list_head*)memoryPtr - 1, &poolPtr->unused); |
|
|
poolPtr->usedCount--; |
|
|
poolPtr->usedCount--; |
|
|
poolPtr->unusedCount++; |
|
|
poolPtr->unusedCount++; |
|
|
|
|
|
|
|
|
if (poolPtr->enforceThreadSafety && pthread_mutex_trylock(&poolPtr->mutex) == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
while (poolPtr->unusedCount > poolPtr->maxPreallocated) |
|
|
|
|
|
{ |
|
|
|
|
|
assert(! list_empty(&poolPtr->unused)); |
|
|
|
|
|
|
|
|
|
|
|
nodePtr = poolPtr->unused.next; |
|
|
|
|
|
|
|
|
|
|
|
list_del(nodePtr); |
|
|
|
|
|
list_add_tail(nodePtr, &poolPtr->pending); |
|
|
|
|
|
poolPtr->unusedCount--; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
poolPtr->unusedCount2 = poolPtr->unusedCount; |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&poolPtr->mutex); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
rtmempool_mutex_unlock(&poolPtr->mutex); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ |
|
|
|
|
|
// LV2 stuff |
|
|
|
|
|
|
|
|
void lv2_rtmempool_init(LV2_RtMemPool_Pool* poolPtr) |
|
|
void lv2_rtmempool_init(LV2_RtMemPool_Pool* poolPtr) |
|
|
{ |
|
|
{ |
|
|
poolPtr->create = rtsafe_memory_pool_create; |
|
|
poolPtr->create = rtsafe_memory_pool_create; |
|
|