企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
LwIP虽然使用超时链表进行管理所有的超时事件,那么它首先需要知道有哪些超时事件才能去管理,而这些超时事件就是通过注册的方式被挂载在链表上,简单来说就是这些超时事件要在内核中登记一下,内核才会去处理,LwIP中注册超时事件的函数是sys\_timeout(),但是实际上是调用sys\_timeout\_abs()函数,具体见代码清单 9‑2。 ``` 1 void 2 sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) 3 { 4 u32_t next_timeout_time; 5 LWIP_ASSERT_CORE_LOCKED(); 6 7 /* overflow handled by TIME_LESS_THAN macro */ 8 next_timeout_time = (u32_t)(sys_now() + msecs); (1) 9 10 sys_timeout_abs(next_timeout_time, handler, arg); 11 } 12 13 static void 14 sys_timeout_abs(u32_t abs_time, sys_timeout_handler handler, void *arg) 15 { 16 struct sys_timeo *timeout, *t; 17 18 timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); (2) 19 if (timeout == NULL) 20 { 21 return; 22 } 23 24 timeout->next = NULL; 25 timeout->h = handler; 26 timeout->arg = arg; 27 timeout->time = abs_time; (3) 28 29 if (next_timeout == NULL) 30 { 31 next_timeout = timeout; (4) 32 return; 33 } 34 if (TIME_LESS_THAN(timeout->time, next_timeout->time)) 35 { 36 timeout->next = next_timeout; 37 next_timeout = timeout; (5) 38 } 39 else 40 { 41 for (t = next_timeout; t != NULL; t = t->next) 42 { 43 if ((t->next == NULL) || 44 TIME_LESS_THAN(timeout->time, t->next->time)) 45 { 46 timeout->next = t->next; 47 t->next = timeout; (6) 48 break; 49 } 50 } 51 } 52 } ``` (1):根据当前时间计算出超时的时间,然后调用sys_timeout_abs()函数将当前事件插入超时链表。 (2):从内存池中申请一个MEMP_SYS_TIMEOUT类型内存,保存对应超时事件的相关信息。 (3):填写对应的超时事件信息,超时回调函数、函数参数、超时的 时间。 (4):如果超时链表中没有超时事件,那么新添加的事件就是链表的第一个。 (5):如果新插入的超时事件比链表上第一个事件的时间短,则将新插入的超时事件设置成链表的第一个。 (6):遍历链表,寻找合适的插入节点,超时链表根据超时事件的时间升序排列。 在timeouts.c中,有一个名字为lwip_cyclic_timer的结构,LwIP使用该结构存放了其内部使用的循环超时事件。这些超时事件在LwIP初始化时通过函数sys_timeouts_init()调用定时器注册函数sys_timeout()注册进入超时链表中,lwip_cyclic_timer的结构具体见: ``` 1 #define TCP_TMR_INTERVAL 250 2 #define IP_TMR_INTERVAL 1000 3 #define ARP_TMR_INTERVAL 1000 4 5 struct lwip_cyclic_timer 6 { 7 u32_t interval_ms; 8 lwip_cyclic_timer_handler handler; 9 }; 10 11 const struct lwip_cyclic_timer lwip_cyclic_timers[] = 12 { 13 {TCP_TMR_INTERVAL, HANDLER(tcp_tmr)}, 14 15 {IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)}, 16 17 {ARP_TMR_INTERVAL, HANDLER(etharp_tmr)}, 18 }; ``` lwip\_cyclic\_timers数组中存放了每个周期性的超时事件回调函数及超时时间,在LwIP初始化的时候就将这些事件一个个插入超时链表中,具体见代码清单 9‑4。 ``` 1 void sys_timeouts_init(void) 2 { 3 size_t i; 4 5 for(i =(LWIP_TCP ? 1 : 0);i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) 6 { 7 sys_timeout(lwip_cyclic_timers[i].interval_ms,lwip_cyclic_timer, 8 LWIP_CONST_CAST(void *, &lwip_cyclic_timers[i])); 9 } 10 } ``` 插入超时链表后的示意图具体见图 9‑2。 ![](https://box.kancloud.cn/46c5aeb527e47b601120c67c03ce909e_945x195.png) 每个sys\_timeo结构体中的h成员变量记录着对应的超时回调函数,对于周期性的回调函数,LwIP是这样子处理的:在初始化的时候将他们注册到 lwip\_cyclic\_timer()函数中,每次在处理回调函数之后,就调用sys\_timeout\_abs()函数将其重新注册到超时链表中,具体见代码清单 9‑5。 ``` 1 lwip_cyclic_timer(void *arg) 2 { 3 u32_t now; 4 u32_t next_timeout_time; 5 const struct lwip_cyclic_timer *cyclic = (const struct lwip_cyclic_timer *)arg; 6 7 cyclic->handler(); 8 9 now = sys_now(); 10 next_timeout_time = (u32_t)(current_timeout_due_time + cyclic->interval_ms); 11 12 if (TIME_LESS_THAN(next_timeout_time, now)) 13 { 14 sys_timeout_abs((u32_t)(now + cyclic->interval_ms), lwip_cyclic_timer, arg); 15 } 16 else 17 { 18 sys_timeout_abs(next_timeout_time, lwip_cyclic_timer, arg); 19 } 20 } ```