0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于DWC_ether_qos的以太网驱动开发-LWIP的内存池介绍

嵌入式USB开发 来源:嵌入式Lee 作者:嵌入式Lee 2023-09-07 08:45 次阅读

本文转自公众号,欢迎关注

https://mp.weixin.qq.com/s/mBoGSf_u9edFF01U_OZT9g

一.前言

lwIP为基础结构提供了专用的内存池管理,比如netconn,protocol控制块,包缓存等。在memp.c下实现。

LWIP的内存池有两种方式实现,通过宏MEMP_MEM_MALLOC配置,默认opt.h中配置为0.

配置为1使用mem_malloc/mem_free mem.c

配置为0使用单独实现memp.c。

我们这里重点讲后者。

二.相关源码

src/core/memp.c

src/include/lwip/memp.h

src/include/lwip/priv/memp_std.h

src/include/lwip/priv/memp_priv.h

三.源码分析

3.1数据结构

内存池的关键数据结构是struct memp_desc对应内存池节点,一个类型的内存池是一个节点,

多个类型的内存池可以作为链表一起管理。

内存池最基本的数据结构是由宏LWIP_MEMPOOL_DECLARE定义的,

该宏在memp.h根据MEMP_MEM_MALLOC的配置实现为

#define LWIP_MEMPOOL_DECLARE(name,num,size,desc)

#define LWIP_MEMPOOL_DECLARE(name,num,size,desc)

前者是使用mem_malloc/mem_free实现内存池时使用,后者是单独实现时使用,我们重点关注后者。

其中LWIP_DECLARE_MEMORY_ALIGNED可以用户实现,如果用户未定义,arch.h默认是

#ifndef LWIP_DECLARE_MEMORY_ALIGNED

即定义了一个数组variable_name,其大小是LWIP_MEM_ALIGN_BUFFER(size)

LWIP_MEM_ALIGN_BUFFER可以用户实现,如果用户未定义,arch.h中默认为

#ifndef LWIP_MEM_ALIGN_BUFFER

即人为的放大了,保证对齐之后始终能保证有足够size的空间。

比如size是8,但是数组的基地址则可能是任意地址,比如是0x0001,要保证地址4字节对齐,

那么只能往后移动实际用的地址是0x0004,那么前面就浪费了3字节,此时8+(4-1)多分配3字节则浪费了这3字节也能保证剩余8字节可用8+(4-1)-3=8。

如果地址是0x0002则浪费2字节,可用8+(4-1)-2>8大于2字节,其他情况类似。

其中MEM_ALIGNMENT在opt中默认为1,用户在lwipopts.h中可以配置。

继续来看宏LWIP_MEMPOOL_DECLARE_STATS_INSTANCE和LWIP_MEMPOOL_DECLARE_STATS_REFERENCE,memp_priv.h中

如果定义了宏MEMP_STATS即使能统计信息,则LWIP_MEMPOOL_DECLARE_STATS_INSTANCE定义了结构体变量static struct stats_mem name;

LWIP_MEMPOOL_DECLARE_STATS_REFERENCE即&name,该变量地址

否则都是空

#if MEMP_STATS

其中stats.h中truct stats_mem如下

/** Memory stats */

继续看DECLARE_LWIP_MEMPOOL_DESC,memp_priv.h中

如果定义了宏LWIP_DEBUG,MEMP_OVERFLOW_CHECK,LWIP_STATS_DISPLAY三者之一,实际就是成员赋值为desc,否则为空。

#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY

继续看LWIP_MEM_ALIGN_SIZE,在arch.h中默认实现,即向上对齐,MEM_ALIGNMENT对齐必须是2的指数。

#ifndef LWIP_MEM_ALIGN_SIZE

最终LWIP_MEMPOOL_DECLARE(name,num,size,desc)展开后为

u8_t memp_memory_name_base[LWIP_MEM_ALIGN_BUFFER(((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size))))]

static struct stats_mem memp_stats_name;

static struct memp*memp_tab_name;

const struct memp_desc memp_name= {

desc,

&memp_stats_name,

LWIP_MEM_ALIGN_SIZE(size),

num,

memp_memory_ name_base,

&memp_tab_name

};

即定义一个数组作为存储,一个统计变量,一个static struct memp指针变量,一个结构变量static struct memp。

其中struct memp

#if !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK

其中struct memp_desc

/** Memory pool descriptor */

3.2内存池接口

LWIP_MEMPOOL_DECLARE(my_private_pool, 10, sizeof(foo), "Some description")

即上面数据结构说明的,使用该宏定义节点相关存储数组,变量等。

LWIP_MEMPOOL_INIT(my_private_pool) ->memp_init_pool

将节点的存储链表形式串起来。

*desc->tab指向最后一个item。

void* my_new_mem = LWIP_MEMPOOL_ALLOC(my_private_pool);->memp_malloc_pool

从链表中取出一个item。

LWIP_MEMPOOL_FREE(my_private_pool, my_new_mem);->memp_free_pool

