LwIP源码分析(2):tcpip_init和tcpip_thread函数分析

本文详细介绍了LwIP与FreeRTOS集成的过程,重点分析了tcpip_init函数的内部实现,包括LwIP内核的初始化、消息队列的创建及tcpip_thread的任务流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 环境:FreeRTOS & LwIP 2.2.0
  • 文章中的所有参数检测的断言代码都删除以使代码更清晰

LwIP通过调用tcpip_init来初始化TCPIP协议栈,函数如下所示,函数中代码的含义见注释:

static tcpip_init_done_fn tcpip_init_done;
static void *tcpip_init_done_arg;
static sys_mbox_t tcpip_mbox;
sys_mutex_t lock_tcpip_core;

void tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
	/* 初始化LwIP */
	lwip_init();
	/* 初始化完毕后调用的回调函数,可传NULL,在tcpip_thread开头调用 */
	tcpip_init_done = initfunc;
	tcpip_init_done_arg = arg;
	/* 创建message box,实际上是FreeRTOS的Queue
	 * 每个项目大小为一个指针的大小(4B),队列长度为TCPIP_MBOX_SIZE */
	if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
		LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
	}
	#if LWIP_TCPIP_CORE_LOCKING
	/* 创建互斥锁:用户可以通过这个锁在代码中实现LwIP的一些操作,而不需要在tcpip_thread的callback中实现 */
	if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
		LWIP_ASSERT("failed to create lock_tcpip_core", 0);
	}
	#endif /* LWIP_TCPIP_CORE_LOCKING */
	/* 创建FreeRTOS任务tcpip_thread */
	sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
}

