1*437bfbebSnyanmisaka /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2*437bfbebSnyanmisaka /*
3*437bfbebSnyanmisaka * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
4*437bfbebSnyanmisaka */
5*437bfbebSnyanmisaka
6*437bfbebSnyanmisaka #define MODULE_TAG "mpp_mem_pool"
7*437bfbebSnyanmisaka
8*437bfbebSnyanmisaka #include <string.h>
9*437bfbebSnyanmisaka
10*437bfbebSnyanmisaka #include "mpp_env.h"
11*437bfbebSnyanmisaka #include "mpp_mem.h"
12*437bfbebSnyanmisaka #include "mpp_list.h"
13*437bfbebSnyanmisaka #include "mpp_debug.h"
14*437bfbebSnyanmisaka #include "mpp_singleton.h"
15*437bfbebSnyanmisaka
16*437bfbebSnyanmisaka #include "mpp_mem_pool.h"
17*437bfbebSnyanmisaka
18*437bfbebSnyanmisaka #define MEM_POOL_DBG_FLOW (0x00000001)
19*437bfbebSnyanmisaka #define MEM_POOL_DBG_EXIT (0x00000002)
20*437bfbebSnyanmisaka
21*437bfbebSnyanmisaka #define mem_pool_dbg(flag, fmt, ...) _mpp_dbg(mpp_mem_pool_debug, flag, fmt, ## __VA_ARGS__)
22*437bfbebSnyanmisaka #define mem_pool_dbg_f(flag, fmt, ...) _mpp_dbg_f(mpp_mem_pool_debug, flag, fmt, ## __VA_ARGS__)
23*437bfbebSnyanmisaka
24*437bfbebSnyanmisaka #define mem_pool_dbg_flow(fmt, ...) mem_pool_dbg(MEM_POOL_DBG_FLOW, fmt, ## __VA_ARGS__)
25*437bfbebSnyanmisaka #define mem_pool_dbg_exit(fmt, ...) mem_pool_dbg(MEM_POOL_DBG_EXIT, fmt, ## __VA_ARGS__)
26*437bfbebSnyanmisaka
27*437bfbebSnyanmisaka #define get_srv_mem_pool(caller) \
28*437bfbebSnyanmisaka ({ \
29*437bfbebSnyanmisaka MppMemPoolSrv *__tmp; \
30*437bfbebSnyanmisaka if (!srv_mem_pool) { \
31*437bfbebSnyanmisaka mem_pool_srv_init(); \
32*437bfbebSnyanmisaka } \
33*437bfbebSnyanmisaka if (srv_mem_pool) { \
34*437bfbebSnyanmisaka __tmp = srv_mem_pool; \
35*437bfbebSnyanmisaka } else { \
36*437bfbebSnyanmisaka mpp_err("mpp mem pool srv not init at %s : %s\n", __FUNCTION__, caller); \
37*437bfbebSnyanmisaka __tmp = NULL; \
38*437bfbebSnyanmisaka } \
39*437bfbebSnyanmisaka __tmp; \
40*437bfbebSnyanmisaka })
41*437bfbebSnyanmisaka
42*437bfbebSnyanmisaka static rk_u32 mpp_mem_pool_debug = 0;
43*437bfbebSnyanmisaka
44*437bfbebSnyanmisaka /*
45*437bfbebSnyanmisaka * Aligning MppMemPoolNode to 8-byte
46*437bfbebSnyanmisaka * Avoiding alignment traps caused by compiler optimizations
47*437bfbebSnyanmisaka */
48*437bfbebSnyanmisaka typedef struct MppMemPoolNode_t {
49*437bfbebSnyanmisaka void *check;
50*437bfbebSnyanmisaka struct list_head list;
51*437bfbebSnyanmisaka void *ptr;
52*437bfbebSnyanmisaka rk_u64 size;
53*437bfbebSnyanmisaka } MppMemPoolNode;
54*437bfbebSnyanmisaka
55*437bfbebSnyanmisaka typedef struct MppMemPoolImpl_t {
56*437bfbebSnyanmisaka void *check;
57*437bfbebSnyanmisaka const char *name;
58*437bfbebSnyanmisaka size_t size;
59*437bfbebSnyanmisaka pthread_mutex_t lock;
60*437bfbebSnyanmisaka struct list_head service_link;
61*437bfbebSnyanmisaka
62*437bfbebSnyanmisaka struct list_head used;
63*437bfbebSnyanmisaka struct list_head unused;
64*437bfbebSnyanmisaka rk_s32 used_count;
65*437bfbebSnyanmisaka rk_s32 unused_count;
66*437bfbebSnyanmisaka
67*437bfbebSnyanmisaka /* extra flag for C++ static destruction order error */
68*437bfbebSnyanmisaka rk_s32 finalized;
69*437bfbebSnyanmisaka } MppMemPoolImpl;
70*437bfbebSnyanmisaka
71*437bfbebSnyanmisaka typedef struct MppMemPoolService_t {
72*437bfbebSnyanmisaka struct list_head list;
73*437bfbebSnyanmisaka pthread_mutex_t lock;
74*437bfbebSnyanmisaka } MppMemPoolSrv;
75*437bfbebSnyanmisaka
76*437bfbebSnyanmisaka static MppMemPoolSrv *srv_mem_pool = NULL;
77*437bfbebSnyanmisaka
mem_pool_srv_init()78*437bfbebSnyanmisaka static void mem_pool_srv_init()
79*437bfbebSnyanmisaka {
80*437bfbebSnyanmisaka MppMemPoolSrv *srv = srv_mem_pool;
81*437bfbebSnyanmisaka
82*437bfbebSnyanmisaka mpp_env_get_u32("mpp_mem_pool_debug", &mpp_mem_pool_debug, 0);
83*437bfbebSnyanmisaka
84*437bfbebSnyanmisaka if (srv)
85*437bfbebSnyanmisaka return;
86*437bfbebSnyanmisaka
87*437bfbebSnyanmisaka srv = mpp_malloc(MppMemPoolSrv, 1);
88*437bfbebSnyanmisaka if (!srv) {
89*437bfbebSnyanmisaka mpp_err_f("failed to allocate pool service\n");
90*437bfbebSnyanmisaka return;
91*437bfbebSnyanmisaka }
92*437bfbebSnyanmisaka
93*437bfbebSnyanmisaka srv_mem_pool = srv;
94*437bfbebSnyanmisaka
95*437bfbebSnyanmisaka {
96*437bfbebSnyanmisaka pthread_mutexattr_t attr;
97*437bfbebSnyanmisaka
98*437bfbebSnyanmisaka pthread_mutexattr_init(&attr);
99*437bfbebSnyanmisaka pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
100*437bfbebSnyanmisaka pthread_mutex_init(&srv->lock, &attr);
101*437bfbebSnyanmisaka pthread_mutexattr_destroy(&attr);
102*437bfbebSnyanmisaka }
103*437bfbebSnyanmisaka
104*437bfbebSnyanmisaka INIT_LIST_HEAD(&srv->list);
105*437bfbebSnyanmisaka }
106*437bfbebSnyanmisaka
put_pool(MppMemPoolSrv * srv,MppMemPoolImpl * impl,const char * caller)107*437bfbebSnyanmisaka static void put_pool(MppMemPoolSrv *srv, MppMemPoolImpl *impl, const char *caller)
108*437bfbebSnyanmisaka {
109*437bfbebSnyanmisaka MppMemPoolNode *node, *m;
110*437bfbebSnyanmisaka
111*437bfbebSnyanmisaka if (impl != impl->check) {
112*437bfbebSnyanmisaka mpp_err_f("invalid mem impl %p check %p at %s\n", impl, impl->check, caller);
113*437bfbebSnyanmisaka return;
114*437bfbebSnyanmisaka }
115*437bfbebSnyanmisaka
116*437bfbebSnyanmisaka if (impl->finalized)
117*437bfbebSnyanmisaka return;
118*437bfbebSnyanmisaka
119*437bfbebSnyanmisaka pthread_mutex_lock(&impl->lock);
120*437bfbebSnyanmisaka
121*437bfbebSnyanmisaka if (!list_empty(&impl->unused)) {
122*437bfbebSnyanmisaka list_for_each_entry_safe(node, m, &impl->unused, MppMemPoolNode, list) {
123*437bfbebSnyanmisaka MPP_FREE(node);
124*437bfbebSnyanmisaka impl->unused_count--;
125*437bfbebSnyanmisaka }
126*437bfbebSnyanmisaka }
127*437bfbebSnyanmisaka
128*437bfbebSnyanmisaka if (!list_empty(&impl->used)) {
129*437bfbebSnyanmisaka mpp_err_f("pool %-16s found %d used buffer size %4d at %s\n",
130*437bfbebSnyanmisaka impl->name, impl->used_count, impl->size, caller);
131*437bfbebSnyanmisaka
132*437bfbebSnyanmisaka list_for_each_entry_safe(node, m, &impl->used, MppMemPoolNode, list) {
133*437bfbebSnyanmisaka MPP_FREE(node);
134*437bfbebSnyanmisaka impl->used_count--;
135*437bfbebSnyanmisaka }
136*437bfbebSnyanmisaka }
137*437bfbebSnyanmisaka
138*437bfbebSnyanmisaka if (impl->used_count || impl->unused_count)
139*437bfbebSnyanmisaka mpp_err_f("pool %-16s size %4d found leaked buffer used:unused [%d:%d] at %s\n",
140*437bfbebSnyanmisaka impl->name, impl->size, impl->used_count, impl->unused_count, caller);
141*437bfbebSnyanmisaka
142*437bfbebSnyanmisaka pthread_mutex_unlock(&impl->lock);
143*437bfbebSnyanmisaka
144*437bfbebSnyanmisaka if (srv) {
145*437bfbebSnyanmisaka pthread_mutex_lock(&srv->lock);
146*437bfbebSnyanmisaka list_del_init(&impl->service_link);
147*437bfbebSnyanmisaka pthread_mutex_unlock(&srv->lock);
148*437bfbebSnyanmisaka }
149*437bfbebSnyanmisaka
150*437bfbebSnyanmisaka impl->finalized = 1;
151*437bfbebSnyanmisaka mpp_free(impl);
152*437bfbebSnyanmisaka }
153*437bfbebSnyanmisaka
mem_pool_srv_deinit()154*437bfbebSnyanmisaka static void mem_pool_srv_deinit()
155*437bfbebSnyanmisaka {
156*437bfbebSnyanmisaka MppMemPoolSrv *srv = srv_mem_pool;
157*437bfbebSnyanmisaka
158*437bfbebSnyanmisaka if (!srv)
159*437bfbebSnyanmisaka return;
160*437bfbebSnyanmisaka
161*437bfbebSnyanmisaka if (!list_empty(&srv->list)) {
162*437bfbebSnyanmisaka MppMemPoolImpl *pos, *n;
163*437bfbebSnyanmisaka
164*437bfbebSnyanmisaka list_for_each_entry_safe(pos, n, &srv->list, MppMemPoolImpl, service_link) {
165*437bfbebSnyanmisaka mem_pool_dbg_exit("pool %-16s size %4d leaked\n", pos->name, pos->size);
166*437bfbebSnyanmisaka put_pool(srv, pos, __FUNCTION__);
167*437bfbebSnyanmisaka }
168*437bfbebSnyanmisaka }
169*437bfbebSnyanmisaka
170*437bfbebSnyanmisaka pthread_mutex_destroy(&srv->lock);
171*437bfbebSnyanmisaka
172*437bfbebSnyanmisaka mpp_free(srv);
173*437bfbebSnyanmisaka srv_mem_pool = NULL;
174*437bfbebSnyanmisaka }
175*437bfbebSnyanmisaka
mpp_mem_pool_init(const char * name,size_t size,const char * caller)176*437bfbebSnyanmisaka MppMemPool mpp_mem_pool_init(const char *name, size_t size, const char *caller)
177*437bfbebSnyanmisaka {
178*437bfbebSnyanmisaka MppMemPoolSrv *srv = get_srv_mem_pool(caller);
179*437bfbebSnyanmisaka MppMemPoolImpl *pool;
180*437bfbebSnyanmisaka
181*437bfbebSnyanmisaka if (!srv)
182*437bfbebSnyanmisaka return NULL;
183*437bfbebSnyanmisaka
184*437bfbebSnyanmisaka pool = mpp_calloc(MppMemPoolImpl, 1);
185*437bfbebSnyanmisaka if (!pool)
186*437bfbebSnyanmisaka return NULL;
187*437bfbebSnyanmisaka
188*437bfbebSnyanmisaka {
189*437bfbebSnyanmisaka pthread_mutexattr_t attr;
190*437bfbebSnyanmisaka
191*437bfbebSnyanmisaka pthread_mutexattr_init(&attr);
192*437bfbebSnyanmisaka pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
193*437bfbebSnyanmisaka pthread_mutex_init(&pool->lock, &attr);
194*437bfbebSnyanmisaka pthread_mutexattr_destroy(&attr);
195*437bfbebSnyanmisaka }
196*437bfbebSnyanmisaka
197*437bfbebSnyanmisaka pool->check = pool;
198*437bfbebSnyanmisaka pool->name = name;
199*437bfbebSnyanmisaka pool->size = size;
200*437bfbebSnyanmisaka pool->used_count = 0;
201*437bfbebSnyanmisaka pool->unused_count = 0;
202*437bfbebSnyanmisaka pool->finalized = 0;
203*437bfbebSnyanmisaka
204*437bfbebSnyanmisaka INIT_LIST_HEAD(&pool->used);
205*437bfbebSnyanmisaka INIT_LIST_HEAD(&pool->unused);
206*437bfbebSnyanmisaka INIT_LIST_HEAD(&pool->service_link);
207*437bfbebSnyanmisaka
208*437bfbebSnyanmisaka pthread_mutex_lock(&srv->lock);
209*437bfbebSnyanmisaka list_add_tail(&pool->service_link, &srv->list);
210*437bfbebSnyanmisaka pthread_mutex_unlock(&srv->lock);
211*437bfbebSnyanmisaka
212*437bfbebSnyanmisaka mem_pool_dbg_flow("pool %-16s size %4d init at %s\n", pool->name, size, caller);
213*437bfbebSnyanmisaka
214*437bfbebSnyanmisaka return pool;
215*437bfbebSnyanmisaka }
216*437bfbebSnyanmisaka
mpp_mem_pool_deinit(MppMemPool pool,const char * caller)217*437bfbebSnyanmisaka void mpp_mem_pool_deinit(MppMemPool pool, const char *caller)
218*437bfbebSnyanmisaka {
219*437bfbebSnyanmisaka MppMemPoolSrv *srv = get_srv_mem_pool(caller);
220*437bfbebSnyanmisaka MppMemPoolImpl *impl = (MppMemPoolImpl *)pool;
221*437bfbebSnyanmisaka
222*437bfbebSnyanmisaka mem_pool_dbg_flow("pool %-16s size %4d deinit at %s\n",
223*437bfbebSnyanmisaka impl->name, impl->size, caller);
224*437bfbebSnyanmisaka
225*437bfbebSnyanmisaka put_pool(srv, impl, caller);
226*437bfbebSnyanmisaka }
227*437bfbebSnyanmisaka
mpp_mem_pool_get(MppMemPool pool,const char * caller)228*437bfbebSnyanmisaka void *mpp_mem_pool_get(MppMemPool pool, const char *caller)
229*437bfbebSnyanmisaka {
230*437bfbebSnyanmisaka MppMemPoolImpl *impl = (MppMemPoolImpl *)pool;
231*437bfbebSnyanmisaka MppMemPoolNode *node = NULL;
232*437bfbebSnyanmisaka void* ptr = NULL;
233*437bfbebSnyanmisaka
234*437bfbebSnyanmisaka pthread_mutex_lock(&impl->lock);
235*437bfbebSnyanmisaka
236*437bfbebSnyanmisaka mem_pool_dbg_flow("pool %-16s size %4d get used:unused [%d:%d] at %s\n",
237*437bfbebSnyanmisaka impl->name, impl->size, impl->used_count, impl->unused_count, caller);
238*437bfbebSnyanmisaka
239*437bfbebSnyanmisaka if (!list_empty(&impl->unused)) {
240*437bfbebSnyanmisaka node = list_first_entry(&impl->unused, MppMemPoolNode, list);
241*437bfbebSnyanmisaka if (node) {
242*437bfbebSnyanmisaka list_del_init(&node->list);
243*437bfbebSnyanmisaka list_add_tail(&node->list, &impl->used);
244*437bfbebSnyanmisaka impl->unused_count--;
245*437bfbebSnyanmisaka impl->used_count++;
246*437bfbebSnyanmisaka ptr = node->ptr;
247*437bfbebSnyanmisaka node->check = node;
248*437bfbebSnyanmisaka goto DONE;
249*437bfbebSnyanmisaka }
250*437bfbebSnyanmisaka }
251*437bfbebSnyanmisaka
252*437bfbebSnyanmisaka node = mpp_malloc_size(MppMemPoolNode, sizeof(MppMemPoolNode) + impl->size);
253*437bfbebSnyanmisaka if (!node) {
254*437bfbebSnyanmisaka mpp_err_f("failed to create node from size %4d pool\n", impl->size);
255*437bfbebSnyanmisaka goto DONE;
256*437bfbebSnyanmisaka }
257*437bfbebSnyanmisaka
258*437bfbebSnyanmisaka node->check = node;
259*437bfbebSnyanmisaka node->ptr = (void *)(node + 1);
260*437bfbebSnyanmisaka node->size = impl->size;
261*437bfbebSnyanmisaka INIT_LIST_HEAD(&node->list);
262*437bfbebSnyanmisaka list_add_tail(&node->list, &impl->used);
263*437bfbebSnyanmisaka impl->used_count++;
264*437bfbebSnyanmisaka ptr = node->ptr;
265*437bfbebSnyanmisaka
266*437bfbebSnyanmisaka DONE:
267*437bfbebSnyanmisaka pthread_mutex_unlock(&impl->lock);
268*437bfbebSnyanmisaka if (node)
269*437bfbebSnyanmisaka memset(node->ptr, 0 , node->size);
270*437bfbebSnyanmisaka return ptr;
271*437bfbebSnyanmisaka }
272*437bfbebSnyanmisaka
mpp_mem_pool_put(MppMemPool pool,void * p,const char * caller)273*437bfbebSnyanmisaka void mpp_mem_pool_put(MppMemPool pool, void *p, const char *caller)
274*437bfbebSnyanmisaka {
275*437bfbebSnyanmisaka MppMemPoolImpl *impl = (MppMemPoolImpl *)pool;
276*437bfbebSnyanmisaka MppMemPoolNode *node = (MppMemPoolNode *)((rk_u8 *)p - sizeof(MppMemPoolNode));
277*437bfbebSnyanmisaka
278*437bfbebSnyanmisaka if (impl != impl->check) {
279*437bfbebSnyanmisaka mpp_err_f("invalid mem pool %p check %p\n", impl, impl->check);
280*437bfbebSnyanmisaka return ;
281*437bfbebSnyanmisaka }
282*437bfbebSnyanmisaka
283*437bfbebSnyanmisaka if (node != node->check) {
284*437bfbebSnyanmisaka mpp_err_f("invalid mem pool ptr %p node %p check %p\n",
285*437bfbebSnyanmisaka p, node, node->check);
286*437bfbebSnyanmisaka return ;
287*437bfbebSnyanmisaka }
288*437bfbebSnyanmisaka
289*437bfbebSnyanmisaka pthread_mutex_lock(&impl->lock);
290*437bfbebSnyanmisaka
291*437bfbebSnyanmisaka mem_pool_dbg_flow("pool %-16s size %4d put used:unused [%d:%d] at %s\n",
292*437bfbebSnyanmisaka impl->name, impl->size, impl->used_count, impl->unused_count, caller);
293*437bfbebSnyanmisaka
294*437bfbebSnyanmisaka list_del_init(&node->list);
295*437bfbebSnyanmisaka list_add(&node->list, &impl->unused);
296*437bfbebSnyanmisaka impl->used_count--;
297*437bfbebSnyanmisaka impl->unused_count++;
298*437bfbebSnyanmisaka node->check = NULL;
299*437bfbebSnyanmisaka
300*437bfbebSnyanmisaka pthread_mutex_unlock(&impl->lock);
301*437bfbebSnyanmisaka }
302*437bfbebSnyanmisaka
303*437bfbebSnyanmisaka MPP_SINGLETON(MPP_SGLN_MEM_POOL, mpp_mem_pool, mem_pool_srv_init, mem_pool_srv_deinit)
304