p->ref > 0

配置:

单片机:stm32h743VIT6

有线网卡:lan8720

操作系统:r-thread

协议栈:lwip

bug:

pbuf_free: p->ref > 0
Assertion: 747 in …\components\net\lwip-2.0.2\src\core\pbuf.c, thread tcpip

问题描述:

当调试的时候,中途断点的停顿时间超20s,就会触发以上bug。

参考资料:

lwip应用开发指南

问题定位+解决方法:

**问题定位:**pbuf_free函数释放pbuf出错,因为被释放的p中的p->ref是0。

**问题再定位:**在pbuf_free函数中,LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);这一语句之前加if(p->ref == 0){p->ref = 1;},在p->ref = 1打断点,单步调试跟踪程序运行。

1.得知函数调用关系:pbuf_free()——>ethernet_input()——>tcpip_thread()。

2.每次单步运行,pbuf内容都会变化。猜测网络数据包是在中断函数里接收。

3.pbuf地址有四个,轮换着用,猜测是定义好的pbuf全局/静态数组。

**问题再再定位:**中断使得数据不断在变化不好操作,因此在前面的if语句加上关中断:if(p->ref == 0){p->ref = 1;HAL_NVIC_DisableIRQ(ETH_IRQn);},还有头文件#include "stm32h7xx_hal.h"。在p->ref = 1打断点,全速运行查看数据包状态。

第一次_未关中断 第一次_关中断 第二次 第三次 第四次 第五次

1.对比第一与第二张图,中断关闭前后,p中数据都有变化。说明关中断前更新了网络数据。

2.比对第二,三,四,五张图,每个pbuf的地址都不一样,且pbuf中的ref都不等于0,所以程序正常运行。

3.比对第二,六张图,两个pbuf的地址一样,且后者包括ref等数据都是0。运行完第六张图后就报错。可以推测是该pbuf在第二张图被释放后,在第六张图又释放一次。所以就报错了。(这里之所以没报内存错误,是因为pbuf->ref的判断在释放内存之前)

**问题再再再定位:**想知道为什么会释放两次pbuf。要知道<1>pbuf到底是什么。<2>pbuf从哪里来的。这就需要看看lwip相关资料。这里参考pbuf链表结构数据包接收过程+pbuf传递流程,可以得到:

<1>pbuf是一个链表,包含next指针,payload数据包指针,tot_len该pbuf及后面链表数据包的长度,len表示该pbuf的数据包长度。ref表示该pbuf在其他pbuf后面的次数(被几个pbuf的next指针指向)。具体见下图:(但在工程中,单个pbuf的长度够用,不需要串成链表)

pbuf链表

<2>low_level_input()获取网络数据包并返回pbuf指针,netif->input()(即tcpip_input())调用tcpip_inpkt()把pbuf指针打包进msg,最后调用sys_mbox_trypost()把msg的地址作为邮件发送到邮箱。接收——打包——发送这个流程都是在中断服务函数ETH_IRQHandler()实现。

以上是打包发送pbuf数据包,再来是接收处理数据包:tcpip_thread()接收邮箱中的msg指针,根据msg里边设置的数据包处理函数ethernet_input(),处理pbuf数据包。流程如下图:

image-20201109150451376

<3>在捋顺数据传递过程并了解pbuf结构的过程中,发现pbuf是已经定义好的静态数组,数量为4。而邮箱可以容纳8个邮件。

上面就有可能出现这一情况:有8个msg装进邮箱,前四个msg14分别打包的是pbuf14,而后四个msg58也是打包的pbuf14。接收邮件端在处理并前四个msg14并释放pbuf14后,再处理msg5时(对应pbuf1),发现此时ref为零(因为pbuf1前面已经被释放)。因而报错。

所以解决的方法是:把邮箱的大小改到3(比pbuf静态数组小,即小于4)。因为等于4的时候依然有可能报错:pbuf1被释放后,又被封装成msg1发送到邮箱。当处理端处理msg1时(对应pbuf1),发现此时ref为零(因为pbuf1前面已经被释放)。因而报错。如图所示:

pbuf数组为4时也可能报错
  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值