该文主要是接上一部分LwIP 之 详解动态内存管理 内存堆(mem.c/h),该部分许多内容需要用到上一篇的内容。该部分主要是详细介绍LwIP中的动态内存池。整个内存池的实现相较于内存堆来说,还是麻烦点的。光是看源码中那一堆宏定义就够费劲!此外还有一点就是,该部分的文件结构也是挺有意思的,主要就是对于宏各种巧妙运用!
  LwIP的内存池实现对应的源码文件主要就是memp.c/h。除此之外,还有两个头文件memp_prive.hmemp_std.h
之前也说过,LwIP内存池的实现受制于两个宏值MEMP_MEM_MALLOCMEM_USE_POOLS的限制。在该部分的源码文件中,仍然到处可见这两个宏值。

memp_std.h

  该文件主要定义了LwIP内部的内存池,此外还通过#include "lwippools.h"的形式,将用户自定义的内存池包含进来。其为LwIP内部使用的文件,外部应用程序不应该使用该文件。这个文件被故意包含多次,一次使用LWIP_MEMPOOL()的空定义来处理所有include,后续多次包含用来构建各种mem池列表。
  该文件比较有意思,其中的宏值定义全部依赖于宏LWIP_MEMPOOL(name,num,size,desc),这样,只要外部提供的该宏值不同,则包含该文件后的源文件(通常为memp.h或memp_priv.h)在预处理后,就会产生不一样的结果。这样,就可以通过在不同的地方多次包含该文件(前面必定提供宏值MEMPOOL)以产生不同结果!下面来详细分析一下该文件。
  该文件的第一部分其实就是定义了三个宏值(第一个由memp.h或memp_priv.h提供),这三个宏值也就对应了LwIP所定义的三种内存池:

  • MEMPOOL: 标准内存池(这个宏通常来自别的文件memp.h或memp_priv.h,通过包含该文件形式定义对应的东西)
  • MALLOC_MEMPOOL: 提供给mem.c中的mem_malloc使用的内存池。前面说过,LwIP的内存堆可以用内存池来实现(依赖于MEMPOOL)。
  • PBUF_MEMPOOL: LwIP的pbuf结构使用的内存池(依赖于MEMPOOL)。pbuf再后面介绍!

上面的宏值为简写,没写参数部分。后面就是使用以上三个宏值,来定义不同的内存池!
  该文件的第二部分部分就是定义上面定义的宏值,来具体定义各种LwIP内部使用的内存池。其他文件(memp.h或memp_priv.h)包含该文件的地方,通过提供不同的MEMPOOL,该部分将产生不同的结果。其中有个地方需要注意一下:

#if MEMP_USE_CUSTOM_POOLS
#include "lwippools.h"
#endif /* MEMP_USE_CUSTOM_POOLS */

通过以上代码,将用户自己定义的内存池引入进来。同时也不难看出,如果用户配置了使用内存池,就必须要定义文件lwippools.h,,并且将自己需要定义的内存池放到该文件中。
  最后,将所有宏值进行反定义,这样就可以保证多次包含时,不会出现宏的重复定义!

memp_prive.h

  该文件定义了内存池的基本结构等,同样为LwIP内部使用的文件,外部应用程序不应该使用该文件。且该文件需要使用memp.h中定义枚举值。因此,这个文件的使用位置比较特殊,如下图

重点注意上图中,高亮部分的注释。下面详细分析以下该文件。
  该文件的第一部分为MEMP_OVERFLOW_CHECK,其主要用来进行内存池的溢出检查,这里不多做说明。
  接下来的第二大部分就是内存池各种结构的定义。首先第一个结构如下:

#if !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK
struct memp {struct memp *next;     /* 下一个链表 */
#if MEMP_OVERFLOW_CHECKconst char *file;            /* 发生溢出时调用函数的文件名,mem_malloc调用者的文件 */int line;                    /* 发生溢出时调用函数的行号,mem_malloc调用者的行数 */
#endif /* MEMP_OVERFLOW_CHECK */
};
#endif /* !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK */

