/* 
 | 
 * 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) & (~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"); \ 
 | 
            service.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: 
 | 
    // avoid any unwanted function 
 | 
    MppMemService(); 
 | 
    ~MppMemService(); 
 | 
  
 | 
    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       lock; 
 | 
    RK_U32      debug; 
 | 
  
 | 
private: 
 | 
    // 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; 
 | 
  
 | 
    MppMemService(const MppMemService &); 
 | 
    MppMemService &operator=(const MppMemService &); 
 | 
}; 
 | 
  
 | 
static MppMemService service; 
 | 
  
 | 
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); 
 | 
  
 | 
    // 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(&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); 
 | 
    } 
 | 
} 
 | 
  
 | 
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) 
 | 
{ 
 | 
    MppMemLog *log = &logs[log_idx]; 
 | 
  
 | 
    if (service.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) 
 | 
{ 
 | 
    RK_U32 debug = service.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(&service.lock); 
 | 
        service.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); 
 | 
            } 
 | 
  
 | 
            service.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) 
 | 
{ 
 | 
    RK_U32 debug = service.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(&service.lock); 
 | 
  
 | 
        // if realloc success reset the node and record 
 | 
        if (debug) { 
 | 
            void *ret_ptr = (debug & MEM_EXT_ROOM) ? 
 | 
                            ((RK_U8 *)ret + MEM_ALIGN) : (ret); 
 | 
  
 | 
            service.reset_node(caller, ptr, ret_ptr, size); 
 | 
            service.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) 
 | 
{ 
 | 
    RK_U32 debug = service.debug; 
 | 
    if (NULL == ptr) 
 | 
        return; 
 | 
  
 | 
    if (!debug) { 
 | 
        os_free(ptr); 
 | 
        return ; 
 | 
    } 
 | 
  
 | 
    size_t size = 0; 
 | 
  
 | 
    AutoMutex auto_lock(&service.lock); 
 | 
    if (debug & MEM_POISON) { 
 | 
        // NODE: keep this node and  delete delay node 
 | 
        void *ret = service.delay_del_node(caller, ptr, &size); 
 | 
        if (ret) 
 | 
            os_free((RK_U8 *)ret - MEM_ALIGN); 
 | 
  
 | 
        service.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 
 | 
        service.del_node(caller, ptr, &size); 
 | 
        service.chk_mem(caller, ptr, size); 
 | 
        os_free(ptr_real); 
 | 
        service.add_log(MEM_FREE, caller, ptr, ptr_real, size, 0); 
 | 
    } 
 | 
} 
 | 
  
 | 
/* dump memory status */ 
 | 
void mpp_show_mem_status() 
 | 
{ 
 | 
    AutoMutex auto_lock(&service.lock); 
 | 
    if (service.debug & MEM_DEBUG_EN) 
 | 
        service.dump(__FUNCTION__); 
 | 
} 
 | 
  
 | 
RK_U32 mpp_mem_total_now() 
 | 
{ 
 | 
    AutoMutex auto_lock(&service.lock); 
 | 
    return service.total_now(); 
 | 
} 
 | 
  
 | 
RK_U32 mpp_mem_total_max() 
 | 
{ 
 | 
    AutoMutex auto_lock(&service.lock); 
 | 
    return service.total_max(); 
 | 
} 
 |