当前位置: 首页 > news >正文

【LwIP源码学习4】主线程tcpip_thread

前言

本文对lwip的主要线程tcpip_thread进行分析。

正文

tcpip_thread是lwip最主要的线程,其创建在tcpip_init函数中

sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);

tcpip_init函数被TCPIP_Init函数调用。
TCPIP_Init函数被用户应用程序调用。
在这里插入图片描述
创建任务的sys_thread_new函数在sys_arch.c文件中实现,sys_arch.c是操作系统相关的接口文件,在有操作系统环境下移植lwip时要对sys_arch.c中的函数进行实现。
tcpip_thread任务的内容如下:

static void
tcpip_thread(void *arg)
{struct tcpip_msg *msg;LWIP_UNUSED_ARG(arg);LWIP_MARK_TCPIP_THREAD();LOCK_TCPIP_CORE();//tcpip_init_done是一个函数指针//tcpip_init_done_arg是一个变量指针//这两个可以由用户设置,如果想在while循环执行前做些什么if (tcpip_init_done != NULL) {tcpip_init_done(tcpip_init_done_arg);}while (1) {                          /* MAIN Loop *///用户可以在opt.h文件中对下面这个宏进行函数定义//可以根据这个宏使得用户在应用层知道tcpip_thread任务还活着LWIP_TCPIP_THREAD_ALIVE();/* wait for a message, timeouts are processed while waiting *///等待邮箱中出现消息、处理超时事件TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg);if (msg == NULL) {LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));LWIP_ASSERT("tcpip_thread: invalid message", 0);continue;}//处理接收到的消息tcpip_thread_handle_msg(msg);}
}

tcpip_init_done函数指针和tcpip_init_done_arg变量指针在tcpip_init中被设置

void
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
...tcpip_init_done = initfunc;tcpip_init_done_arg = arg;
...
}

而在用户可以修改的sys_arch.c文件中对TCPIP_Init函数的实现:

void TCPIP_Init(void)
{
...tcpip_init(NULL, NULL);
...
}

LWIP_TCPIP_THREAD_ALIVE宏在opt.h文件中被定义

#if !defined LWIP_TCPIP_THREAD_ALIVE || defined __DOXYGEN__
#define LWIP_TCPIP_THREAD_ALIVE()
#endif

如果用于想监测tcpip_thread任务是否一直活着可以在这里进行修改。

TCPIP_MBOX_FETCHtcpip_timeouts_mbox_fetch函数的带参宏定义,用于等待邮箱中是否有需要处理的消息,或者检查是否有超时事件,如果有则执行其回调函数。

static void
tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
{u32_t sleeptime, res;again:LWIP_ASSERT_CORE_LOCKED();//获取距离最近超时事件的时间sleeptime = sys_timeouts_sleeptime();if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE) {//表示系统没有超时事件UNLOCK_TCPIP_CORE();//没有超时事件就无限期的一直等待邮箱中有消息到来sys_arch_mbox_fetch(mbox, msg, 0);LOCK_TCPIP_CORE();return;} else if (sleeptime == 0) {//表示有超时事件需要立刻执行//找出来超时事件并执行其回调函数sys_check_timeouts();/* We try again to fetch a message from the mbox. *///处理完需要立刻执行的超时事件后继续查看最近超时事件时间goto again;}//如果系统有超时事件但不还有一段时间触发,就执行以下代码UNLOCK_TCPIP_CORE();//等到邮箱中是否有消息,等待时间为sleeptime,也就是最近超时事件发生时间res = sys_arch_mbox_fetch(mbox, msg, sleeptime);LOCK_TCPIP_CORE();if (res == SYS_ARCH_TIMEOUT) {//表示邮箱等待超时了,没有等到邮箱中出现新的消息/* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurredbefore a message could be fetched. */sys_check_timeouts(); //处理超时事件/* We try again to fetch a message from the mbox. */goto again; //继续查看是否有超时事件,没有就无限期等邮箱}
}

以上这个函数只有在收到邮箱中的一个消息之后才return返回,否则有超时事件就处理超时事件,没有则无限期等待邮箱中出现消息。
思考:似乎有个bug,如果一开始没有超时事件,在无限性等待邮箱中的消息时又出现超时事件了,那么如果一直等不到邮箱中的消息,新出现的超时事件就一直不会被处理了。可能这种情况不会发生,也可能lwip对这种情况有其他处理,还没看到。
其中等待邮箱中出现消息的sys_arch_mbox_fetch函数在sys_arch.c文件中,由用户移植时进行实现。

接下来调用tcpip_thread_handle_msg函数对消息进行分类处理。

static void
tcpip_thread_handle_msg(struct tcpip_msg *msg)
{switch (msg->type) {case TCPIP_MSG_API:...break;case TCPIP_MSG_API_CALL:...break;case TCPIP_MSG_INPKT:...break;case TCPIP_MSG_TIMEOUT:...break;case TCPIP_MSG_UNTIMEOUT:...break;case TCPIP_MSG_CALLBACK:...break;case TCPIP_MSG_CALLBACK_STATIC:...break;default:...break;}
}

http://www.mrgr.cn/news/64597.html

相关文章:

  • 初识动态规划(由浅入深)
  • 在线PDF转图片网站
  • golang gin ShouldBind的介绍和使用
  • SQL 常用语句
  • 微信支付接口变心了:暂不支持该类型商户号绑定本AppID,请点击“拒绝”结束该流程,点此查看详细说明。如有疑问,可咨询客服
  • Android编译环境构建(二)(可用于物理机、虚拟机、容器化Jenkins环境)
  • http://43.139.152.26 枪声问题(桂城真题)
  • 构 造 器
  • linux perf 环境部署和基本测试(基于Ubuntu20.04)
  • Qt中的Model与View 2
  • Linux -- 初识信号
  • Guava Cache 原理与实现剖析
  • Git - 两种方式撤销已提交到远端仓库的记录并删除提交记录
  • 文化素质教育系列讲座听讲5
  • DICOM标准:MR图像模块属性详解——磁共振成像(MR)在DICOM中的应用
  • PHP如何处理密码嗅探和重播攻击
  • 撒大苏打是
  • 如何将Python列表转换为Excel表格的第一列:详细指南
  • Gradle的安装和使用
  • JeecgBoot集成工作流实战教程
  • 【汇编语言】[BX]和loop指令(一)—— 初识[BX]和loop指令
  • java项目之个人博客系统的设计与实现(springboot)
  • ARIMA时间序列预测模型详细讲解+Python案例演示
  • As Simple as One and Two
  • 算法学习(七)—— 分治
  • 棉花病害识别检测数据集(猫脸码客 第232期)