LwIP的内存池是通过链表来组织的。上面的结构就是链表的节点结构了!
  接下来是一个比较复杂的枚举变量的定义。其实,这里面就定义了两个枚举变量MEMP_POOL_HELPER_START 和 MEMP_POOL_HELPER_END,后面的一堆东西就是给这两个枚举变量赋初值的。这其中就需要memp.h中定义的枚举变量memp_t中的值。

#if MEM_USE_POOLS && MEMP_USE_CUSTOM_POOLS
/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */
typedef enum {/* Get the first (via:MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/MEMP_POOL_HELPER_FIRST = ((u8_t)
#define LWIP_MEMPOOL(name,num,size,desc)
#define LWIP_MALLOC_MEMPOOL_START 1
#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0
#define LWIP_MALLOC_MEMPOOL_END
#include "lwip/priv/memp_std.h") ,/* Get the last (via:MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */MEMP_POOL_HELPER_LAST = ((u8_t)
#define LWIP_MEMPOOL(name,num,size,desc)
#define LWIP_MALLOC_MEMPOOL_START
#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *
#define LWIP_MALLOC_MEMPOOL_END 1
#include "lwip/priv/memp_std.h")
} memp_pool_helper_t;

首先说一下这个枚举变量是干啥的!之前曾经说过,LwIP的内存堆可以使用内存池来实现。那么为了实现该部分,内存池这里必须要提供必要的结构、接口来供内存堆实现时调用。其中,这个枚举结构就是定义出了内存池枚举memp_t中的用户定义的供内存堆使用的内存池的枚举界限!将这个枚举各部分展开后,就是如下

#if MEM_USE_POOLS && MEMP_USE_CUSTOM_POOLS
/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */
typedef enum {/* Get the first (via:MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)“MEMP_POOL_##size” 这个东西,就是之前定义的枚举memp_t中 ,用户自定义的内存池的枚举值,结果一步步替换后就成该名*/MEMP_POOL_HELPER_FIRST = ((u8_t)
#define LWIP_MEMPOOL(name,num,size,desc)
#define LWIP_MALLOC_MEMPOOL_START 1
#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0
#define LWIP_MALLOC_MEMPOOL_END// #if MEMP_USE_CUSTOM_POOLS
// #include "lwippools.h"
// #endif /* MEMP_USE_CUSTOM_POOLS */
// /* 这里将其展开之后就是如下 */
LWIP_MALLOC_MEMPOOL_START
LWIP_MALLOC_MEMPOOL(20, 256) -> MEMP_POOL_256
LWIP_MALLOC_MEMPOOL(10, 512) -> MEMP_POOL_512
LWIP_MALLOC_MEMPOOL(5, 1512) -> MEMP_POOL_1512
LWIP_MALLOC_MEMPOOL_END#undef LWIP_MEMPOOL
#undef LWIP_MALLOC_MEMPOOL
#undef LWIP_MALLOC_MEMPOOL_START
#undef LWIP_MALLOC_MEMPOOL_END
#undef LWIP_PBUF_MEMPOOL) ,  /*最终 MEMP_POOL_HELPER_START = 1*MEMP_POOL_256+0*MEMP_POOL_512+0*MEMP_POOL_1512 = MEMP_POOL_256*//* Get the last (via:MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) 结束值展开和上面一样不再说明 */MEMP_POOL_HELPER_LAST = ((u8_t)
#define LWIP_MEMPOOL(name,num,size,desc)
#define LWIP_MALLOC_MEMPOOL_START
#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *
#define LWIP_MALLOC_MEMPOOL_END 1
#include "lwip/priv/memp_std.h")/* 最终 MEMP_POOL_HELPER_LAST = 0 + MEMP_POOL_256 * 0 + MEMP_POOL_512 * 0 + MEMP_POOL_1512 * 1 = MEMP_POOL_1512 */
} memp_pool_helper_t;

最终,宏MEMP_POOL_HELPER_FIRST = MEMP_POOL_256,而宏MEMP_POOL_HELPER_LAST = MEMP_POOL_1512
  在接下来就是内存池描述符的结构定义了,在LwIP1.4.1版本中,以下各部分都是独立的,最新版中将其统一成了一个结构体。具体如下:

/** Memory pool descriptor */
struct memp_desc {
#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY/** Textual description */const char *desc;
#endif /* LWIP_DEBUG || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY */
#if MEMP_STATS/** Statistics */struct stats_mem *stats;
#endif/** Element size */u16_t size;
#if !MEMP_MEM_MALLOC/** Number of elements */u16_t num;/** Base address */u8_t *base;/** First free element of each pool. Elements form a linked list. */struct memp **tab;
#endif /* MEMP_MEM_MALLOC */
};

  该文件的最后一部分就是个接口的定义了,其实现均在memp.c文件中,后面会详细的说明。

memp.h

  该文件主要就是定义以下内存池使用的宏,结构等,其中部分结构放在了memp_priv.h文件中,如果之前看过LwIP1.4.1的源码就会知道,原来是没有memp_priv.h文件的,所有结构都在memp.h中,最新的源码进行结构调整。文件开始就是如下:

/* run once with empty definition to handle all custom includes in lwippools.h*/
#define LWIP_MEMPOOL(name,num,size,desc)    /* 这个宏为空 */
#include "lwip/priv/memp_std.h"   /* 其中的定义均是基于上面宏值得,也就成了空 */

结合memp_std.h不难发现,将各宏展开后其实就剩下两句:

#if MEMP_USE_CUSTOM_POOLS
#include "lwippools.h"
#endif

其实,再将上面展开后,里面定义的内存池也是无效的,如果文件lwippools.h中有引入其他文件或结构是,这几句唯一的作用就是将用户自定义的内存池时,用到的各种东西引入进来。否则以上就会全部为空,啥也不剩!
  接下来是如下几句,这个枚举就是列出LwIP中定义的各种内存池的对应的枚举值。

typedef enum {
#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_##name,    /* ## 为连接符 且会忽略##前后的空格, 例如:a ## b 其实就是 ab */
#include "lwip/priv/memp_std.h"MEMP_MAX
} memp_t;

这个用来为每个定义的内存池定义一个枚举变量值。memp_std.h中通过使用宏值#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,来定义各种枚举值,简单将宏值展开后,就是如下

typedef enum {/** A list of internal pools used by LWIP.** LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description)*  creates a pool name MEMP_pool_name. description is used in stats.c*/
#if LWIP_RAWMEMP_RAW_PCB,
#endif /* LWIP_RAW */#if LWIP_UDPMEMP_UDP_PCB,
#endif /* LWIP_UDP */#if LWIP_TCPMEMP_TCP_PCB,MEMP_TCP_PCB_LISTEN,MEMP_TCP_SEG,
#endif /* LWIP_TCP */#if LWIP_IPV4 && IP_REASSEMBLYMEMP_REASSDATA,
#endif /* LWIP_IPV4 && IP_REASSEMBLY */
#if (IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG)MEMP_FRAG_PBUF,
#endif /* IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF || (LWIP_IPV6 && LWIP_IPV6_FRAG) */#if LWIP_NETCONN || LWIP_SOCKETMEMP_NETBUF,MEMP_NETCONN,
#endif /* LWIP_NETCONN || LWIP_SOCKET */#if NO_SYS==0MEMP_TCPIP_MSG_API,
#if LWIP_MPU_COMPATIBLEMEMP_API_MSG,
#if LWIP_DNSMEMP_DNS_API_MSG,
#endif
#if LWIP_SOCKET && !LWIP_TCPIP_CORE_LOCKINGMEMP_SOCKET_SETGETSOCKOPT_DATA,
#endif
#if LWIP_NETIF_APIMEMP_NETIFAPI_MSG,
#endif
#endif /* LWIP_MPU_COMPATIBLE */
#if !LWIP_TCPIP_CORE_LOCKING_INPUTMEMP_TCPIP_MSG_INPKT,
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
#endif /* NO_SYS==0 */#if LWIP_IPV4 && LWIP_ARP && ARP_QUEUEINGMEMP_ARP_QUEUE,
#endif /* LWIP_IPV4 && LWIP_ARP && ARP_QUEUEING */#if LWIP_IGMPMEMP_IGMP_GROUP,
#endif /* LWIP_IGMP */#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOMMEMP_SYS_TIMEOUT,
#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */#if LWIP_DNS && LWIP_SOCKETMEMP_NETDB,
#endif /* LWIP_DNS && LWIP_SOCKET */
#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMICMEMP_LOCALHOSTLIST,
#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */#if LWIP_IPV6 && LWIP_ND6_QUEUEINGMEMP_ND6_QUEUE,
#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */#if LWIP_IPV6 && LWIP_IPV6_REASSMEMP_IP6_REASSDATA,
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */#if LWIP_IPV6 && LWIP_IPV6_MLDMEMP_MLD6_GROUP,
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD *//** A list of pools of pbuf's used by LWIP.** LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description)*    creates a pool name MEMP_pool_name. description is used in stats.c*     This allocates enough space for the pbuf struct and a payload.*     (Example: pbuf_payload_size=0 allocates only size for the struct)*/MEMP_PBUF,MEMP_PBUF_POOL,/** Allow for user-defined pools; this must be explicitly set in lwipopts.h* since the default is to NOT look for lwippools.h*/
// #if MEMP_USE_CUSTOM_POOLS
// #include "lwippools.h"
// /* 这里将其展开之后就是如下 */
// LWIP_MALLOC_MEMPOOL_START
// LWIP_MALLOC_MEMPOOL(20, 256) -> MEMP_POOL_256
// LWIP_MALLOC_MEMPOOL(10, 512) -> MEMP_POOL_512
// LWIP_MALLOC_MEMPOOL(5, 1512) -> MEMP_POOL_1512
// LWIP_MALLOC_MEMPOOL_END
// #endif /* MEMP_USE_CUSTOM_POOLS */
MEMP_POOL_256,
MEMP_POOL_512,
MEMP_POOL_1512,MEMP_MAX
} memp_t;

接下来,就是#include "lwip/priv/memp_priv.h" ,这个文件的引用必须放在这里,因为其内部会使用上面的枚举值(memp_t)。继续是一些宏定义,其中比较重要的就是LWIP_MEMPOOL_DECLARE(name,num,size,desc),这个宏最终用来定义出各内存池!而这其中,根据用户配置的宏值MEMP_MEM_MALLOCMEM_USE_POOLS的不同,会有不同的定义。其中前者方式下比较简单、后者则相对来说复杂一些!

  该文件的最后一部分就是个接口的定义了,其实现均在memp.c文件中,后面会详细的说明。

memp.c

  该文件主要就针对上面各种定义的具体实现了,整个文件代码并没多少行,看起来还是比较简单的。比较麻烦的就是上面对于宏函数的巧妙运用上。文件开头是如下结构

#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
#include "lwip/priv/memp_std.h"
/* 全局型指针数组,指向每类POOL的描述符 */
const struct memp_desc* const memp_pools[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name,
#include "lwip/priv/memp_std.h"
};

这里就是定义所有内存池了。看起来非常简单,但是真正展开各宏值才是比较麻烦的!再接下来就是具体的实现函数了,下面就以源码注释的形式进行说明(注意对于其中的调试用的函数或者安全性函数不进行说明)。


/*** Initialize custom memory pool.* Related functions: memp_malloc_pool, memp_free_pool** @param desc pool to initialize*/
void
memp_init_pool(const struct memp_desc *desc)
{#if MEMP_MEM_MALLOCLWIP_UNUSED_ARG(desc);
#elseint i;struct memp *memp;*desc->tab = NULL;memp = (struct memp*)LWIP_MEM_ALIGN(desc->base);     /* 将内存池起始空间进行对齐,这个宏在上一篇文章中有详细介绍 *//* create a linked list of memp elements */for (i = 0; i < desc->num; ++i) { /* 将该类所有POOL组成链表的形式 */memp->next = *desc->tab;*desc->tab = memp;
#if MEMP_OVERFLOW_CHECKmemp_overflow_init_element(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK *//* cast through void* to get rid of alignment warnings */memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size
#if MEMP_OVERFLOW_CHECK+ MEMP_SANITY_REGION_AFTER_ALIGNED
#endif);}
#if MEMP_STATSdesc->stats->avail = desc->num;
#endif /* MEMP_STATS */
#endif /* !MEMP_MEM_MALLOC */#if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY)desc->stats->name  = desc->desc;
#endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */
}/*** Initializes lwIP built-in pools.* Related functions: memp_malloc, memp_free** Carves out memp_memory into linked lists for each pool-type.*/
void
memp_init(void)
{u16_t i;/* 对每个定义的内存池进行初始化 */for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) {memp_init_pool(memp_pools[i]);     /* 初始化是根据文件开头定义的内存池描述符(memp_pools数组)表进行的 */#if LWIP_STATS && MEMP_STATSlwip_stats.memp[i] = memp_pools[i]->stats;
#endif}#if MEMP_OVERFLOW_CHECK >= 2/* check everything a first time to see if it worked */memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
}static void*
#if !MEMP_OVERFLOW_CHECK
do_memp_malloc_pool(const struct memp_desc *desc)
#else
do_memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line)
#endif
{struct memp *memp;SYS_ARCH_DECL_PROTECT(old_level);/* 临界保护区 */#if MEMP_MEM_MALLOCmemp = (struct memp *)mem_malloc(MEMP_SIZE + MEMP_ALIGN_SIZE(desc->size));SYS_ARCH_PROTECT(old_level);
#else /* MEMP_MEM_MALLOC */SYS_ARCH_PROTECT(old_level);/* 进入临界区 */memp = *desc->tab;
#endif /* MEMP_MEM_MALLOC */if (memp != NULL) {#if !MEMP_MEM_MALLOC
#if MEMP_OVERFLOW_CHECK == 1memp_overflow_check_element_overflow(memp, desc);memp_overflow_check_element_underflow(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */*desc->tab = memp->next;
#if MEMP_OVERFLOW_CHECKmemp->next = NULL;
#endif /* MEMP_OVERFLOW_CHECK */
#endif /* !MEMP_MEM_MALLOC */
#if MEMP_OVERFLOW_CHECKmemp->file = file;memp->line = line;
#if MEMP_MEM_MALLOCmemp_overflow_init_element(memp, desc);
#endif /* MEMP_MEM_MALLOC */
#endif /* MEMP_OVERFLOW_CHECK */LWIP_ASSERT("memp_malloc: memp properly aligned",((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
#if MEMP_STATSdesc->stats->used++;if (desc->stats->used > desc->stats->max) {desc->stats->max = desc->stats->used;}
#endifSYS_ARCH_UNPROTECT(old_level);/* cast through u8_t* to get rid of alignment warnings */return ((u8_t*)memp + MEMP_SIZE);} else {LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", desc->desc));
#if MEMP_STATSdesc->stats->err++;
#endif}SYS_ARCH_UNPROTECT(old_level);/* 退出临界区 */return NULL;
}/*** Get an element from a custom pool.** @param desc the pool to get an element from** @return a pointer to the allocated memory or a NULL pointer on error*/
void *
#if !MEMP_OVERFLOW_CHECK
memp_malloc_pool(const struct memp_desc *desc)
#else
memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line)
#endif
{LWIP_ASSERT("invalid pool desc", desc != NULL);if (desc == NULL) {return NULL;}#if !MEMP_OVERFLOW_CHECKreturn do_memp_malloc_pool(desc);
#elsereturn do_memp_malloc_pool_fn(desc, file, line);
#endif
}/*** Get an element from a specific pool.** @param type the pool to get an element from** @return a pointer to the allocated memory or a NULL pointer on error*//* 分配过程是如果memp_tab[]数组中相应链表的指针为空,说明该类型的POOL已经没有了,分配失败;否则选择链表中的第一个POOL,并在POOL最开始处预留出MEMP_SIZE(这里为0)的空间,最后将有效地址返回给函数调用者。*/
void *
#if !MEMP_OVERFLOW_CHECK
memp_malloc(memp_t type)
#else
memp_malloc_fn(memp_t type, const char* file, const int line)
#endif
{void *memp;LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);#if MEMP_OVERFLOW_CHECK >= 2memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */#if !MEMP_OVERFLOW_CHECKmemp = do_memp_malloc_pool(memp_pools[type]);
#elsememp = do_memp_malloc_pool_fn(memp_pools[type], file, line);
#endifreturn memp;
}static void
do_memp_free_pool(const struct memp_desc* desc, void *mem)
{struct memp *memp;SYS_ARCH_DECL_PROTECT(old_level);LWIP_ASSERT("memp_free: mem properly aligned",((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);/* cast through void* to get rid of alignment warnings */memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);SYS_ARCH_PROTECT(old_level);  /* 进入临界区 */#if MEMP_OVERFLOW_CHECK == 1memp_overflow_check_element_overflow(memp, desc);memp_overflow_check_element_underflow(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */#if MEMP_STATSdesc->stats->used--;
#endif#if MEMP_MEM_MALLOCLWIP_UNUSED_ARG(desc);SYS_ARCH_UNPROTECT(old_level);mem_free(memp);
#else /* MEMP_MEM_MALLOC */memp->next = *desc->tab;*desc->tab = memp;#if MEMP_SANITY_CHECKLWIP_ASSERT("memp sanity", memp_sanity(desc));
#endif /* MEMP_SANITY_CHECK */SYS_ARCH_UNPROTECT(old_level);        /* 退出临界区 */
#endif /* !MEMP_MEM_MALLOC */
}/*** Put a custom pool element back into its pool.** @param desc the pool where to put mem* @param mem the memp element to free*/
void
memp_free_pool(const struct memp_desc* desc, void *mem)
{LWIP_ASSERT("invalid pool desc", desc != NULL);if ((desc == NULL) || (mem == NULL)) {return;}do_memp_free_pool(desc, mem);
}/*** Put an element back into its pool.** @param type the pool where to put mem* @param mem the memp element to free*//* 内存池释放 */
void
memp_free(memp_t type, void *mem)
{#ifdef LWIP_HOOK_MEMP_AVAILABLEstruct memp *old_first;
#endifLWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;);if (mem == NULL) {return;}#if MEMP_OVERFLOW_CHECK >= 2memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */#ifdef LWIP_HOOK_MEMP_AVAILABLEold_first = *memp_pools[type]->tab;
#endifdo_memp_free_pool(memp_pools[type], mem);#ifdef LWIP_HOOK_MEMP_AVAILABLEif (old_first == NULL) {LWIP_HOOK_MEMP_AVAILABLE(type);}
#endif
}

还有好多解释没完善的地方,后续用到在整理。。

LwIP 之六 详解动态内存管理 内存池(memp.c/h)相关推荐

  1. LwIP 之五 详解动态内存管理 内存堆(mem.c/h)

    写在前面   目前网上有很多介绍LwIP内存的文章,但是绝大多数都不够详细,甚至很多介绍都是错误的!无论是代码的说明还是给出的图例,都欠佳!下面就从源代码,到图例详细进行说明.   目前,网络上多数文 ...

  2. LwIP 之六 详解内存池(memp.c/h)动态内存管理策略

      对于嵌入式开发来说,内存管理及使用是至关重要的,内存的使用多少.内存泄漏等时刻需要注意!合理的内存管理策略将从根本上决定内存分配和回收效率,最终决定系统的整体性能.LwIP 就提供了 动态内存堆管 ...

  3. 三星服务器内存条型号区分,三星内存铭牌详解|三星内存条标签内存参数详解...

    三星内存铭牌详解|三星内存条标签内存参数详解 大多数朋友都清楚内存铭牌上,记录着内存的重要数据.但是大多数朋友都对此不甚了然!为此小编也想学习下,现在把相关的学习笔记分享出来,希望和朋友们显摆下,小编 ...

  4. linux根-文件系统-目录管理-文件管理-用户及权限详解-用户组-用户管理-权限管理...

    一 .Linux文件结构 文件结构是文件存放在磁盘等存贮设备上的组织方法.主要体现在对文件和目录的组织上. 目录提供了管理文件的一个方便而有效的途径. Linux使用标准的目录结构,在安装的时候,安装 ...

  5. smss.exe是什么进程?详解Windows会话管理器中的smss.exe

    smss.exe是什么进程?详解Windows会话管理器中的smss.exe 进程综述 smss.exe是什么进程?详解Windows会话管理器中的smss.exe-冯金伟博客园smss.exe是什么 ...

  6. [深入浅出Cocoa]之消息(二)-详解动态方法决议(Dynamic Method Resolution)

    [深入浅出Cocoa]之消息(二)-详解动态方法决议(Dynamic Method Resolution) 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循&quo ...

  7. Android UI详解之布局管理器(一)

    Android UI详解之布局管理器 一.布局管理器 ①顶级父类View ②子类GroupView ③AbsoluteLayout.FrameLayout.LinearLayout.GridLayou ...

  8. Mybatis的特性详解——动态SQL

    Mybatis的特性详解--动态SQL 前言 一.动态sql的元素 1.MyBatis if标签:条件判断 2.MyBatis choose.when和otherwise标签 3.MyBatis wh ...

  9. 内存管理-内存池的实现

    内存池的实现 1 前言 2 内存池的原理 2.1 内存利用链表进行管理 2.2 分配固定大小 2.3 按块进行内存管理 3 内存池的实现 3.1 内存池的创建 3.2 内存池的销毁 3.3 内存分配 ...

最新文章

  1. cmd 文本替换_将CMD信息保存为文件
  2. Javascript--键盘事件的组合使用
  3. nginx实现web负载均衡
  4. gradient杂谈
  5. 杭电1978java实现
  6. 查找有权限使用某个T-Code的所有用户列表
  7. linux网络设备—mdio总线
  8. java国际化bundle_Java国际化(i18n)ResourceBundle类
  9. EWSN 2019 (待续)
  10. 当MVP与阿里云一起踏上西行远征——阿里云MVP“戈壁之路”徒步记行
  11. 电商独立站-谷歌SEO指标
  12. java 全局钩子_[原]在全局鼠标钩子中模拟鼠标右键单击
  13. MPC(模型预测控制)控制小车沿轨迹移动——C++实现
  14. 【混音教程】开启你的混音生涯的6个心法|MZD Studios
  15. 卡西欧科学计算机使用方法,卡西欧科学计算器使用教程
  16. linux vga 驱动,Linux VGA驱动移植实验【转】
  17. 地图省界线什么样_地图上省份的划分精细复杂,为何分得这么细致?原来有这么多学问...
  18. python剪刀石头布_python练习案例--剪刀石头布
  19. 科技战疫,多家科技企业IT工程师驻地武汉驰援
  20. 自动化学报- Teleoperation

热门文章

  1. tomcat基本知识点与实例
  2. Centos7 下安装配置tomcat7
  3. iOS开发-面试总结(十四)
  4. s7-300 第9讲 定时器
  5. freemarker入门实例与源码研究准备工作
  6. python实现gif动画(matplotlib、imageio、pillow))
  7. java防止库存超买_java初探(1)之防止库存为负以及防超买
  8. 猛增 110K Star!年增长数最多的 10 大顶级前端学习资源项目!
  9. spring boot基础配置
  10. reactjs脚手架目录结构说明