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

 

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