xref: /rockchip-linux_mpp/osal/mpp_mem_pool.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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