LwIP以太网在初始化过程中卡死整个程序
问题描述
当有以太网初始化的时候整个程序就有可能卡死,去掉以太网初始化整个程序没有卡死
以太网PHY初始化过程会有自协商过程,时间比较长,所以创建一个线程在线程中初始化。
有时候LwIP初始化不会导致整个系统程序卡死,有时候会卡死,这只是表象,可能是网卡初始化有问题,也不一定是网卡初始化的问题。
有时候提示LwIP以太网等初始化一切正常,程序也没有卡死,TCP等无法连接,实际网络是没有初始化成功的
特别是在调试模式下程序很容易出现这些问题
定位与排查
程序是设置了优化的,先将程序优化等级改为不优化
不优化的程序才是最原始的程序才容易暴露存在的问题
使用JLink调试,全速运行程序卡死,程序直接hardfault,打印了backtrace信息
通过LR找到hardfault前的一条语句,发现是LwIP memp.c如下函数
static void
memp_overflow_init_element(struct memp *p, const struct memp_desc *desc)
{
mem_overflow_init_raw((u8_t *)p + MEMP_SIZE, desc->size);
}
该函数在LwIP初始化内存池的时候调用的,通过LR还无法判断hardfault问题的真正原因。
继续调试。
再次调试全速运行程序,程序正常运行,但是连接程序创建的TCP服务器,发送一两次数据,程序就卡死,break跳到程序卡死的地方,发现是在了rt-thread栈检查函数** _rt_scheduler_stack_check ** 里面 while (level); 这条语句上,这就和卡死整个程序现象很相似了。
#ifdef RT_USING_OVERFLOW_CHECK
static void _rt_scheduler_stack_check(struct rt_thread *thread)
{
RT_ASSERT(thread != RT_NULL);
#if defined(ARCH_CPU_STACK_GROWS_UPWARD)
if (*((rt_uint8_t *)((rt_ubase_t)thread->stack_addr + thread->stack_size - 1)) != '#' ||
#else
if (*((rt_uint8_t *)thread->stack_addr) != '#' ||
#endif
(rt_ubase_t)thread->sp <= (rt_ubase_t)thread->stack_addr ||
(rt_ubase_t)thread->sp >
(rt_ubase_t)thread->stack_addr + (rt_ubase_t)thread->stack_size)
{
rt_ubase_t level;
rt_kprintf("thread:%s stack overflow\n", thread->name);
#ifdef RT_USING_FINSH
{
extern long list_thread(void);
list_thread();
}
#endif
level = rt_hw_interrupt_disable();
while (level);
}
#if defined(ARCH_CPU_STACK_GROWS_UPWARD)
else if ((rt_ubase_t)thread->sp > ((rt_ubase_t)thread->stack_addr + thread->stack_size))
{
rt_kprintf("warning: %s stack is close to the top of stack address.\n",
thread->name);
}
#else
else if ((rt_ubase_t)thread->sp <= ((rt_ubase_t)thread->stack_addr + 32))
{
rt_kprintf("warning: %s stack is close to end of stack address.\n",
thread->name);
}
#endif
}
至此我极度怀疑整个程序卡死问题就是因为这个hardfault问题导致的。
但是没有打印出是哪个线程栈溢出了,可以发现是没有实现rt-thread的rt_kprintf函数所以没能打印出栈溢出的线程。
将rt_kprintf暂时改为printf,再次调试hardfault后打印出了栈溢出的线程。
该线程是LwIP网卡底层数据接收线程。
将该线程的栈增大,再次测试不再出现hardfault的问题,此时还不能确保导致整个程序卡死的问题已经解决
还需要继续测试。
用原来的程序测试其他板子出现卡死程序现象,再增大EthRx这个线程的栈,再进行测试发现程序没有卡死,以太网也正常了。
到此该问题应该是解决了,后续继续测试一段时间,没有再出现过程序卡死问题。
总结
在将程序优化等级改为不优化才很容易测出来hardfault问题,而在有优化的时候的,编译器可能优化了代码不容易出现问题,所以调试程序问题最好还是将优化等改为不优化,才更容易发现问题。