Item插入到链表中

这里管理内存池实际可以用上述的链表形式,也可以用bitmap形式。

上述用链表形式每次malloc(出链表),free(入链表)都是堆链表尾,*desc->tab操作,执行时间固定。

而bitmap需要使用for循环去查询空闲bit执行时间不固定,当然也可以使用类似ucOS优先级调度的查表法来优化。

四.内部使用的内存池

数据结构中分析了LWIP_MEMPOOL_DECLARE宏,实际就是定义内存节点相关的变量(存储数组,统计变量,描述结构等)

用户可以直接使用内存池接口。

而lwip内部也使用了内存池进行管理,见memp.c/memp.h

4.1内部使用内存池

memp.h中

/* run once with empty definition to handle all custom includes in lwippools.h */

第一个#include "lwip/priv/memp_std.h"前因为LWIP_MEMPOOL为空,所以include memp_std.h进来所有的LWIP_MEMPOOL为空,此时相当于只是include进来memp_std.h中包含的头文件。

后一个#include "lwip/priv/memp_std.h"前LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,

所以include memp_std.h后相当于,定义了MEMP_xxx的枚举

展开就是(当然要对应的宏使能才会有)

typedef enum {

RAW_PCB_RAW_PCB,

UDP_PCB_UDP_PCB,

......

MEMP_MAX

} memp_t;

注意每次memp_std.h中都undef了相关宏,所以不影响后续使用。

这里是一个小的编程技巧,一个头文件不同的宏配置下展开为不同的内容。

而memp.c中

#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)

第一个包含memp_std.h 根据LWIP_MEMPOOL_DECLARE,定义了各个内存池节点

后一个memp_std.h则根据LWIP_MEMPOOL(name,num,size,desc) & name展开

即定义了一个结构体数组,数组的成员即上面定义的内存池节点。

const struct memp_desc *const memp_pools[MEMP_MAX] = {

&RAW_PCB,

......

};

所有使用到内建内存池总结如下

4.2内部使用内存池接口

以下都是调用内存池接口,不再赘述。

memp_free

memp_free_pool

memp_malloc

memp_malloc_pool

memp_init

五.堆使用内存池实现

前面我们看到定义宏MEMP_MEM_MALLOC,memp.c内存池可以使用mem.c堆实现.

反过来定义宏MEM_USE_POOLS,mem.c也可以用memp.c内存池实现.所以可以看出LWIP的堆管理实现方式比较灵活的,可以根据实际应用配置。

在opt.h中MEM_USE_POOLS是默认配置为0的,可以在lwipopts.h中修改配置。

#if !defined MEM_USE_POOLS || defined __DOXYGEN__

如果MEMP_USE_CUSTOM_POOLS配置为1,则MEMP_USE_CUSTOM_POOLS也要配置为1

此时

memp_std.h中

