xref: /OK3568_Linux_fs/external/mpp/osal/mpp_mem_pool.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2021 Rockchip Electronics Co. LTD
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Licensed under the Apache License, Version 2.0 (the "License");
5*4882a593Smuzhiyun  * you may not use this file except in compliance with the License.
6*4882a593Smuzhiyun  * You may obtain a copy of the License at
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *      http://www.apache.org/licenses/LICENSE-2.0
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Unless required by applicable law or agreed to in writing, software
11*4882a593Smuzhiyun  * distributed under the License is distributed on an "AS IS" BASIS,
12*4882a593Smuzhiyun  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4882a593Smuzhiyun  * See the License for the specific language governing permissions and
14*4882a593Smuzhiyun  * limitations under the License.
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define MODULE_TAG "mpp_mem_pool"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <string.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include "mpp_err.h"
22*4882a593Smuzhiyun #include "mpp_env.h"
23*4882a593Smuzhiyun #include "mpp_mem.h"
24*4882a593Smuzhiyun #include "mpp_list.h"
25*4882a593Smuzhiyun #include "mpp_debug.h"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "mpp_mem_pool.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define MPP_MEM_POOL_DBG_FLOW           (0x00000001)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define mem_pool_dbg(flag, fmt, ...)    _mpp_dbg(mpp_mem_pool_debug, flag, fmt, ## __VA_ARGS__)
32*4882a593Smuzhiyun #define mem_pool_dbg_f(flag, fmt, ...)  _mpp_dbg_f(mpp_mem_pool_debug, flag, fmt, ## __VA_ARGS__)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define mem_pool_dbg_flow(fmt, ...)     mem_pool_dbg(MPP_MEM_POOL_DBG_FLOW, fmt, ## __VA_ARGS__)
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun RK_U32 mpp_mem_pool_debug = 0;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun typedef struct MppMemPoolNode_t {
39*4882a593Smuzhiyun     void                *check;
40*4882a593Smuzhiyun     struct list_head    list;
41*4882a593Smuzhiyun     void                *ptr;
42*4882a593Smuzhiyun     size_t              size;
43*4882a593Smuzhiyun } MppMemPoolNode;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun typedef struct MppMemPoolImpl_t {
46*4882a593Smuzhiyun     void                *check;
47*4882a593Smuzhiyun     size_t              size;
48*4882a593Smuzhiyun     pthread_mutex_t     lock;
49*4882a593Smuzhiyun     struct list_head    service_link;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun     struct list_head    used;
52*4882a593Smuzhiyun     struct list_head    unused;
53*4882a593Smuzhiyun     RK_S32              used_count;
54*4882a593Smuzhiyun     RK_S32              unused_count;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun     /* extra flag for C++ static destruction order error */
57*4882a593Smuzhiyun     RK_S32              finalized;
58*4882a593Smuzhiyun } MppMemPoolImpl;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun class MppMemPoolService
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun public:
getInstance()63*4882a593Smuzhiyun     static MppMemPoolService* getInstance() {
64*4882a593Smuzhiyun         AutoMutex auto_lock(get_lock());
65*4882a593Smuzhiyun         static MppMemPoolService pool_service;
66*4882a593Smuzhiyun         return &pool_service;
67*4882a593Smuzhiyun     }
get_lock()68*4882a593Smuzhiyun     static Mutex *get_lock() {
69*4882a593Smuzhiyun         static Mutex lock;
70*4882a593Smuzhiyun         return &lock;
71*4882a593Smuzhiyun     }
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun     MppMemPoolImpl *get_pool(size_t size);
74*4882a593Smuzhiyun     void put_pool(MppMemPoolImpl *impl);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun private:
77*4882a593Smuzhiyun     MppMemPoolService();
78*4882a593Smuzhiyun     ~MppMemPoolService();
79*4882a593Smuzhiyun     struct list_head    mLink;
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun 
MppMemPoolService()82*4882a593Smuzhiyun MppMemPoolService::MppMemPoolService()
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun     INIT_LIST_HEAD(&mLink);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun     mpp_env_get_u32("mpp_mem_pool_debug", &mpp_mem_pool_debug, 0);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
~MppMemPoolService()89*4882a593Smuzhiyun MppMemPoolService::~MppMemPoolService()
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun     if (!list_empty(&mLink)) {
92*4882a593Smuzhiyun         MppMemPoolImpl *pos, *n;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun         list_for_each_entry_safe(pos, n, &mLink, MppMemPoolImpl, service_link) {
95*4882a593Smuzhiyun             put_pool(pos);
96*4882a593Smuzhiyun         }
97*4882a593Smuzhiyun     }
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
get_pool(size_t size)100*4882a593Smuzhiyun MppMemPoolImpl *MppMemPoolService::get_pool(size_t size)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun     MppMemPoolImpl *pool = mpp_malloc(MppMemPoolImpl, 1);
103*4882a593Smuzhiyun     if (NULL == pool)
104*4882a593Smuzhiyun         return NULL;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun     pthread_mutexattr_t attr;
107*4882a593Smuzhiyun     pthread_mutexattr_init(&attr);
108*4882a593Smuzhiyun     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
109*4882a593Smuzhiyun     pthread_mutex_init(&pool->lock, &attr);
110*4882a593Smuzhiyun     pthread_mutexattr_destroy(&attr);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun     pool->check = pool;
113*4882a593Smuzhiyun     pool->size = size;
114*4882a593Smuzhiyun     pool->used_count = 0;
115*4882a593Smuzhiyun     pool->unused_count = 0;
116*4882a593Smuzhiyun     pool->finalized = 0;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun     INIT_LIST_HEAD(&pool->used);
119*4882a593Smuzhiyun     INIT_LIST_HEAD(&pool->unused);
120*4882a593Smuzhiyun     INIT_LIST_HEAD(&pool->service_link);
121*4882a593Smuzhiyun     AutoMutex auto_lock(get_lock());
122*4882a593Smuzhiyun     list_add_tail(&pool->service_link, &mLink);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun     return pool;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
put_pool(MppMemPoolImpl * impl)127*4882a593Smuzhiyun void MppMemPoolService::put_pool(MppMemPoolImpl *impl)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun     MppMemPoolNode *node, *m;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun     if (impl != impl->check) {
132*4882a593Smuzhiyun         mpp_err_f("invalid mem impl %p check %p\n", impl, impl->check);
133*4882a593Smuzhiyun         return;
134*4882a593Smuzhiyun     }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun     if (impl->finalized)
137*4882a593Smuzhiyun         return;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun     pthread_mutex_lock(&impl->lock);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun     if (!list_empty(&impl->unused)) {
142*4882a593Smuzhiyun         list_for_each_entry_safe(node, m, &impl->unused, MppMemPoolNode, list) {
143*4882a593Smuzhiyun             MPP_FREE(node);
144*4882a593Smuzhiyun             impl->unused_count--;
145*4882a593Smuzhiyun         }
146*4882a593Smuzhiyun     }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun     if (!list_empty(&impl->used)) {
149*4882a593Smuzhiyun         mpp_err_f("found %d used buffer size %d\n",
150*4882a593Smuzhiyun                   impl->used_count, impl->size);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun         list_for_each_entry_safe(node, m, &impl->used, MppMemPoolNode, list) {
153*4882a593Smuzhiyun             MPP_FREE(node);
154*4882a593Smuzhiyun             impl->used_count--;
155*4882a593Smuzhiyun         }
156*4882a593Smuzhiyun     }
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun     if (impl->used_count || impl->unused_count)
159*4882a593Smuzhiyun         mpp_err_f("pool size %d found leaked buffer used:unused [%d:%d]\n",
160*4882a593Smuzhiyun                   impl->size, impl->used_count, impl->unused_count);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun     pthread_mutex_unlock(&impl->lock);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun     {
165*4882a593Smuzhiyun         AutoMutex auto_lock(get_lock());
166*4882a593Smuzhiyun         list_del_init(&impl->service_link);
167*4882a593Smuzhiyun     }
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun     impl->finalized = 1;
170*4882a593Smuzhiyun     mpp_free(impl);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
mpp_mem_pool_init_f(const char * caller,size_t size)173*4882a593Smuzhiyun MppMemPool mpp_mem_pool_init_f(const char *caller, size_t size)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun     mem_pool_dbg_flow("pool %d init from %s", size, caller);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun     return (MppMemPool)MppMemPoolService::getInstance()->get_pool(size);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
mpp_mem_pool_deinit_f(const char * caller,MppMemPool pool)180*4882a593Smuzhiyun void mpp_mem_pool_deinit_f(const char *caller, MppMemPool pool)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun     MppMemPoolImpl *impl = (MppMemPoolImpl *)pool;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun     mem_pool_dbg_flow("pool %d deinit from %s", impl->size, caller);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun     MppMemPoolService::getInstance()->put_pool(impl);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
mpp_mem_pool_get_f(const char * caller,MppMemPool pool)189*4882a593Smuzhiyun void *mpp_mem_pool_get_f(const char *caller, MppMemPool pool)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun     MppMemPoolImpl *impl = (MppMemPoolImpl *)pool;
192*4882a593Smuzhiyun     MppMemPoolNode *node = NULL;
193*4882a593Smuzhiyun     void* ptr = NULL;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun     pthread_mutex_lock(&impl->lock);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun     mem_pool_dbg_flow("pool %d get used:unused [%d:%d] from %s", impl->size,
198*4882a593Smuzhiyun                       impl->used_count, impl->unused_count, caller);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun     if (!list_empty(&impl->unused)) {
201*4882a593Smuzhiyun         node = list_first_entry(&impl->unused, MppMemPoolNode, list);
202*4882a593Smuzhiyun         if (node) {
203*4882a593Smuzhiyun             list_del_init(&node->list);
204*4882a593Smuzhiyun             list_add_tail(&node->list, &impl->used);
205*4882a593Smuzhiyun             impl->unused_count--;
206*4882a593Smuzhiyun             impl->used_count++;
207*4882a593Smuzhiyun             ptr = node->ptr;
208*4882a593Smuzhiyun             node->check = node;
209*4882a593Smuzhiyun             goto DONE;
210*4882a593Smuzhiyun         }
211*4882a593Smuzhiyun     }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun     node = mpp_malloc_size(MppMemPoolNode, sizeof(MppMemPoolNode) + impl->size);
214*4882a593Smuzhiyun     if (NULL == node) {
215*4882a593Smuzhiyun         mpp_err_f("failed to create node from size %d pool\n", impl->size);
216*4882a593Smuzhiyun         goto DONE;
217*4882a593Smuzhiyun     }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun     node->check = node;
220*4882a593Smuzhiyun     node->ptr = (void *)(node + 1);
221*4882a593Smuzhiyun     node->size = impl->size;
222*4882a593Smuzhiyun     INIT_LIST_HEAD(&node->list);
223*4882a593Smuzhiyun     list_add_tail(&node->list, &impl->used);
224*4882a593Smuzhiyun     impl->used_count++;
225*4882a593Smuzhiyun     ptr = node->ptr;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun DONE:
228*4882a593Smuzhiyun     pthread_mutex_unlock(&impl->lock);
229*4882a593Smuzhiyun     if (node)
230*4882a593Smuzhiyun         memset(node->ptr, 0 , node->size);
231*4882a593Smuzhiyun     return ptr;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
mpp_mem_pool_put_f(const char * caller,MppMemPool pool,void * p)234*4882a593Smuzhiyun void mpp_mem_pool_put_f(const char *caller, MppMemPool pool, void *p)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun     MppMemPoolImpl *impl = (MppMemPoolImpl *)pool;
237*4882a593Smuzhiyun     MppMemPoolNode *node = (MppMemPoolNode *)((RK_U8 *)p - sizeof(MppMemPoolNode));
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun     if (impl != impl->check) {
240*4882a593Smuzhiyun         mpp_err_f("invalid mem pool %p check %p\n", impl, impl->check);
241*4882a593Smuzhiyun         return ;
242*4882a593Smuzhiyun     }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun     if (node != node->check) {
245*4882a593Smuzhiyun         mpp_err_f("invalid mem pool ptr %p node %p check %p\n",
246*4882a593Smuzhiyun                   p, node, node->check);
247*4882a593Smuzhiyun         return ;
248*4882a593Smuzhiyun     }
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun     pthread_mutex_lock(&impl->lock);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun     mem_pool_dbg_flow("pool %d put used:unused [%d:%d] from %s", impl->size,
253*4882a593Smuzhiyun                       impl->used_count, impl->unused_count, caller);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun     list_del_init(&node->list);
256*4882a593Smuzhiyun     list_add(&node->list, &impl->unused);
257*4882a593Smuzhiyun     impl->used_count--;
258*4882a593Smuzhiyun     impl->unused_count++;
259*4882a593Smuzhiyun     node->check = NULL;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun     pthread_mutex_unlock(&impl->lock);
262*4882a593Smuzhiyun }
263