/*
|
* Copyright 2021 Rockchip Electronics Co. LTD
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
#define MODULE_TAG "mpp_mem_pool"
|
|
#include <string.h>
|
|
#include "mpp_err.h"
|
#include "mpp_env.h"
|
#include "mpp_mem.h"
|
#include "mpp_list.h"
|
#include "mpp_debug.h"
|
|
#include "mpp_mem_pool.h"
|
|
#define MPP_MEM_POOL_DBG_FLOW (0x00000001)
|
|
#define mem_pool_dbg(flag, fmt, ...) _mpp_dbg(mpp_mem_pool_debug, flag, fmt, ## __VA_ARGS__)
|
#define mem_pool_dbg_f(flag, fmt, ...) _mpp_dbg_f(mpp_mem_pool_debug, flag, fmt, ## __VA_ARGS__)
|
|
#define mem_pool_dbg_flow(fmt, ...) mem_pool_dbg(MPP_MEM_POOL_DBG_FLOW, fmt, ## __VA_ARGS__)
|
|
RK_U32 mpp_mem_pool_debug = 0;
|
|
typedef struct MppMemPoolNode_t {
|
void *check;
|
struct list_head list;
|
void *ptr;
|
size_t size;
|
} MppMemPoolNode;
|
|
typedef struct MppMemPoolImpl_t {
|
void *check;
|
size_t size;
|
pthread_mutex_t lock;
|
struct list_head service_link;
|
|
struct list_head used;
|
struct list_head unused;
|
RK_S32 used_count;
|
RK_S32 unused_count;
|
} MppMemPoolImpl;
|
|
class MppMemPoolService
|
{
|
public:
|
static MppMemPoolService* getInstance() {
|
AutoMutex auto_lock(get_lock());
|
static MppMemPoolService pool_service;
|
return &pool_service;
|
}
|
static Mutex *get_lock() {
|
static Mutex lock;
|
return &lock;
|
}
|
|
MppMemPoolImpl *get_pool(size_t size);
|
void put_pool(MppMemPoolImpl *impl);
|
|
private:
|
MppMemPoolService();
|
~MppMemPoolService();
|
struct list_head mLink;
|
};
|
|
MppMemPoolService::MppMemPoolService()
|
{
|
INIT_LIST_HEAD(&mLink);
|
|
mpp_env_get_u32("mpp_mem_pool_debug", &mpp_mem_pool_debug, 0);
|
}
|
|
MppMemPoolService::~MppMemPoolService()
|
{
|
if (!list_empty(&mLink)) {
|
MppMemPoolImpl *pos, *n;
|
|
list_for_each_entry_safe(pos, n, &mLink, MppMemPoolImpl, service_link) {
|
put_pool(pos);
|
}
|
}
|
}
|
|
MppMemPoolImpl *MppMemPoolService::get_pool(size_t size)
|
{
|
MppMemPoolImpl *pool = mpp_malloc(MppMemPoolImpl, 1);
|
if (NULL == pool)
|
return NULL;
|
|
pthread_mutexattr_t attr;
|
pthread_mutexattr_init(&attr);
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
pthread_mutex_init(&pool->lock, &attr);
|
pthread_mutexattr_destroy(&attr);
|
|
pool->check = pool;
|
pool->size = size;
|
pool->used_count = 0;
|
pool->unused_count = 0;
|
|
INIT_LIST_HEAD(&pool->used);
|
INIT_LIST_HEAD(&pool->unused);
|
INIT_LIST_HEAD(&pool->service_link);
|
AutoMutex auto_lock(get_lock());
|
list_add_tail(&pool->service_link, &mLink);
|
|
return pool;
|
}
|
|
void MppMemPoolService::put_pool(MppMemPoolImpl *impl)
|
{
|
MppMemPoolNode *node, *m;
|
|
if (impl != impl->check) {
|
mpp_err_f("invalid mem impl %p check %p\n", impl, impl->check);
|
return ;
|
}
|
|
if (!list_empty(&impl->unused)) {
|
list_for_each_entry_safe(node, m, &impl->unused, MppMemPoolNode, list) {
|
MPP_FREE(node);
|
impl->unused_count--;
|
}
|
}
|
|
if (!list_empty(&impl->used)) {
|
mpp_err_f("found %d used buffer size %d\n",
|
impl->used_count, impl->size);
|
|
list_for_each_entry_safe(node, m, &impl->used, MppMemPoolNode, list) {
|
MPP_FREE(node);
|
impl->used_count--;
|
}
|
}
|
|
mpp_assert(!impl->used_count);
|
mpp_assert(!impl->unused_count);
|
|
{
|
AutoMutex auto_lock(get_lock());
|
list_del_init(&impl->service_link);
|
}
|
|
mpp_free(impl);
|
}
|
|
MppMemPool mpp_mem_pool_init_f(const char *caller, size_t size)
|
{
|
mem_pool_dbg_flow("pool %d init from %s", size, caller);
|
|
return (MppMemPool)MppMemPoolService::getInstance()->get_pool(size);
|
}
|
|
void mpp_mem_pool_deinit_f(const char *caller, MppMemPool pool)
|
{
|
MppMemPoolImpl *impl = (MppMemPoolImpl *)pool;
|
|
mem_pool_dbg_flow("pool %d deinit from %s", impl->size, caller);
|
|
MppMemPoolService::getInstance()->put_pool(impl);
|
}
|
|
void *mpp_mem_pool_get_f(const char *caller, MppMemPool pool)
|
{
|
MppMemPoolImpl *impl = (MppMemPoolImpl *)pool;
|
MppMemPoolNode *node = NULL;
|
void* ptr = NULL;
|
|
pthread_mutex_lock(&impl->lock);
|
|
mem_pool_dbg_flow("pool %d get used:unused [%d:%d] from %s", impl->size,
|
impl->used_count, impl->unused_count, caller);
|
|
if (!list_empty(&impl->unused)) {
|
node = list_first_entry(&impl->unused, MppMemPoolNode, list);
|
if (node) {
|
list_del_init(&node->list);
|
list_add_tail(&node->list, &impl->used);
|
impl->unused_count--;
|
impl->used_count++;
|
ptr = node->ptr;
|
goto DONE;
|
}
|
}
|
|
node = mpp_malloc_size(MppMemPoolNode, sizeof(MppMemPoolNode) + impl->size);
|
if (NULL == node) {
|
mpp_err_f("failed to create node from size %d pool\n", impl->size);
|
goto DONE;
|
}
|
|
node->check = node;
|
node->ptr = (void *)(node + 1);
|
node->size = impl->size;
|
INIT_LIST_HEAD(&node->list);
|
list_add_tail(&node->list, &impl->used);
|
impl->used_count++;
|
ptr = node->ptr;
|
|
DONE:
|
pthread_mutex_unlock(&impl->lock);
|
if (node)
|
memset(node->ptr, 0 , node->size);
|
return ptr;
|
}
|
|
void mpp_mem_pool_put_f(const char *caller, MppMemPool pool, void *p)
|
{
|
MppMemPoolImpl *impl = (MppMemPoolImpl *)pool;
|
MppMemPoolNode *node = (MppMemPoolNode *)((RK_U8 *)p - sizeof(MppMemPoolNode));
|
|
if (impl != impl->check) {
|
mpp_err_f("invalid mem pool %p check %p\n", impl, impl->check);
|
return ;
|
}
|
|
if (node != node->check) {
|
mpp_err_f("invalid mem pool ptr %p node %p check %p\n",
|
p, node, node->check);
|
return ;
|
}
|
|
pthread_mutex_lock(&impl->lock);
|
|
mem_pool_dbg_flow("pool %d put used:unused [%d:%d] from %s", impl->size,
|
impl->used_count, impl->unused_count, caller);
|
|
list_del_init(&node->list);
|
list_add(&node->list, &impl->unused);
|
impl->used_count--;
|
impl->unused_count++;
|
|
pthread_mutex_unlock(&impl->lock);
|
}
|