您的位置:首页 > 其它

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所示。
  
[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分配内存的方式都不一样,如图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);

  }

}

复制代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: