|  |  |  |  | /******************************************************************************
 | 
					
						
							|  |  |  |  |  * 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"}, | 
					
						
							|  |  |  |  |     {MTYPE_UPGRADE,         "UPGRADE"}, | 
					
						
							|  |  |  |  |     { -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 mallinfo2 minfo = mallinfo2(); | 
					
						
							|  |  |  |  |     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 ****************/ |