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

前言

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

正文

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

c 复制代码
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任务的内容如下:

c 复制代码
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中被设置

c 复制代码
void
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
...
  tcpip_init_done = initfunc;
  tcpip_init_done_arg = arg;
...
}

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

c 复制代码
void TCPIP_Init(void)
{
...
  tcpip_init(NULL, NULL);
...
}

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

c 复制代码
#if !defined LWIP_TCPIP_THREAD_ALIVE || defined __DOXYGEN__
#define LWIP_TCPIP_THREAD_ALIVE()
#endif

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

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

c 复制代码
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 occurred
       before 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函数对消息进行分类处理。

c 复制代码
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;
  }
}
相关推荐
OOJO26 分钟前
c++---list介绍
c语言·开发语言·数据结构·c++·算法·list
笨笨饿2 小时前
29_Z变换在工程中的实际意义
c语言·开发语言·人工智能·单片机·mcu·算法·机器人
Amazing_Cacao2 小时前
深度观察 | 从“产区玄学”到“液态战场”:精品巧克力的终极试金石
学习
艾为电子3 小时前
【技术帖】让接口不再短命:艾为 C-Shielding™ Type-C智能水汽防护技术解析
c语言·开发语言
xiangw@GZ3 小时前
低功耗应用:BUCK的输入与输出环路
嵌入式硬件
张同学033 小时前
220V 转 12V/5V 电源输入电路设计笔记
笔记·嵌入式硬件·硬件工程
深蓝海拓4 小时前
S7-1500PLC学习笔记:MOVE_BLK、MOVE_BLK_VARIANT、BLKMOV的区别
笔记·学习·plc
darkhorsefly4 小时前
玩24算的益处
学习·游戏·24算
清风6666664 小时前
基于单片机的智能药物盒设计与实现
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
李永奉5 小时前
杰理芯片SDK-详细讲解AC695N/AC696N芯片SDK中APP模式流程
单片机·嵌入式硬件·物联网·语音识别