/*

可以看出,用户必须提供lwippools.h文件,申明对应的内存池节点。

即在原来memp_t和memp_pools的基础上后面继续添加节点。

内容如下

LWIP_MALLOC_MEMPOOL_START

此时mem_malloc则从

memp_pools中

MEMP_POOL_FIRST~MEMP_POOL_LAST处

搜搜,找到有节点有空闲空间,大小满足所需大小的即止。

即如下获取MEMP_POOL_HELPER_FIRST和MEMP_POOL_HELPER_LAST

#if MEM_USE_POOLS && MEMP_USE_CUSTOM_POOLS

六.总结

内存池适合分配大小固定的动态内存分配,比如用于协议包等的缓存等;

算法简单,执行时间固定,比较可靠。但是其存储是单独分配的静态数组,相当于需要固定分配一部分空间,不管对应的程序运行还是不运行,比较浪费空间。

当然也可以定义宏MEMP_MEM_MALLOC使用mem_malloc堆的方式实现,而mem_malloc进一步可以配置使用LWIP的实现还是使用系统的malloc(配置宏MEM_LIBC_MALLOC)。

此时和系统堆共用,这样存储利用率更高。

LWIP内部实现了堆和内存池管理可以直接使用,也可以配置使用系统的堆管理,非常灵活,移植性也非常好。

wKgaomT5Jw6AbNkLAAPYEkmgmX8781.png

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 以太网
    +关注

    关注

    40

    文章

    5371

    浏览量

    171024
  • 内存
    +关注

    关注

    8

    文章

    2996

    浏览量

    73867
  • 驱动开发
    +关注

    关注

    0

    文章

    130

    浏览量

    12061
收藏 人收藏

    评论

    相关推荐

    基于DWC_ether_qos以太网驱动开发-MAC帧格式介绍

    本文转自公众号,欢迎关注 基于DWC_ether_qos以太网驱动开发-MAC帧格式介绍 (qq.com) 一.前言   在
    的头像 发表于 08-30 09:23 2213次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-MAC帧格式<b class='flag-5'>介绍</b>

    基于DWC_ether_qos以太网驱动开发-MDIO驱动编写与测试

    本文转自公众号欢迎关注 基于DWC_ether_qos以太网驱动开发-MDIO驱动编写与测试 一.前言
    的头像 发表于 08-30 09:37 3603次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-MDIO<b class='flag-5'>驱动</b>编写与测试

    基于DWC_ether_qos以太网驱动开发-描述符链表介绍

    本文转自公众号欢迎关注 一.描述符概述 1.0 前言 对于DWC Ethernet QoS驱动的编写来说,初始化完成之后,核心操作就是DMA的描述符链表配置(linked list
    的头像 发表于 08-30 09:39 4348次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-描述符链表<b class='flag-5'>介绍</b>

    基于DWC_ether_qos以太网驱动开发-数据流验证过程

    转自公众号欢迎关注 https://mp.weixin.qq.com/s/klrHhaLMM_0W3FGVwHXFkA 基于DWC_ether_qos以太网驱动开发-数据流验证过程
    的头像 发表于 08-31 08:41 1886次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-数据流验证过程

    基于DWC_ether_qos以太网驱动开发-收发驱动编写与调试

    本文转自公众号,欢迎关注 基于DWC_ether_qos以太网驱动开发-收发驱动编写与调试 (qq.com) https://mp.wei
    的头像 发表于 09-05 08:47 2208次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-收发<b class='flag-5'>驱动</b>编写与调试

    基于DWC_ether_qos以太网驱动开发-无OS环境移植LWIP

    本文转自公众号欢迎关注 基于DWC_ether_qos以太网驱动开发-无OS环境移植LWIP (qq.com) https://mp.we
    的头像 发表于 09-06 08:40 1490次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-无OS环境移植<b class='flag-5'>LWIP</b>

    基于DWC_ether_qos以太网驱动开发-LWIP的堆管理介绍

    本文转自公众号欢迎关注 基于DWC_ether_qos以太网驱动开发-LWIP的堆管理介绍 (
    的头像 发表于 09-08 08:40 1198次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>LWIP</b>的堆管理<b class='flag-5'>介绍</b>

    基于DWC_ether_qos以太网驱动开发-LWIP的堆(内存)未对齐导致问题的案例分享

    本文转自公众号欢迎关注 https://mp.weixin.qq.com/s/ErIa2ss2YZLGYbSwoJEzog 一. 前言 内存未对齐访问问题这个已经是老生常谈的问题了, 由于LWIP
    的头像 发表于 09-09 08:44 1658次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>LWIP</b>的堆(<b class='flag-5'>内存</b><b class='flag-5'>池</b>)未对齐导致问题的案例分享

    基于DWC_ether_qos以太网驱动开发-RTOS环境移植LWIP与性能测试

    本文转自公众号,欢迎关注 基于DWC_ether_qos以太网驱动开发-RTOS环境移植LWIP与性能测试 (qq.com) https:
    的头像 发表于 09-11 11:20 1909次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-RTOS环境移植<b class='flag-5'>LWIP</b>与性能测试

    基于DWC_ether_qos以太网驱动开发-LWIP在PC上进行开发调试

    本文转自公众号欢迎关注 基于DWC_ether_qos以太网驱动开发-LWIP在PC上进行开发
    的头像 发表于 09-11 08:40 1892次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>LWIP</b>在PC上进行<b class='flag-5'>开发</b>调试

    基于DWC_ether_qos以太网驱动开发-LWIP的定时器模块详解

    一. 前言 LWIP的定时器模块,实现了通用的软件定时器,用于内部的周期事件处理,比如arp,tcp的超时等,用户也可以使用。这一篇来分析该模块的实现。 二.代码分析 2.1源码 源码
    的头像 发表于 09-18 09:33 1550次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>LWIP</b>的定时器模块详解

    基于DWC_ether_qos以太网驱动开发-LWIP的ARP模块介绍

    TCP/IP通讯第一步需要先调通ARP,否则TCP/IP包都不知道MAC地址要发给谁。这一篇来基于LWIP的ARP实现进行相关的分析。
    的头像 发表于 09-18 09:34 1744次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>LWIP</b>的ARP模块<b class='flag-5'>介绍</b>

    以太网Lwip例程

    以太网Lwip例程
    发表于 12-06 16:53 26次下载
    <b class='flag-5'>以太网</b><b class='flag-5'>Lwip</b>例程

    设计软件核心以太网服务质量数据手册免费下载

    本文描述Synopsys设计软件核心以太网服务质量DWC以太网QoS核心5.10A。DWC以太网
    发表于 10-23 08:00 16次下载
    设计软件核心<b class='flag-5'>以太网</b>服务质量数据手册免费下载

    基于DWC_ether_qos以太网驱动开发-包过滤

    以太网上数据非常多,如果所有数据都接收交给软件去处理软件负载会非常重,所以一般只需要接收发给自己的数据即可
    的头像 发表于 09-02 09:19 1616次阅读
    基于<b class='flag-5'>DWC_ether_qos</b>的<b class='flag-5'>以太网</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-包过滤