LwIP之动态内存池

先看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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章