SylixOS_LWIP协议栈学习:数据包管理
2017-04-11 15:52
423 查看
在《SylixOS_LWIP协议栈学习: 动态内存管理》中提到过:LWIP中常用的内存分配策略有两种,一种是内存堆分配,一种是内存池分配。
内存堆能分配合理的任意大小的内存块,缺点是当经过多次的分配释放后,内存堆中间会出现很多碎片,使得需要分配较大内存块时分配失败;
内存池分配速度快,通过简单的链表操作(各种类型的 POOL 已经分配内存,大小固定),但是采用 POOL 会浪费掉一定的内存空间。
在 LWIP 数据包管理中,将这两种分配策略混合使用,达到了很好的内存使用效率。
Pbuf的结构体定义如下:
struct pbuf {
struct pbuf *next; /*指向下一个buf */
void *payload; /*指向pbuf数据中的起始位置 */
u16_t tot_len; /*该pbuf和后续pbuf中数据长度的总和 */
u16_t len; /*该pbuf中数据的长度 */
u8_t type; /*pbuf的类型,pbuf_type */
u8_t flags; /*misc flag */
u16_t ref; /*该pbuf引用计数(仅当ref=1时,该pbuf才允许删除)*/
};
其中Pbuf_type类型枚举如下:
typedef enum {
PBUF_RAM, /* pbuf data is stored in RAM */
PBUF_ROM, /* pbuf data is stored in ROM */
PBUF_POOL, /* pbuf comes from the pbuf pool */
PBUF_REF /* pbuf payload refers to RAM */
} pbuf_type;
即pbuf 的类型有四类:PBUF_RAM、 PBUF_ROM、 PBUF_REF、 PBUF_POOL
PBUF_RAM 类型的 pbuf 主要通过内存堆分配得到的。这种类型的 pbuf 在协议栈中是用得最多的。协议栈要发送的数据和应用程序要传递的数据一般都采用这个形式。
PBUF_POOL 类型和 PBUF_RAM 类型的 pbuf 有很大的相似之处,但它主要通过内存池分配得到的。这种类型的 pbuf 可以在极短的时
间内得到分配。在接受数据包时, LWIP 一般采用这种方式包装数据。
PBUF_ROM 和 PBUF_REF 类型的 pbuf 基本相同,它们的申请都是在内存堆中分配一个相应的 pbuf 结构头,而不申请数据区的空间。这就是它们与 PBUF_RAM 和 PBUF_POOL的最大区别。
PBUF_ROM 和 PBUF_REF 类型的区别在于前者指向 ROM 空间内的某段数据,而后者指向 RAM 空间内的某段数据。
它们的特点和使用场合如表1所示。
每一种pbuf分配内存的方式都不一样,如图2所示。
只有选择合适的pbuf类型才能发挥LWIP的最大性能,一个数据包可能是多种pbuf的组合,用链表连接起来,如图3所示。
总结:
在(/libsylixos/SylixOS/config/net/net_perf_cfg.h)中,对于系统总pubf数量是可以配置的。
在现阶段写的接收函数中,pbuf通过netdev_pbuf_alloc()函数申请。申请的类型为PBUF_POOL。
申请:PBUF_POOL最终调用memp_malloc(MEMP_PBUF_POOL)函数;PBUF_ROM 和
PBUF_REF最终调用memp_malloc(MEMP_PBUF)函数;
PBUF_RAM最终调用mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset)+ LWIP_MEM_ALIGN_SIZE(length))函数。
释放:PBUF_POOL 类型和PBUF_ROM 类型、 PBUF_REF 类型需要通过 memp_free()函数删除,
PBUF_RAM 类型需要通过 mem_free()函数删除。
在mem_free()函数进行内存释放的时候,为了防止内存碎片的产生,上一个与下一个分配块的使用标志会被检查,
如果他们中的任何一个还未被使用,这个内存块将被合并到一个更大的未使用内存块中。(如果上一个与下一个分配块都已被使用,仍无法避免产生内存碎片)
附录:
/**
* "Plug holes" by combining adjacent empty struct mems.
* After this function is through, there should not exist
* one empty struct mem pointing to another empty struct mem.
*
* @param mem this points to a struct mem which just has been freed
* @internal this function is only called by mem_free() and mem_trim()
*
* This assumes access to the heap is protected by the calling function
* already.
*/
static void
plug_holes(struct mem *mem)
{
struct mem *nmem;
struct mem *pmem;
LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
/* plug hole forward */
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
nmem = (struct mem *)(void *)&ram[mem->next];
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
/* if mem->next is unused and not end of ram, combine mem and mem->next */
if (lfree == nmem) {
lfree = mem;
}
mem->next = nmem->next;
((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
}
/* plug hole backward */
pmem = (struct mem *)(void *)&ram[mem->prev];
if (pmem != mem && pmem->used == 0) {
/* if mem->prev is unused, combine mem and mem->prev */
if (lfree == mem) {
lfree = pmem;
}
pmem->next = mem->next;
((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
}
}
复制代码
内存堆能分配合理的任意大小的内存块,缺点是当经过多次的分配释放后,内存堆中间会出现很多碎片,使得需要分配较大内存块时分配失败;
内存池分配速度快,通过简单的链表操作(各种类型的 POOL 已经分配内存,大小固定),但是采用 POOL 会浪费掉一定的内存空间。
在 LWIP 数据包管理中,将这两种分配策略混合使用,达到了很好的内存使用效率。
Pbuf的结构体定义如下:
struct pbuf {
struct pbuf *next; /*指向下一个buf */
void *payload; /*指向pbuf数据中的起始位置 */
u16_t tot_len; /*该pbuf和后续pbuf中数据长度的总和 */
u16_t len; /*该pbuf中数据的长度 */
u8_t type; /*pbuf的类型,pbuf_type */
u8_t flags; /*misc flag */
u16_t ref; /*该pbuf引用计数(仅当ref=1时,该pbuf才允许删除)*/
};
其中Pbuf_type类型枚举如下:
typedef enum {
PBUF_RAM, /* pbuf data is stored in RAM */
PBUF_ROM, /* pbuf data is stored in ROM */
PBUF_POOL, /* pbuf comes from the pbuf pool */
PBUF_REF /* pbuf payload refers to RAM */
} pbuf_type;
即pbuf 的类型有四类:PBUF_RAM、 PBUF_ROM、 PBUF_REF、 PBUF_POOL
PBUF_RAM 类型的 pbuf 主要通过内存堆分配得到的。这种类型的 pbuf 在协议栈中是用得最多的。协议栈要发送的数据和应用程序要传递的数据一般都采用这个形式。
PBUF_POOL 类型和 PBUF_RAM 类型的 pbuf 有很大的相似之处,但它主要通过内存池分配得到的。这种类型的 pbuf 可以在极短的时
间内得到分配。在接受数据包时, LWIP 一般采用这种方式包装数据。
PBUF_ROM 和 PBUF_REF 类型的 pbuf 基本相同,它们的申请都是在内存堆中分配一个相应的 pbuf 结构头,而不申请数据区的空间。这就是它们与 PBUF_RAM 和 PBUF_POOL的最大区别。
PBUF_ROM 和 PBUF_REF 类型的区别在于前者指向 ROM 空间内的某段数据,而后者指向 RAM 空间内的某段数据。
它们的特点和使用场合如表1所示。
[align=left]类别[/align] | [align=left]分配方式[/align] | [align=left]特点[/align] | [align=left]使用场合[/align] |
[align=left]PBUF_RAM[/align] | [align=left]内存堆,包括pbuf和数据区[/align] | [align=left]长度不定,分配耗时[/align] | [align=left]应用程序和协议栈[/align] |
[align=left]PBUF_POOL[/align] | [align=left]内存池,包括pbuf和数据区[/align] | [align=left]长度固定,分配快[/align] | [align=left]中断服务程序[/align] |
[align=left]PBUF_ROM[/align] | [align=left]内存池,仅包括pbuf[/align] | [align=left]所指数据位于ROM中[/align] | [align=left]应用程序引用内存区[/align] |
[align=left]PBUF_REF[/align] | [align=left]内存池,仅包括pbuf[/align] | [align=left]所指数据位于RAM中[/align] | [align=left]应用程序引用内存区[/align] |
只有选择合适的pbuf类型才能发挥LWIP的最大性能,一个数据包可能是多种pbuf的组合,用链表连接起来,如图3所示。
总结:
在(/libsylixos/SylixOS/config/net/net_perf_cfg.h)中,对于系统总pubf数量是可以配置的。
在现阶段写的接收函数中,pbuf通过netdev_pbuf_alloc()函数申请。申请的类型为PBUF_POOL。
申请:PBUF_POOL最终调用memp_malloc(MEMP_PBUF_POOL)函数;PBUF_ROM 和
PBUF_REF最终调用memp_malloc(MEMP_PBUF)函数;
PBUF_RAM最终调用mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset)+ LWIP_MEM_ALIGN_SIZE(length))函数。
释放:PBUF_POOL 类型和PBUF_ROM 类型、 PBUF_REF 类型需要通过 memp_free()函数删除,
PBUF_RAM 类型需要通过 mem_free()函数删除。
在mem_free()函数进行内存释放的时候,为了防止内存碎片的产生,上一个与下一个分配块的使用标志会被检查,
如果他们中的任何一个还未被使用,这个内存块将被合并到一个更大的未使用内存块中。(如果上一个与下一个分配块都已被使用,仍无法避免产生内存碎片)
附录:
/**
* "Plug holes" by combining adjacent empty struct mems.
* After this function is through, there should not exist
* one empty struct mem pointing to another empty struct mem.
*
* @param mem this points to a struct mem which just has been freed
* @internal this function is only called by mem_free() and mem_trim()
*
* This assumes access to the heap is protected by the calling function
* already.
*/
static void
plug_holes(struct mem *mem)
{
struct mem *nmem;
struct mem *pmem;
LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
/* plug hole forward */
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
nmem = (struct mem *)(void *)&ram[mem->next];
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
/* if mem->next is unused and not end of ram, combine mem and mem->next */
if (lfree == nmem) {
lfree = mem;
}
mem->next = nmem->next;
((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
}
/* plug hole backward */
pmem = (struct mem *)(void *)&ram[mem->prev];
if (pmem != mem && pmem->used == 0) {
/* if mem->prev is unused, combine mem and mem->prev */
if (lfree == mem) {
lfree = pmem;
}
pmem->next = mem->next;
((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
}
}
复制代码
相关文章推荐
- LwIP协议栈学习--内存管理
- SylixOS_LWIP协议栈学习:网络接口结构
- SylixOS_LWIP协议栈学习:以太网网卡接口部分初始化
- LWIP数据包管理学习
- SylixOS_LWIP协议栈学习:动态内存管理
- 终于找到最全的(LwIP协议栈学习--内存管理)
- LwIP协议栈学习--内存管理
- LwIP协议栈学习--内存管理
- 学习Linux-4.12内核网路协议栈(2.4)——接口层数据包的发送
- ARM硬件平台上基于UCOS移植Lwip网络协议栈 分类: 嵌入式开发学习 2015-06-14 10:33 55人阅读 评论(1) 收藏
- ZigBee ZStack 协议栈学习-- 一个数据包的艺术之旅
- lwip之数据包管理
- LwIP 协议栈源码详解 ——TCP/IP 协议的实现(四:数据包 pbuf )
- 学习Linux-4.12内核网路协议栈(2.2)——接口层数据包的接收(上半部)
- LWIP数据包管理
- LwIP协议栈的学习与应用
- [LWIP学习]--tcpip_input,tcpip_inpkt,tcpip_thread函数分析(协议栈入口)
- lwip协议栈学习---udp
- 分析和学习Spring中的jpetstore用户管理
- 知识管理系统的学习(一)