其中lwip_init函数内容如下(各个初始化需要打开相应的宏定义,这里略去#ifdef...#endif的宏定义以方便阅读代码):

void lwip_init(void)
{
	 /* 统计模块初始化,这里只是初始化lwip_stats.mem.name为MEM */
	 stats_init();
	 /* 带操作系统时的初始化:函数中暂时没有内容 */
	 sys_init();
	 /* 初始化内存堆的起始地址、结束地址以及空闲列表 */
	 mem_init();
	 /* 初始化LwIP内存池 */
	 memp_init();
	 /* 初始化pbuf:函数中暂时没有内容 */
	 pbuf_init();
	 /* 初始化netif:主要是环回的ip,网关,子网掩码以及netif的添加和配置 */
	 netif_init();
	 /* 兼容老版本:函数中暂时没有内容 */
	 ip_init();
	 /* 兼容老版本:函数中暂时没有内容 */
	 etharp_init();
	 /* 兼容老版本:函数中暂时没有内容 */
	 raw_init();
	 /* 初始化UDP端口号(随机分配),范围:0xc000~0xffff */
	 udp_init();
	 /* 初始化TCP端口号(随机分配),范围:0xc000~0xffff */
	 tcp_init();
	 /* 初始化组播IP */
	 igmp_init();
	 /* 初始化DNS解析:设置UDP PCB并配置默认服务器 */
	 dns_init();
	 /* 初始化PPP:根据配置分配相关的结构体内存和初始化魔术字(PPP连接需要用到) */
	 ppp_init();
	 /* 初始化软件定时器 */
	 sys_timeouts_init();
}

最后,可以看到tcpip_init最终调用sys_thread_new创建了一个tcpip_thread任务,看看它做了什么:

static void tcpip_thread(void *arg)
{
	struct tcpip_msg *msg;
	/* 上锁 */
	LOCK_TCPIP_CORE();
	/* 调用前面设置的回调函数 */
	if (tcpip_init_done != NULL) {
		tcpip_init_done(tcpip_init_done_arg);
	}
	
	while (1) {
		/* 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_MBOX_FETCH来等待消息,这个函数中还有定时器的检查,具体解释参考:LwIP源码分析(1):软件定时器

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();
  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;
  }
}

对于这边的互斥锁,tcpip_thread一上来就调用LOCK_TCPIP_CORE上锁,在TCPIP_MBOX_FETCH中等待消息队列阻塞时释放这个锁,等待完这个队列,无论有没有消息到来,sys_arch_mbox_fetch返回后就立即上锁,因为在此期间tcpip_thread已经阻塞死等,此时用户可以调用部分LwIP内核函数。

对于消息处理函数tcpip_thread_handle_msg(msg)相关的结构体和实现需要在了解TCP/IP原理之后进行分析,这样知道在哪里在何时会往这个mbox发送消息,我们才能知道每个消息的定义,不同的消息需要执行什么操作。后续循序渐进地分析完LwIP相关代码后,我会写一个博客来分析,这里暂不讨论。

<think>嗯,用户想了解关于lwip_link_thread的流程图、工作机制设计结构。首先,我需要确定lwip_link_threadLWIP中的具体作用位置。根据提供的引用,特别是引用[3],提到了RT-Thread网络框架中eth_device的结构初始化过程,其中可能涉及lwip_link_thread。但LWIP本身可能并没有直接命名为lwip_link_thread的线程,这可能是一个特定于RT-Thread或用户自定义的线程。 接下来,我需要回忆LWIP的常见结构。LWIP通常运行在一个独立的线程中,比如tcpip_thread,负责处理网络协议栈的各种事件,如数据包的接收发送。引用[1]提到了tcpip_init()初始化MailBox并创建tcpip_thread线程,这可能就是LWIP的主线程。而引用[3]中的eth_device结构提到了网络接口的注册数据传输函数,这可能与底层驱动相关。 用户提到的lwip_link_thread可能是指处理网络连接状态(如链路状态检测)的线程。例如,在RT-Thread中,可能有专门的线程来轮询物理链路的连接状态,更新netif结构体的link_status字段,并通过回调函数通知应用层。这种线程通常会定期检查PHY芯片的状态,比如通过读取寄存器确定连接是否正常。 关于流程图,可能的流程包括线程初始化、循环检测链路状态、更新状态并触发相关事件。设计结构方面,该线程可能依赖于底层驱动接口,使用信号量或邮箱机制与其他线程通信,确保网络状态的及时更新。 需要确认LWIP的标准实现中是否有类似的线程,或者是否是RT-Thread的扩展。根据引用[3],RT-Thread网络框架通过eth_device_init注册设备,这可能包括启动一个线程来处理链路状态,比如lwip_link_thread。该线程可能负责调用PHY的检测函数,设置netif的link状态,并调用相应的回调函数。 最后,用户可能需要具体的代码示例或流程图来说明这一过程。需要结合RT-ThreadLWIP的文档,确保信息的准确性,并引用提供的参考资料中的相关内容,如eth_device结构体初始化过程。</think>### lwIP链路状态管理机制解析 根据提供的参考资料,lwIP协议栈本身没有直接名为$lwip\_link\_thread$的官方线程,但在RT-Thread网络框架中可能涉及链路状态监测的特殊线程实现。以下是基于协议栈工作原理RT-Thread网络框架的分析: #### 一、工作机制 1. **线程创建**:在RT-Thread初始化阶段通过$eth\_device\_init()$注册网卡设备时,可能创建名为$lwip\_link\_thread$的独立线程 2. **状态轮询**:通过PHY芯片寄存器(如BMCR/BMSR)定期检测链路状态,频率通常为1-3秒 3. **状态更新**: - 更新$netif->flags$字段的$NETIF_FLAG_LINK_UP$标志位 - 触发$netif\_status\_callback$回调函数通知应用层[^3] 4. **事件驱动**:使用RT-Thread的IPC机制(信号量/邮箱)进行线程间通信 #### 二、设计结构 ```c struct link_thread_env { struct netif *netif; // 关联的网络接口 rt_uint32_t interval; // 检测间隔(ms) phy_check_fn phy_check; // PHY检测函数指针 }; ``` #### 三、典型流程图 ```mermaid graph TD A[线程创建] --> B{链路检测使能?} B -->|是| C[读取PHY状态寄存器] B -->|否| D[休眠interval周期] C --> E{链路状态变化?} E -->|是| F[更新netif.link_status] E -->|否| G[维持当前状态] F --> H[触发状态回调函数] H --> D D --> B ``` #### 四、关键实现代码 ```c static void link_thread_entry(void *parameter) { struct link_thread_env *env = (struct link_thread_env *)parameter; while (1) { rt_thread_mdelay(env->interval); uint16_t phy_status = env->phy_check(env->netif); uint8_t new_status = (phy_status & PHY_LINK_MASK) ? 1 : 0; if (new_status != env->netif->link_status) { env->netif->link_status = new_status; if (netif->link_callback) { netif->link_callback(netif); } } } } ``` [^1]: TCP/IP协议栈初始化过程参考 : RT-Thread网络框架实现细节
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tilblackout

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值