|
|
/******************************************************************************
|
|
|
* file lib/management/memory.c
|
|
|
* author YuLiang
|
|
|
* version 1.0.0
|
|
|
* date 14-Sep-2021
|
|
|
* brief This file provides all the memory operation functions.
|
|
|
******************************************************************************
|
|
|
* Attention
|
|
|
*
|
|
|
* <h2><center>© COPYRIGHT(c) 2021 LandPower</center></h2>
|
|
|
*
|
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
|
* are permitted provided that the following conditions are met:
|
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
|
* this list of conditions and the following disclaimer.
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
* and/or other materials provided with the distribution.
|
|
|
* 3. Neither the name of LandPower nor the names of its contributors may be used to
|
|
|
* endorse or promote products derived from this software without specific
|
|
|
* prior written permission.
|
|
|
*
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
*
|
|
|
******************************************************************************/
|
|
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
#include "config.h"
|
|
|
#endif
|
|
|
|
|
|
/* 标准C库头文件. */
|
|
|
#include <malloc.h>
|
|
|
#include <sys/resource.h>
|
|
|
|
|
|
/* 用户代码头文件. */
|
|
|
#include "cmd.h"
|
|
|
|
|
|
/* Private define ------------------------------------------------------------*/
|
|
|
#define MEM_LOCK pthread_mutex_lock(&mem_mutex)
|
|
|
#define MEM_UNLOCK pthread_mutex_unlock(&mem_mutex)
|
|
|
|
|
|
/* Private macro -------------------------------------------------------------*/
|
|
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
|
static mem_node_t mem_list_management[] =
|
|
|
{
|
|
|
{MTYPE_CLI, "Cli"},
|
|
|
{MTYPE_BUF, "Buffer"},
|
|
|
{MTYPE_BUF_DATA, "Buffer data"},
|
|
|
{MTYPE_BUF_TMP, "Buffer temp"},
|
|
|
{MTYPE_VTY, "Vty"},
|
|
|
{MTYPE_VTY_TMP, "Vty temp"},
|
|
|
{MTYPE_VTY_OUT_BUF, "Vty output buffer"},
|
|
|
{MTYPE_VTY_HIST, "Vty history"},
|
|
|
{MTYPE_HASH, "Hash"},
|
|
|
{MTYPE_HASH_BACKET, "Hash Bucket"},
|
|
|
{MTYPE_HASH_INDEX, "Hash Index"},
|
|
|
{MTYPE_LOG, "Logging"},
|
|
|
{MTYPE_MTIMER, "Timer"},
|
|
|
{MTYPE_THREAD_MONITOR, "Thread monitor"},
|
|
|
{MTYPE_PREFIX, "Prefix"},
|
|
|
{MTYPE_THREAD, "Thread"},
|
|
|
{MTYPE_THREAD_STATS, "Thread stats"},
|
|
|
{MTYPE_THREAD_MASTER, "Thread master"},
|
|
|
{MTYPE_THREAD_FUNCNAME, "Thread function name"},
|
|
|
{MTYPE_FIFO, "fifo"},
|
|
|
{MTYPE_GPIO, "gpio"},
|
|
|
{ -1, NULL },
|
|
|
};
|
|
|
|
|
|
static mem_node_t mem_list_transceiver[] =
|
|
|
{
|
|
|
{MTYPE_RECV, "Receive"},
|
|
|
{MTYPE_SENT, "Sent"},
|
|
|
{MTYPE_USART, "Usart"},
|
|
|
{MTYPE_ETH, "Ethernet"},
|
|
|
{ -1, NULL },
|
|
|
};
|
|
|
|
|
|
static mem_node_t mem_list_process[] =
|
|
|
{
|
|
|
{MTYPE_GIS, "GIS"},
|
|
|
{MTYPE_DAU, "DAU"},
|
|
|
{MTYPE_CSG, "CSG"},
|
|
|
{MTYPE_STORAGE, "STORAGE"},
|
|
|
{MTYPE_DEBUG, "DEBUG"},
|
|
|
{ -1, NULL },
|
|
|
};
|
|
|
|
|
|
static mem_list_t mlists[] __attribute__ ((unused)) =
|
|
|
{
|
|
|
{mem_list_management, "MANAGEMENT"},
|
|
|
{mem_list_transceiver, "TRANSCEIVER"},
|
|
|
{mem_list_process, "PROCESS"},
|
|
|
{NULL, NULL},
|
|
|
};
|
|
|
|
|
|
/* 同于统计每个模块申请内存的次数. */
|
|
|
static struct
|
|
|
{
|
|
|
const char *name;
|
|
|
int32_t alloc;
|
|
|
uint32_t t_malloc;
|
|
|
uint32_t c_malloc;
|
|
|
uint32_t t_calloc;
|
|
|
uint32_t c_calloc;
|
|
|
uint32_t t_realloc;
|
|
|
uint32_t t_free;
|
|
|
uint32_t c_strdup;
|
|
|
} mstat[MTYPE_MAX];
|
|
|
|
|
|
static pthread_mutex_t mem_mutex;
|
|
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
|
|
|
|
/* Internal functions --------------------------------------------------------*/
|
|
|
/* 查找模块相应的说明字符串: key -- 模块 */
|
|
|
static const char *_x_desc_lookup(uint32_t key)
|
|
|
{
|
|
|
const mem_list_t *list = NULL;
|
|
|
const mem_node_t *pnt = NULL;
|
|
|
|
|
|
for(list = mlists; list->nodes != NULL; list++)
|
|
|
{
|
|
|
for(pnt = list->nodes; pnt->index >= 0; pnt++)
|
|
|
{
|
|
|
if (pnt->index == key)
|
|
|
{
|
|
|
return pnt->format;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return "";
|
|
|
}
|
|
|
|
|
|
/* 打印每个模块的内存使用情况: pri -- log优先级 */
|
|
|
static void _x_memstats_print(int32_t pri)
|
|
|
{
|
|
|
mem_list_t *ml = NULL;
|
|
|
|
|
|
for (ml = mlists; ml->nodes; ml++)
|
|
|
{
|
|
|
mem_node_t *m = NULL;
|
|
|
|
|
|
log_out(LOG_MEMORY, pri, "Memory utilization in module %s:", ml->name);
|
|
|
for(m = ml->nodes; m->index >= 0; m++)
|
|
|
{
|
|
|
if (m->index && mstat[m->index].alloc)
|
|
|
{
|
|
|
log_out(LOG_MEMORY, pri, " %-30s: %10ld", m->format, (long)mstat[m->index].alloc);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 打印内存申请错误信息: fname -- 调用的函数,type -- 模块, size -- 大小 */
|
|
|
static void __attribute__ ((noreturn)) _x_mem_error(const char *fname, int32_t type, size_t size)
|
|
|
{
|
|
|
log_err(LOG_MEMORY, "%s : can't allocate memory for '%s' size %d: %s!",
|
|
|
fname, _x_desc_lookup(type), (int)size, safe_strerror(errno));
|
|
|
|
|
|
/* 打印每个模块的内存使用请款 */
|
|
|
_x_memstats_print(LOG_LVL_WARN);
|
|
|
|
|
|
/* 打印堆栈信息 */
|
|
|
log_backtrace(LOG_LVL_WARN);
|
|
|
|
|
|
abort();
|
|
|
}
|
|
|
|
|
|
/* 增加内存alloc计数 */
|
|
|
static void _x_alloc_inc(int32_t type)
|
|
|
{
|
|
|
MEM_LOCK;
|
|
|
mstat[type].alloc++;
|
|
|
MEM_UNLOCK;
|
|
|
}
|
|
|
|
|
|
/* 减少内存alloc计数 */
|
|
|
static void _x_alloc_dec(int32_t type)
|
|
|
{
|
|
|
MEM_LOCK;
|
|
|
mstat[type].alloc--;
|
|
|
MEM_UNLOCK;
|
|
|
}
|
|
|
|
|
|
/* 打印内存申请释放的debug信息. */
|
|
|
static void _x_mtype_log(char *func, void *memory, const char *file, int32_t line, uint32_t type)
|
|
|
{
|
|
|
//log_debug(LOG_MEMORY, "%s: %s %p %s %d", func, _x_desc_lookup(type), memory, file, line);
|
|
|
log_out(LOG_MEMORY, LOG_LVL_DBG,"%s: %s %p %s %d", func, _x_desc_lookup(type), memory, file, line);
|
|
|
}
|
|
|
|
|
|
/* Stats querying from users */
|
|
|
/* Return a pointer to a human friendly string describing
|
|
|
* the byte count passed in. E.g:
|
|
|
* "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc.
|
|
|
* Up to 4 significant figures will be given.
|
|
|
* The pointer returned may be NULL (indicating an error)
|
|
|
* or point to the given buffer, or point to static storage. */
|
|
|
static const char *_x_mtype_memstr(char *buf, size_t len, uint32_t bytes)
|
|
|
{
|
|
|
int32_t t = 0;
|
|
|
int32_t g = 0;
|
|
|
int32_t m = 0;
|
|
|
int32_t k = 0;
|
|
|
|
|
|
/* easy cases */
|
|
|
if (!bytes)
|
|
|
return "0 bytes";
|
|
|
if (1 == bytes)
|
|
|
return "1 byte";
|
|
|
|
|
|
#if 0
|
|
|
if (sizeof(unsigned long) >= 8)
|
|
|
/* Hacked to make it not warn on ILP32 machines
|
|
|
* Shift will always be 40 at runtime. See below too */
|
|
|
t = bytes >> (sizeof (unsigned long) >= 8 ? 40 : 0);
|
|
|
else
|
|
|
t = 0;
|
|
|
#endif
|
|
|
|
|
|
g = bytes >> 30;
|
|
|
m = bytes >> 20;
|
|
|
k = bytes >> 10;
|
|
|
|
|
|
if (t > 10)
|
|
|
{
|
|
|
/* The shift will always be 39 at runtime.
|
|
|
* Just hacked to make it not warn on 'smaller' machines.
|
|
|
* Static compiler analysis should mean no extra code */
|
|
|
if (bytes & (1UL << (sizeof(unsigned long) >= 8 ? 39 : 0)))
|
|
|
t++;
|
|
|
snprintf (buf, len, "%4d TiB", t);
|
|
|
}
|
|
|
else if (g > 10)
|
|
|
{
|
|
|
if (bytes & (1 << 29))
|
|
|
g++;
|
|
|
snprintf (buf, len, "%d GiB", g);
|
|
|
}
|
|
|
else if (m > 10)
|
|
|
{
|
|
|
if (bytes & (1 << 19))
|
|
|
m++;
|
|
|
snprintf (buf, len, "%d MiB", m);
|
|
|
}
|
|
|
else if (k > 10)
|
|
|
{
|
|
|
if (bytes & (1 << 9))
|
|
|
k++;
|
|
|
snprintf (buf, len, "%d KiB", k);
|
|
|
}
|
|
|
else
|
|
|
snprintf (buf, len, "%d bytes", bytes);
|
|
|
|
|
|
return buf;
|
|
|
}
|
|
|
|
|
|
/* 打印内存使用情况根据系统调用. */
|
|
|
static int32_t _x_show_memory_mallinfo(vty_t *vty)
|
|
|
{
|
|
|
struct mallinfo minfo = mallinfo();
|
|
|
char buf[MTYPE_MEMSTR_LEN] = {0};
|
|
|
|
|
|
vty_out(vty, "System allocator statistics:%s", VTY_NEWLINE);
|
|
|
vty_out(vty, " Total heap allocated: %s%s",
|
|
|
_x_mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.arena), VTY_NEWLINE);
|
|
|
vty_out(vty, " Holding block headers: %s%s",
|
|
|
_x_mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.hblkhd), VTY_NEWLINE);
|
|
|
vty_out(vty, " Used small blocks: %s%s",
|
|
|
_x_mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.usmblks), VTY_NEWLINE);
|
|
|
vty_out(vty, " Used ordinary blocks: %s%s",
|
|
|
_x_mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.uordblks), VTY_NEWLINE);
|
|
|
vty_out(vty, " Free small blocks: %s%s",
|
|
|
_x_mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fsmblks), VTY_NEWLINE);
|
|
|
vty_out(vty, " Free ordinary blocks: %s%s",
|
|
|
_x_mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fordblks), VTY_NEWLINE);
|
|
|
vty_out(vty, " Ordinary blocks: %ld%s", (unsigned long)minfo.ordblks, VTY_NEWLINE);
|
|
|
vty_out(vty, " Small blocks: %ld%s", (unsigned long)minfo.smblks, VTY_NEWLINE);
|
|
|
vty_out(vty, " Holding blocks: %ld%s", (unsigned long)minfo.hblks, VTY_NEWLINE);
|
|
|
vty_out(vty, "(see system documentation for 'mallinfo' for meaning)%s", VTY_NEWLINE);
|
|
|
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
static void _x_show_separator(vty_t *vty)
|
|
|
{
|
|
|
vty_out(vty, "-----------------------------%s", VTY_NEWLINE);
|
|
|
}
|
|
|
|
|
|
int32_t _x_show_memory_vty(vty_t *vty, mem_node_t *list)
|
|
|
{
|
|
|
mem_node_t *m = NULL;
|
|
|
int32_t needsep = 0;
|
|
|
|
|
|
for (m = list; m->index >= 0; m++)
|
|
|
if (0 == m->index)
|
|
|
{
|
|
|
if (needsep)
|
|
|
{
|
|
|
_x_show_separator(vty);
|
|
|
needsep = 0;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
vty_out(vty, "%-30s: %10d%s", m->format, mstat[m->index].alloc, VTY_NEWLINE);
|
|
|
needsep = 1;
|
|
|
}
|
|
|
|
|
|
return needsep;
|
|
|
}
|
|
|
|
|
|
/* 申请内存,并增加相应的模块的申请数: type -- 模块,size -- 大小 */
|
|
|
static void *_x_malloc (int32_t type, size_t size)
|
|
|
{
|
|
|
void *memory = NULL;
|
|
|
|
|
|
memory = malloc(size);
|
|
|
|
|
|
if (NULL == memory)
|
|
|
_x_mem_error("malloc", type, size);
|
|
|
|
|
|
memset(memory, 0, size);
|
|
|
|
|
|
_x_alloc_inc(type);
|
|
|
|
|
|
return memory;
|
|
|
}
|
|
|
|
|
|
/* 申请内存,并增加相应的模块的申请数: type -- 模块,size -- 大小 */
|
|
|
static void *_x_malloc_q (int32_t type, size_t size)
|
|
|
{
|
|
|
void *memory = NULL;
|
|
|
|
|
|
memory = malloc(size);
|
|
|
|
|
|
if (NULL == memory)
|
|
|
_x_mem_error("malloc", type, size);
|
|
|
|
|
|
_x_alloc_inc(type);
|
|
|
|
|
|
return memory;
|
|
|
}
|
|
|
|
|
|
/* Allocate memory as in zmalloc, and also clear the memory. */
|
|
|
static void *_x_calloc(int32_t type, size_t size)
|
|
|
{
|
|
|
void *memory = NULL;
|
|
|
|
|
|
memory = calloc(1, size);
|
|
|
|
|
|
if (NULL == memory)
|
|
|
_x_mem_error("calloc", type, size);
|
|
|
|
|
|
memset(memory, 0, size);
|
|
|
|
|
|
_x_alloc_inc(type);
|
|
|
|
|
|
return memory;
|
|
|
}
|
|
|
|
|
|
/* Given a pointer returned by zmalloc or zcalloc, free it and
|
|
|
* return a pointer to a new size, basically acting like realloc().
|
|
|
* Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the
|
|
|
* same type.
|
|
|
* Effects: Returns a pointer to the new memory, or aborts. */
|
|
|
static void *_x_realloc(int32_t type, void *ptr, size_t size)
|
|
|
{
|
|
|
void *memory = NULL;
|
|
|
|
|
|
memory = realloc(ptr, size);
|
|
|
if (NULL == memory)
|
|
|
_x_mem_error("realloc", type, size);
|
|
|
|
|
|
if (NULL == ptr)
|
|
|
_x_alloc_inc(type);
|
|
|
|
|
|
return memory;
|
|
|
}
|
|
|
|
|
|
/* Free memory allocated by z*alloc or zstrdup.
|
|
|
* Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the
|
|
|
* same type.
|
|
|
* Effects: The memory is freed and may no longer be referenced. */
|
|
|
static void _x_free(int32_t type, void *ptr)
|
|
|
{
|
|
|
if (ptr != NULL)
|
|
|
{
|
|
|
_x_alloc_dec(type);
|
|
|
free(ptr);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Duplicate a string, counting memory usage by type.
|
|
|
* Effects: The string is duplicated, and the return value must
|
|
|
* eventually be passed to zfree with the same type. The function will
|
|
|
* succeed or abort. */
|
|
|
static char *_x_strdup(int32_t type, const char *str)
|
|
|
{
|
|
|
void *dup = NULL;
|
|
|
|
|
|
dup = strdup(str);
|
|
|
if (dup == NULL)
|
|
|
_x_mem_error("strdup", type, strlen(str));
|
|
|
|
|
|
_x_alloc_inc(type);
|
|
|
|
|
|
return dup;
|
|
|
}
|
|
|
|
|
|
/* Interface functions -------------------------------------------------------*/
|
|
|
/* description: 申请内存.
|
|
|
param: file -- 调用的文件
|
|
|
line -- 调用的行数
|
|
|
type -- 哪个模块调用
|
|
|
size -- 分配的大小
|
|
|
return: 分配的内存地址 */
|
|
|
void *mtype_x_malloc(const char *file, int32_t line, int32_t type, size_t size)
|
|
|
{
|
|
|
void *memory = NULL;
|
|
|
|
|
|
mstat[type].c_malloc++;
|
|
|
mstat[type].t_malloc++;
|
|
|
|
|
|
memory = _x_malloc(type, size);
|
|
|
_x_mtype_log("x_malloc", memory, file, line, type);
|
|
|
|
|
|
return memory;
|
|
|
}
|
|
|
|
|
|
void *mtype_x_malloc_q(const char *file, int32_t line, int32_t type, size_t size)
|
|
|
{
|
|
|
void *memory = NULL;
|
|
|
|
|
|
mstat[type].c_malloc++;
|
|
|
mstat[type].t_malloc++;
|
|
|
|
|
|
memory = _x_malloc_q(type, size);
|
|
|
_x_mtype_log("x_malloc_q", memory, file, line, type);
|
|
|
|
|
|
return memory;
|
|
|
}
|
|
|
|
|
|
/* 见mtype_x_malloc. */
|
|
|
void *mtype_x_calloc(const char *file, int32_t line, int32_t type, size_t size)
|
|
|
{
|
|
|
void *memory = NULL;
|
|
|
|
|
|
mstat[type].c_calloc++;
|
|
|
mstat[type].t_calloc++;
|
|
|
|
|
|
memory = _x_calloc(type, size);
|
|
|
_x_mtype_log("x_calloc", memory, file, line, type);
|
|
|
|
|
|
return memory;
|
|
|
}
|
|
|
|
|
|
/* 见mtype_x_malloc. */
|
|
|
void *mtype_x_realloc(const char *file, int32_t line, int32_t type, void *ptr, size_t size)
|
|
|
{
|
|
|
void *memory = NULL;
|
|
|
|
|
|
/* Realloc need before allocated pointer. */
|
|
|
mstat[type].t_realloc++;
|
|
|
|
|
|
memory = _x_realloc(type, ptr, size);
|
|
|
|
|
|
_x_mtype_log("x_realloc", memory, file, line, type);
|
|
|
|
|
|
return memory;
|
|
|
}
|
|
|
|
|
|
/* 见mtype_x_malloc. */
|
|
|
void mtype_x_free(const char *file, int32_t line, int32_t type, void *ptr)
|
|
|
{
|
|
|
mstat[type].t_free++;
|
|
|
|
|
|
_x_free(type, ptr);
|
|
|
|
|
|
_x_mtype_log("x_free", ptr, file, line, type);
|
|
|
}
|
|
|
|
|
|
/* 见mtype_x_malloc. */
|
|
|
char *mtype_x_strdup(const char *file, int32_t line, int32_t type, const char *str)
|
|
|
{
|
|
|
char *memory = NULL;
|
|
|
|
|
|
mstat[type].c_strdup++;
|
|
|
|
|
|
memory = _x_strdup(type, str);
|
|
|
|
|
|
_x_mtype_log("x_strdup", memory, file, line, type);
|
|
|
|
|
|
return memory;
|
|
|
}
|
|
|
|
|
|
CMD(show_memory_all,
|
|
|
show_memory_all_cmd,
|
|
|
"show memory",
|
|
|
SHOW_STR
|
|
|
"Memory statistics\n")
|
|
|
{
|
|
|
mem_list_t *ml = NULL;
|
|
|
int needsep = 0;
|
|
|
|
|
|
needsep = _x_show_memory_mallinfo(vty);
|
|
|
|
|
|
for (ml = mlists; ml->nodes; ml++)
|
|
|
{
|
|
|
if (needsep)
|
|
|
_x_show_separator(vty);
|
|
|
needsep = _x_show_memory_vty(vty, ml->nodes);
|
|
|
}
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
}
|
|
|
|
|
|
void mem_show(vty_t *vty)
|
|
|
{
|
|
|
mem_list_t *ml = NULL;
|
|
|
int needsep = 0;
|
|
|
|
|
|
for (ml = mlists; ml->nodes; ml++)
|
|
|
{
|
|
|
if (needsep)
|
|
|
_x_show_separator(vty);
|
|
|
needsep = _x_show_memory_vty(vty, ml->nodes);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* description: memory模块初始化.
|
|
|
param:
|
|
|
return: */
|
|
|
void mtype_init(void)
|
|
|
{
|
|
|
cmd_install_element(COMMON_NODE, &show_memory_all_cmd);
|
|
|
}
|
|
|
|
|
|
/* description: memory模块初始化.
|
|
|
param:
|
|
|
return: */
|
|
|
void mtype_init_befor(void)
|
|
|
{
|
|
|
/* 初始化线程锁. */
|
|
|
pthread_mutex_init(&mem_mutex, NULL);
|
|
|
}
|
|
|
|
|
|
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****************/
|