先看memp_t,這是一個枚舉體,定義了所有內存池的類型。
typedef enum {
#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,
#include "lwip/memp_std.h"
MEMP_MAX
} memp_t;
枚舉體包含了一個頭文件,對頭文件進行展開
typedef enum {
#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,
......
#if LWIP_RAW
LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB")
#endif
#if LWIP_UDP
LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB")
#endif
#if LWIP_TCP
LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB")
LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN")
LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG")
#endif
......
#undef LWIP_MEMPOOL
......
MEMP_MAX
} memp_t;
進一步,對宏LWIP_MEMPOOL進行展開,最終得到memp_t類型如下
typedef enum {
MEMP_RAW_PCB,
MEMP_UDP_PCB,
MEMP_TCP_PCB,
MEMP_TCP_PCB_LISTEN,
MEMP_TCP_SEG,
......
MEMP_MAX
} memp_t;
按照上面的原理,編譯的時候,會建立起來幾個全局變量
/* 各個內存池單元大小 */
const u16_t memp_sizes[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
#include "lwip/memp_std.h"
};
展開後
const u16_t memp_sizes[MEMP_MAX] = {
LWIP_MEM_ALIGN_SIZE(sizeof(struct raw_pcb)),
LWIP_MEM_ALIGN_SIZE(sizeof(struct udp_pcb)),
LWIP_MEM_ALIGN_SIZE(sizeof(struct tcp_pcb)),
LWIP_MEM_ALIGN_SIZE(sizeof(struct tcp_pcb_listen)),
LWIP_MEM_ALIGN_SIZE(sizeof(struct tcp_seg)),
...
};
/* 各個內存池單元個數數組 */
static const u16_t memp_num[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) (num),
#include "lwip/memp_std.h"
};
展開後
static const u16_t memp_num[MEMP_MAX] = {
MEMP_NUM_RAW_PCB,
MEMP_NUM_UDP_PCB,
MEMP_NUM_TCP_PCB,
MEMP_NUM_TCP_PCB_LISTEN,
MEMP_NUM_TCP_SEG,
...
};
/* 所有內存池空間 */
static u8_t memp_memory[MEM_ALIGNMENT - 1
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
#include "lwip/memp_std.h"
];
展開後
static u8_t memp_memory[MEM_ALIGNMENT - 1
+ (MEMP_NUM_RAW_PCB) * (MEMP_SIZE + MEMP_ALIGN_SIZE(sizeof(struct raw_pcb)))
+ (MEMP_NUM_UDP_PCB) * (MEMP_SIZE + MEMP_ALIGN_SIZE(sizeof(struct udp_pcb)))
+ (MEMP_NUM_TCP_PCB) * (MEMP_SIZE + MEMP_ALIGN_SIZE(sizeof(struct tcp_pcb)))
+ (MEMP_NUM_TCP_PCB_LISTEN) * (MEMP_SIZE + MEMP_ALIGN_SIZE(sizeof(struct tcp_pcb_listen)))
+ (MEMP_NUM_TCP_SEG) * (MEMP_SIZE + MEMP_ALIGN_SIZE(sizeof(struct tcp_seg)))
];
接下來再看一個結構體,這個結構體用於將內存池單元連接成鏈表
/* 內存池單元結構體 */
struct memp {
struct memp *next;
};
而下面這個數組用於指向各個內存池鏈表中的第一個空閒單元
static struct memp *memp_tab[MEMP_MAX];
接下來看一下內存池相關的API
/* 初始化內存池 */
void memp_init(void)
{
struct memp *memp;
u16_t i, j;
/* 內存池所在內存地址 */
memp = LWIP_MEM_ALIGN(memp_memory);
/* 將內存分割成各個內存池 */
for (i = 0; i < MEMP_MAX; ++i) {
/* 將各個內存池單元連接成鏈表 */
memp_tab[i] = NULL;
for (j = 0; j < memp_num[i]; ++j) {
memp->next = memp_tab[i];
memp_tab[i] = memp;
memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]);
}
}
}
初始化完成之後,內存池空間被組織成如下結構
/* 申請一個內存池單元 */
void *memp_malloc(memp_t type)
{
struct memp *memp;
/* 內存池空閒單元指針 */
memp = memp_tab[type];
/* 鏈表頭部取出一個單元 */
if (memp != NULL) {
memp_tab[type] = memp->next;
memp = (struct memp *)((u8_t *)memp + MEMP_SIZE);
}
/* 返回內存地址 */
return memp;
}
/* 釋放一個內存池單元 */
void memp_free(memp_t type, void *mem)
{
struct memp *memp;
if (mem == NULL) {
return;
}
/* 將內存地址轉換爲內存池單元指針 */
memp = (struct memp *)((u8_t*)mem - MEMP_SIZE);
/* 將內存池單元插入相應鏈表頭部 */
memp->next = memp_tab[type];
memp_tab[type] = memp;
}