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