mirror of
https://github.com/nyanmisaka/mpp.git
synced 2025-09-27 13:32:09 +08:00

When another C++ static global object init before the mpp_mem service the MppService service will be inited twice. Then on object destroy will deinit service twice and cause mutex double delete issue. On init E mpp_mem : MppMemService start 0 0x7c536619e8 I mpp_mem : MppMemService mpp_mem_debug enabled 3 max node 1024 E mpp_mem : MppMemService start 1 0x5e8d724230 I mpp_mem : MppMemService mpp_mem_debug enabled 3 max node 1024 On destory 05-17 09:58:04.743 2576 2576 E mpp_mem : ~MppMemService enter 0 0x5e8d724230 05-17 09:58:04.743 2576 2576 E mpp_mem : ~MppMemService enter 1 0x7c536619e8 05-17 09:58:04.743 2576 2576 E mpp_mem : mpp_osal_free *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** Build fingerprint: 'rockchip/rk3576_t/rk3576_t:13/TQ3C.230805.001.B2/eng.kenjc.20240510.161710:userdebug/release-keys' Revision: '0' ABI: 'arm64' Timestamp: 2024-05-17 09:58:04.800905936+0000 Process uptime: 1s Cmdline: mpp_trie_test pid: 2576, tid: 2576, name: mpp_trie_test >>> mpp_trie_test <<< uid: 0 tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE) signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr -------- Abort message: 'FORTIFY: pthread_mutex_lock called on a destroyed mutex (0x5e8d724230)' x0 0000000000000000 x1 0000000000000a10 x2 0000000000000006 x3 0000007fd26f05d0 x4 0000000000008080 x5 0000000000008080 x6 0000000000008080 x7 8080000000000000 x8 00000000000000f0 x9 0000007c50d22a00 x10 0000000000000001 x11 0000007c50d60de4 x12 0101010101010101 x13 000000007fffffff x14 000000000001ffea x15 0000000000000078 x16 0000007c50dc5d58 x17 0000007c50da2c70 x18 0000007c55b38000 x19 0000000000000a10 x20 0000000000000a10 x21 00000000ffffffff x22 0000000000001000 x23 0000005e8d724230 x24 0000007c5489e010 x25 0000005e8d70c060 x26 0000000000000002 x27 0000007c513226e8 x28 0000000000000000 x29 0000007fd26f0650 lr 0000007c50d52968 sp 0000007fd26f05b0 pc 0000007c50d52994 pst 0000000000000000 backtrace: #00 pc 0000000000051994 /apex/com.android.runtime/lib64/bionic/libc.so (abort+164) (BuildId: 4e07915368c859b1910c68c84a8de75f) #01 pc 000000000005363c /apex/com.android.runtime/lib64/bionic/libc.so (__fortify_fatal(char const*, ...)+124) (BuildId: 4e07915368c859b1910c68c84a8de75f) #02 pc 00000000000b74cc /apex/com.android.runtime/lib64/bionic/libc.so (HandleUsingDestroyedMutex(pthread_mutex_t*, char const*)+60) (BuildId: 4e07915368c859b1910c68c84a8de75f) #03 pc 00000000000b735c /apex/com.android.runtime/lib64/bionic/libc.so (pthread_mutex_lock+240) (BuildId: 4e07915368c859b1910c68c84a8de75f) #04 pc 0000000000048290 /system/bin/mpp_trie_test (mpp_osal_free+108) (BuildId: 55dca41ecc701b3ad16f0ef02270a45ce40533ff) #05 pc 0000000000041080 /system/bin/mpp_trie_test (MppMemPoolService::~MppMemPoolService()+32) (BuildId: 55dca41ecc701b3ad16f0ef02270a45ce40533ff) #06 pc 00000000000b9ca4 /apex/com.android.runtime/lib64/bionic/libc.so (__cxa_finalize+280) (BuildId: 4e07915368c859b1910c68c84a8de75f) #07 pc 00000000000ac944 /apex/com.android.runtime/lib64/bionic/libc.so (exit+24) (BuildId: 4e07915368c859b1910c68c84a8de75f) #08 pc 000000000004a1f8 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+100) (BuildId: 4e07915368c859b1910c68c84a8de75f) Signed-off-by: Herman Chen <herman.chen@rock-chips.com> Change-Id: I81ead0f796ba6e26b520a87ae69cc8f7f6e816f4
785 lines
21 KiB
C++
785 lines
21 KiB
C++
/*
|
|
* Copyright 2015 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"
|
|
|
|
#include <string.h>
|
|
|
|
#include "mpp_env.h"
|
|
#include "mpp_mem.h"
|
|
#include "mpp_list.h"
|
|
#include "mpp_debug.h"
|
|
#include "mpp_common.h"
|
|
|
|
#include "os_mem.h"
|
|
|
|
// mpp_mem_debug bit mask
|
|
#define MEM_DEBUG_EN (0x00000001)
|
|
// NOTE: runtime log need debug enable
|
|
#define MEM_RUNTIME_LOG (0x00000002)
|
|
#define MEM_NODE_LOG (0x00000004)
|
|
#define MEM_EXT_ROOM (0x00000010)
|
|
#define MEM_POISON (0x00000020)
|
|
|
|
// default memory align size is set to 32
|
|
#define MEM_MAX_INDEX (0x7fffffff)
|
|
#define MEM_ALIGN 32
|
|
#define MEM_ALIGN_MASK (MEM_ALIGN - 1)
|
|
#define MEM_ALIGNED(x) (((x) + MEM_ALIGN_MASK) & (~MEM_ALIGN_MASK))
|
|
#define MEM_HEAD_ROOM(debug) ((debug & MEM_EXT_ROOM) ? (MEM_ALIGN) : (0))
|
|
#define MEM_NODE_MAX (1024)
|
|
#define MEM_FREE_MAX (512)
|
|
#define MEM_LOG_MAX (1024)
|
|
#define MEM_CHECK_MARK (0xdd)
|
|
#define MEM_HEAD_MASK (0xab)
|
|
#define MEM_TAIL_MASK (0xcd)
|
|
|
|
#define MPP_MEM_ASSERT(cond) \
|
|
do { \
|
|
if (!(cond)) { \
|
|
mpp_err("found mpp_mem assert failed, start dumping:\n"); \
|
|
MppMemService::get_inst()->dump(__FUNCTION__); \
|
|
mpp_assert(cond); \
|
|
} \
|
|
} while (0)
|
|
|
|
typedef enum MppMemOps_e {
|
|
MEM_MALLOC,
|
|
MEM_REALLOC,
|
|
MEM_FREE,
|
|
MEM_FREE_DELAY,
|
|
|
|
MEM_OPS_BUTT,
|
|
} MppMemOps;
|
|
|
|
/*
|
|
* Here we combined valid flag with index value to keep node structure small
|
|
* If index >= 0 this node is valid otherwise it is invalid
|
|
* When we need to invalid one index use ~ to revert all bit
|
|
* Then max valid index is 0x7fffffff. When index goes beyond it and becomes
|
|
* negative value index will be reset to zero.
|
|
*/
|
|
typedef struct MppMemNode_s {
|
|
RK_S32 index;
|
|
size_t size;
|
|
void *ptr;
|
|
const char *caller;
|
|
} MppMemNode;
|
|
|
|
typedef struct MppMemLog_s {
|
|
RK_U32 index;
|
|
MppMemOps ops;
|
|
size_t size_0; // size at input
|
|
size_t size_1; // size at output
|
|
void *ptr; // ptr at input
|
|
void *ret; // ptr at output
|
|
MppMemNode *node; // node for operation
|
|
const char *caller;
|
|
} MppMemLog;
|
|
|
|
class MppMemService
|
|
{
|
|
public:
|
|
static MppMemService *get_inst() {
|
|
static MppMemService instance;
|
|
return &instance;
|
|
}
|
|
|
|
void add_node(const char *caller, void *ptr, size_t size);
|
|
/*
|
|
* try delete node will return index in nodes
|
|
* return 1 for need os_free call to real free
|
|
* return 0 for reserve memory for check
|
|
*/
|
|
RK_S32 find_node(const char *caller, void *ptr, size_t *size, RK_S32 *idx);
|
|
/*
|
|
*/
|
|
void del_node(const char *caller, void *ptr, size_t *size);
|
|
void* delay_del_node(const char *caller, void *ptr, size_t *size);
|
|
void reset_node(const char *caller, void *ptr, void *ret, size_t size);
|
|
|
|
void chk_node(const char *caller, MppMemNode *node);
|
|
void chk_mem(const char *caller, void *ptr, size_t size);
|
|
RK_S32 chk_poison(MppMemNode *node);
|
|
|
|
void add_log(MppMemOps ops, const char *caller, void *ptr, void *ret,
|
|
size_t size_0, size_t size_1);
|
|
|
|
void dump(const char *caller);
|
|
RK_U32 total_now(void) { return m_total_size; }
|
|
RK_U32 total_max(void) { return m_total_max; }
|
|
|
|
Mutex *m_lock;
|
|
RK_U32 debug;
|
|
|
|
private:
|
|
// avoid any unwanted function
|
|
MppMemService();
|
|
~MppMemService();
|
|
MppMemService(const MppMemService &);
|
|
MppMemService &operator=(const MppMemService &);
|
|
|
|
// data for node record and delay free check
|
|
RK_S32 nodes_max;
|
|
RK_S32 nodes_idx;
|
|
RK_S32 nodes_cnt;
|
|
RK_S32 frees_max;
|
|
RK_S32 frees_idx;
|
|
RK_S32 frees_cnt;
|
|
|
|
MppMemNode *nodes;
|
|
MppMemNode *frees;
|
|
|
|
// data for log record
|
|
RK_U32 log_index;
|
|
RK_S32 log_max;
|
|
RK_S32 log_idx;
|
|
RK_S32 log_cnt;
|
|
|
|
MppMemLog *logs;
|
|
RK_U32 m_total_size;
|
|
RK_U32 m_total_max;
|
|
};
|
|
|
|
static const char *ops2str[MEM_OPS_BUTT] = {
|
|
"malloc",
|
|
"realloc",
|
|
"free",
|
|
"delayed",
|
|
};
|
|
|
|
static void show_mem(RK_U32 *buf, RK_S32 size)
|
|
{
|
|
mpp_err("dumping buf %p size %d start\n", buf, size);
|
|
while (size > 0) {
|
|
if (size >= 16) {
|
|
mpp_err("%08x %08x %08x %08x\n", buf[0], buf[1], buf[2], buf[3]);
|
|
buf += 4;
|
|
size -= 16;
|
|
} else if (size >= 12) {
|
|
mpp_err("%08x %08x %08x\n", buf[0], buf[1], buf[2]);
|
|
buf += 3;
|
|
size -= 12;
|
|
} else if (size >= 8) {
|
|
mpp_err("%08x %08x\n", buf[0], buf[1]);
|
|
buf += 2;
|
|
size -= 8;
|
|
} else if (size >= 4) {
|
|
mpp_err("%08x\n", buf[0]);
|
|
buf += 1;
|
|
size -= 4;
|
|
} else {
|
|
mpp_log("end with size %d\n", size);
|
|
break;
|
|
}
|
|
}
|
|
mpp_err("dumping buf %p size %d end\n", buf, size);
|
|
}
|
|
|
|
static void set_mem_ext_room(void *p, size_t size)
|
|
{
|
|
memset((RK_U8 *)p - MEM_ALIGN, MEM_HEAD_MASK, MEM_ALIGN);
|
|
memset((RK_U8 *)p + size, MEM_TAIL_MASK, MEM_ALIGN);
|
|
}
|
|
|
|
MppMemService::MppMemService()
|
|
: debug(0),
|
|
nodes_max(MEM_NODE_MAX),
|
|
nodes_idx(0),
|
|
nodes_cnt(0),
|
|
frees_max(MEM_FREE_MAX),
|
|
frees_idx(0),
|
|
frees_cnt(0),
|
|
nodes(NULL),
|
|
frees(NULL),
|
|
log_index(0),
|
|
log_max(MEM_LOG_MAX),
|
|
log_idx(0),
|
|
log_cnt(0),
|
|
logs(NULL),
|
|
m_total_size(0),
|
|
m_total_max(0)
|
|
{
|
|
mpp_env_get_u32("mpp_mem_debug", &debug, 0);
|
|
|
|
m_lock = new Mutex();
|
|
|
|
// add more flag if debug enabled
|
|
if (debug)
|
|
debug |= MEM_DEBUG_EN;
|
|
|
|
if (debug & MEM_DEBUG_EN) {
|
|
mpp_env_get_u32("mpp_mem_node_max", (RK_U32 *)&nodes_max, MEM_NODE_MAX);
|
|
|
|
mpp_log_f("mpp_mem_debug enabled %x max node %d\n",
|
|
debug, nodes_max);
|
|
|
|
size_t size = nodes_max * sizeof(MppMemNode);
|
|
os_malloc((void **)&nodes, MEM_ALIGN, size);
|
|
mpp_assert(nodes);
|
|
memset(nodes, 0xff, size);
|
|
add_node(__FUNCTION__, nodes, size);
|
|
|
|
size = frees_max * sizeof(MppMemNode);
|
|
os_malloc((void **)&frees, MEM_ALIGN, size);
|
|
mpp_assert(frees);
|
|
memset(frees, 0xff, size);
|
|
add_node(__FUNCTION__, frees, size);
|
|
|
|
size = log_max * sizeof(MppMemLog);
|
|
os_malloc((void **)&logs, MEM_ALIGN, size);
|
|
mpp_assert(logs);
|
|
add_node(__FUNCTION__, logs, size);
|
|
|
|
add_node(__FUNCTION__, this, sizeof(MppMemService));
|
|
}
|
|
}
|
|
|
|
MppMemService::~MppMemService()
|
|
{
|
|
if (debug & MEM_DEBUG_EN) {
|
|
AutoMutex auto_lock(m_lock);
|
|
|
|
RK_S32 i = 0;
|
|
MppMemNode *node = nodes;
|
|
|
|
// delete self node first
|
|
size_t size = 0;
|
|
|
|
del_node(__FUNCTION__, this, &size);
|
|
del_node(__FUNCTION__, nodes, &size);
|
|
del_node(__FUNCTION__, frees, &size);
|
|
del_node(__FUNCTION__, logs, &size);
|
|
|
|
// then check leak memory
|
|
if (nodes_cnt) {
|
|
for (i = 0; i < nodes_max; i++, node++) {
|
|
if (node->index >= 0) {
|
|
mpp_log("found idx %8d mem %10p size %d leaked\n",
|
|
node->index, node->ptr, node->size);
|
|
nodes_cnt--;
|
|
add_log(MEM_FREE, __FUNCTION__, node->ptr, NULL,
|
|
node->size, 0);
|
|
}
|
|
}
|
|
|
|
mpp_assert(nodes_cnt == 0);
|
|
}
|
|
|
|
// finally release all delay free memory
|
|
if (frees_cnt) {
|
|
node = frees;
|
|
|
|
for (i = 0; i < frees_max; i++, node++) {
|
|
if (node->index >= 0) {
|
|
os_free((RK_U8 *)node->ptr - MEM_HEAD_ROOM(debug));
|
|
node->index = ~node->index;
|
|
frees_cnt--;
|
|
add_log(MEM_FREE_DELAY, __FUNCTION__, node->ptr, NULL,
|
|
node->size, 0);
|
|
}
|
|
}
|
|
|
|
mpp_assert(frees_cnt == 0);
|
|
}
|
|
|
|
os_free(nodes);
|
|
os_free(frees);
|
|
os_free(logs);
|
|
}
|
|
|
|
if (m_lock) {
|
|
delete m_lock;
|
|
m_lock = NULL;
|
|
}
|
|
}
|
|
|
|
void MppMemService::add_node(const char *caller, void *ptr, size_t size)
|
|
{
|
|
RK_S32 i = 0;
|
|
|
|
if (debug & MEM_NODE_LOG)
|
|
mpp_log("mem cnt: %5d total %8d inc size %8d at %s\n",
|
|
nodes_cnt, m_total_size, size, caller);
|
|
|
|
if (nodes_cnt >= nodes_max) {
|
|
mpp_err("******************************************************\n");
|
|
mpp_err("* Reach max limit of mpp_mem counter %5d *\n", nodes_max);
|
|
mpp_err("* Increase limit by setup env mpp_mem_node_max or *\n");
|
|
mpp_err("* recompile mpp with larger macro MEM_NODE_MAX value *\n");
|
|
mpp_err("******************************************************\n");
|
|
mpp_abort();
|
|
}
|
|
|
|
MppMemNode *node = nodes;
|
|
for (i = 0; i < nodes_max; i++, node++) {
|
|
if (node->index < 0) {
|
|
node->index = nodes_idx++;
|
|
node->size = size;
|
|
node->ptr = ptr;
|
|
node->caller = caller;
|
|
|
|
// NOTE: reset node index on revert
|
|
if (nodes_idx < 0)
|
|
nodes_idx = 0;
|
|
|
|
nodes_cnt++;
|
|
m_total_size += size;
|
|
if (m_total_size > m_total_max)
|
|
m_total_max = m_total_size;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RK_S32 MppMemService::find_node(const char *caller, void *ptr, size_t *size, RK_S32 *idx)
|
|
{
|
|
RK_S32 i = 0;
|
|
MppMemNode *node = nodes;
|
|
|
|
MPP_MEM_ASSERT(nodes_cnt <= nodes_max);
|
|
for (i = 0; i < nodes_max; i++, node++) {
|
|
if (node->index >= 0 && node->ptr == ptr) {
|
|
*size = node->size;
|
|
*idx = i;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
mpp_err("%s can NOT found node with ptr %p\n", caller, ptr);
|
|
mpp_abort();
|
|
return 0;
|
|
}
|
|
|
|
void MppMemService::del_node(const char *caller, void *ptr, size_t *size)
|
|
{
|
|
RK_S32 i = 0;
|
|
MppMemNode *node = nodes;
|
|
|
|
MPP_MEM_ASSERT(nodes_cnt <= nodes_max);
|
|
|
|
for (i = 0; i < nodes_max; i++, node++) {
|
|
if (node->index >= 0 && node->ptr == ptr) {
|
|
*size = node->size;
|
|
node->index = ~node->index;
|
|
nodes_cnt--;
|
|
m_total_size -= node->size;
|
|
|
|
if (debug & MEM_NODE_LOG)
|
|
mpp_log("mem cnt: %5d total %8d dec size %8d at %s\n",
|
|
nodes_cnt, m_total_size, node->size, caller);
|
|
return ;
|
|
}
|
|
}
|
|
|
|
mpp_err("%s fail to find node with ptr %p\n", caller, ptr);
|
|
mpp_abort();
|
|
return ;
|
|
}
|
|
|
|
void *MppMemService::delay_del_node(const char *caller, void *ptr, size_t *size)
|
|
{
|
|
RK_S32 i = 0;
|
|
MppMemNode *node = nodes;
|
|
|
|
// clear output first
|
|
void *ret = NULL;
|
|
*size = 0;
|
|
|
|
// find the node to save
|
|
MPP_MEM_ASSERT(nodes_cnt <= nodes_max);
|
|
for (i = 0; i < nodes_max; i++, node++) {
|
|
if (node->index >= 0 && node->ptr == ptr) {
|
|
chk_node(caller, node);
|
|
break;
|
|
}
|
|
}
|
|
|
|
MPP_MEM_ASSERT(i < nodes_max);
|
|
if (debug & MEM_NODE_LOG)
|
|
mpp_log("mem cnt: %5d total %8d dec size %8d at %s\n",
|
|
nodes_cnt, m_total_size, node->size, caller);
|
|
|
|
MppMemNode *free_node = NULL;
|
|
|
|
MPP_MEM_ASSERT(frees_cnt <= frees_max);
|
|
|
|
if (frees_cnt) {
|
|
MppMemNode *tmp = frees;
|
|
|
|
// NODE: check all data here
|
|
for (i = 0; i < frees_max; i++, tmp++) {
|
|
if (tmp->index >= 0) {
|
|
chk_node(caller, tmp);
|
|
chk_poison(tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (frees_cnt >= frees_max) {
|
|
// free list full start del
|
|
RK_S32 frees_last = frees_idx - frees_cnt;
|
|
if (frees_last < 0)
|
|
frees_last += frees_max;
|
|
|
|
free_node = &frees[frees_last];
|
|
|
|
if (free_node->index >= 0) {
|
|
chk_node(caller, free_node);
|
|
chk_poison(free_node);
|
|
ret = free_node->ptr;
|
|
*size = free_node->size;
|
|
free_node->index = ~free_node->index;
|
|
frees_cnt--;
|
|
}
|
|
}
|
|
|
|
MPP_MEM_ASSERT(frees_cnt <= frees_max);
|
|
|
|
// free list is NOT full just store
|
|
free_node = &frees[frees_idx];
|
|
frees_idx++;
|
|
if (frees_idx >= frees_max)
|
|
frees_idx = 0;
|
|
if (frees_cnt < frees_max)
|
|
frees_cnt++;
|
|
|
|
MPP_MEM_ASSERT(frees_cnt <= frees_max);
|
|
|
|
memcpy(&frees[frees_idx], node, sizeof(*node));
|
|
|
|
if ((debug & MEM_POISON) && (node->size < 1024))
|
|
memset(node->ptr, MEM_CHECK_MARK, node->size);
|
|
|
|
node->index = ~node->index;
|
|
m_total_size -= node->size;
|
|
nodes_cnt--;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void MppMemService::chk_node(const char *caller, MppMemNode *node)
|
|
{
|
|
if ((debug & MEM_EXT_ROOM) == 0)
|
|
return ;
|
|
|
|
chk_mem(caller, node->ptr, node->size);
|
|
}
|
|
|
|
void MppMemService::chk_mem(const char *caller, void *ptr, size_t size)
|
|
{
|
|
if ((debug & MEM_EXT_ROOM) == 0)
|
|
return ;
|
|
|
|
RK_S32 i = 0;
|
|
RK_U8 *p = (RK_U8 *)ptr - MEM_ALIGN;
|
|
|
|
for (i = 0; i < MEM_ALIGN; i++) {
|
|
if (p[i] != MEM_HEAD_MASK) {
|
|
mpp_err("%s checking ptr %p head room found error!\n", caller, ptr);
|
|
dump(caller);
|
|
show_mem((RK_U32 *)p, MEM_ALIGN);
|
|
mpp_abort();
|
|
}
|
|
}
|
|
|
|
p = (RK_U8 *)ptr + size;
|
|
for (i = 0; i < MEM_ALIGN; i++) {
|
|
if (p[i] != MEM_TAIL_MASK) {
|
|
mpp_err("%s checking ptr %p tail room found error!\n", caller, ptr);
|
|
dump(caller);
|
|
show_mem((RK_U32 *)p, MEM_ALIGN);
|
|
mpp_abort();
|
|
}
|
|
}
|
|
}
|
|
|
|
RK_S32 MppMemService::chk_poison(MppMemNode *node)
|
|
{
|
|
if ((debug & MEM_POISON) == 0)
|
|
return 0;
|
|
|
|
// check oldest memory and free it
|
|
RK_U8 *node_ptr = (RK_U8 *)node->ptr;
|
|
RK_S32 size = node->size;
|
|
RK_S32 i = 0;
|
|
RK_S32 start = -1;
|
|
RK_S32 end = -1;
|
|
|
|
if (size >= 1024)
|
|
return 0;
|
|
|
|
for (; i < size; i++) {
|
|
if (node_ptr[i] != MEM_CHECK_MARK) {
|
|
if (start < 0) {
|
|
start = i;
|
|
}
|
|
end = i + 1;
|
|
}
|
|
}
|
|
|
|
if (start >= 0 || end >= 0) {
|
|
mpp_err_f("found memory %p size %d caller %s overwrite from %d to %d\n",
|
|
node_ptr, size, node->caller, start, end);
|
|
dump(node->caller);
|
|
}
|
|
|
|
return end - start;
|
|
}
|
|
|
|
void MppMemService::reset_node(const char *caller, void *ptr, void *ret, size_t size)
|
|
{
|
|
RK_S32 i = 0;
|
|
MppMemNode *node = nodes;
|
|
|
|
if (debug & MEM_NODE_LOG)
|
|
mpp_log("mem cnt: %5d total %8d equ size %8d at %s\n",
|
|
nodes_cnt, m_total_size, size, __FUNCTION__);
|
|
|
|
MPP_MEM_ASSERT(nodes_cnt <= nodes_max);
|
|
|
|
for (i = 0; i < nodes_max; i++, node++) {
|
|
if (node->index >= 0 && node->ptr == ptr) {
|
|
m_total_size += size;
|
|
m_total_size -= node->size;
|
|
|
|
node->ptr = ret;
|
|
node->size = size;
|
|
node->caller = caller;
|
|
|
|
if (debug & MEM_EXT_ROOM)
|
|
set_mem_ext_room(ret, size);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MppMemService::add_log(MppMemOps ops, const char *caller,
|
|
void *ptr, void *ret, size_t size_0, size_t size_1)
|
|
{
|
|
MppMemService *srv = MppMemService::get_inst();
|
|
MppMemLog *log = &logs[log_idx];
|
|
|
|
if (srv->debug & MEM_RUNTIME_LOG)
|
|
mpp_log("%-7s ptr %010p %010p size %8u %8u at %s\n",
|
|
ops2str[ops], ptr, ret, size_0, size_1, caller);
|
|
|
|
log->index = log_index++;
|
|
log->ops = ops;
|
|
log->size_0 = size_0;
|
|
log->size_1 = size_1;
|
|
log->ptr = ptr;
|
|
log->ret = ret;
|
|
log->node = NULL;
|
|
log->caller = caller;
|
|
|
|
log_idx++;
|
|
if (log_idx >= log_max)
|
|
log_idx = 0;
|
|
|
|
if (log_cnt < log_max)
|
|
log_cnt++;
|
|
}
|
|
|
|
void MppMemService::dump(const char *caller)
|
|
{
|
|
RK_S32 i;
|
|
MppMemNode *node = nodes;
|
|
|
|
mpp_log("mpp_mem enter status dumping from %s:\n", caller);
|
|
|
|
mpp_log("mpp_mem node count %d:\n", nodes_cnt);
|
|
if (nodes_cnt) {
|
|
for (i = 0; i < nodes_max; i++, node++) {
|
|
if (node->index < 0)
|
|
continue;
|
|
|
|
mpp_log("mpp_memory index %d caller %-32s size %-8u ptr %p\n",
|
|
node->index, node->caller, node->size, node->ptr);
|
|
}
|
|
}
|
|
|
|
node = frees;
|
|
mpp_log("mpp_mem free count %d:\n", frees_cnt);
|
|
if (frees_cnt) {
|
|
for (i = 0; i < frees_max; i++, node++) {
|
|
if (node->index < 0)
|
|
continue;
|
|
|
|
mpp_log("mpp_freed index %d caller %-32s size %-8u ptr %p\n",
|
|
node->index, node->caller, node->size, node->ptr);
|
|
}
|
|
}
|
|
|
|
RK_S32 start = log_idx - log_cnt;
|
|
RK_S32 tmp_cnt = log_cnt;
|
|
|
|
if (start < 0)
|
|
start += log_max;
|
|
|
|
mpp_log("mpp_mem enter log dumping:\n");
|
|
|
|
while (tmp_cnt) {
|
|
MppMemLog *log = &logs[start];
|
|
|
|
mpp_log("idx %-8d op: %-7s from %-32s ptr %10p %10p size %7d %7d\n",
|
|
log->index, ops2str[log->ops], log->caller,
|
|
log->ptr, log->ret, log->size_0, log->size_1);
|
|
|
|
start++;
|
|
if (start >= log_max)
|
|
start = 0;
|
|
|
|
tmp_cnt--;
|
|
}
|
|
}
|
|
|
|
void *mpp_osal_malloc(const char *caller, size_t size)
|
|
{
|
|
MppMemService *srv = MppMemService::get_inst();
|
|
RK_U32 debug = srv->debug;
|
|
size_t size_align = MEM_ALIGNED(size);
|
|
size_t size_real = (debug & MEM_EXT_ROOM) ? (size_align + 2 * MEM_ALIGN) :
|
|
(size_align);
|
|
void *ptr;
|
|
|
|
os_malloc(&ptr, MEM_ALIGN, size_real);
|
|
|
|
if (debug) {
|
|
AutoMutex auto_lock(srv->m_lock);
|
|
srv->add_log(MEM_MALLOC, caller, NULL, ptr, size, size_real);
|
|
|
|
if (ptr) {
|
|
if (debug & MEM_EXT_ROOM) {
|
|
ptr = (RK_U8 *)ptr + MEM_ALIGN;
|
|
set_mem_ext_room(ptr, size);
|
|
}
|
|
|
|
srv->add_node(caller, ptr, size);
|
|
}
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void *mpp_osal_calloc(const char *caller, size_t size)
|
|
{
|
|
void *ptr = mpp_osal_malloc(caller, size);
|
|
if (ptr)
|
|
memset(ptr, 0, size);
|
|
return ptr;
|
|
}
|
|
|
|
void *mpp_osal_realloc(const char *caller, void *ptr, size_t size)
|
|
{
|
|
MppMemService *srv = MppMemService::get_inst();
|
|
RK_U32 debug = srv->debug;
|
|
void *ret;
|
|
|
|
if (NULL == ptr)
|
|
return mpp_osal_malloc(caller, size);
|
|
|
|
if (0 == size) {
|
|
mpp_err("warning: realloc %p to zero size\n", ptr);
|
|
return NULL;
|
|
}
|
|
|
|
size_t size_align = MEM_ALIGNED(size);
|
|
size_t size_real = (debug & MEM_EXT_ROOM) ? (size_align + 2 * MEM_ALIGN) :
|
|
(size_align);
|
|
void *ptr_real = (RK_U8 *)ptr - MEM_HEAD_ROOM(debug);
|
|
|
|
os_realloc(ptr_real, &ret, MEM_ALIGN, size_align);
|
|
|
|
if (NULL == ret) {
|
|
// if realloc fail the original buffer will be kept the same.
|
|
mpp_err("mpp_realloc ptr %p to size %d failed\n", ptr, size);
|
|
} else {
|
|
AutoMutex auto_lock(srv->m_lock);
|
|
|
|
// if realloc success reset the node and record
|
|
if (debug) {
|
|
void *ret_ptr = (debug & MEM_EXT_ROOM) ?
|
|
((RK_U8 *)ret + MEM_ALIGN) : (ret);
|
|
|
|
srv->reset_node(caller, ptr, ret_ptr, size);
|
|
srv->add_log(MEM_REALLOC, caller, ptr, ret_ptr, size, size_real);
|
|
ret = ret_ptr;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void mpp_osal_free(const char *caller, void *ptr)
|
|
{
|
|
MppMemService *srv = MppMemService::get_inst();
|
|
RK_U32 debug = srv->debug;
|
|
|
|
if (NULL == ptr)
|
|
return;
|
|
|
|
if (!debug) {
|
|
os_free(ptr);
|
|
return ;
|
|
}
|
|
|
|
size_t size = 0;
|
|
|
|
AutoMutex auto_lock(srv->m_lock);
|
|
if (debug & MEM_POISON) {
|
|
// NODE: keep this node and delete delay node
|
|
void *ret = srv->delay_del_node(caller, ptr, &size);
|
|
if (ret)
|
|
os_free((RK_U8 *)ret - MEM_ALIGN);
|
|
|
|
srv->add_log(MEM_FREE_DELAY, caller, ptr, ret, size, 0);
|
|
} else {
|
|
void *ptr_real = (RK_U8 *)ptr - MEM_HEAD_ROOM(debug);
|
|
// NODE: delete node and return size here
|
|
srv->del_node(caller, ptr, &size);
|
|
srv->chk_mem(caller, ptr, size);
|
|
os_free(ptr_real);
|
|
srv->add_log(MEM_FREE, caller, ptr, ptr_real, size, 0);
|
|
}
|
|
}
|
|
|
|
/* dump memory status */
|
|
void mpp_show_mem_status()
|
|
{
|
|
MppMemService *srv = MppMemService::get_inst();
|
|
AutoMutex auto_lock(srv->m_lock);
|
|
|
|
if (srv->debug & MEM_DEBUG_EN)
|
|
srv->dump(__FUNCTION__);
|
|
}
|
|
|
|
RK_U32 mpp_mem_total_now()
|
|
{
|
|
MppMemService *srv = MppMemService::get_inst();
|
|
AutoMutex auto_lock(srv->m_lock);
|
|
|
|
return srv->total_now();
|
|
}
|
|
|
|
RK_U32 mpp_mem_total_max()
|
|
{
|
|
MppMemService *srv = MppMemService::get_inst();
|
|
AutoMutex auto_lock(srv->m_lock);
|
|
|
|
return srv->total_max();
|
|
}
|