LwIP之定时事件
先看一下定时事件数据结构
/* 定时回调函数指针 */ typedef void (*sys_timeout_handler)(void *arg);/* 定时器事件 */ struct sys_timeo {struct sys_timeo *next; //下一个定时事件u32_t time; //定时时间sys_timeout_handler h; //定时回调函数void *arg; //定时回调参数 };
所有的定时事件最终被串接在一个链表上
/* 定时事件队列 */ static struct sys_timeo *next_timeout;
下面看一下定时机制的实现代码
/* 初始化定时事件 */ void sys_timeouts_init(void) {/* 启动IP重组定时事件 */sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);/* 启动ARP定时事件 */sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); }/* 启动定时事件 */ void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) {struct sys_timeo *timeout, *t;/* 为定时事件结构体申请空间 */timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);if(timeout == NULL) {return;}/* 初始化参数 */timeout->next = NULL;timeout->h = handler;timeout->arg = arg;timeout->time = msecs;/* 定时事件队列为空 */if(next_timeout == NULL) {next_timeout = timeout;return;}/* 将定时事件插入链表 */if(next_timeout->time > msecs) {next_timeout->time -= msecs;timeout->next = next_timeout;next_timeout = timeout;} else {for(t = next_timeout; t != NULL; t = t->next) {timeout->time -= t->time;if(t->next == NULL || t->next->time > timeout->time) {if(t->next != NULL) {t->next->time -= timeout->time;}timeout->next = t->next;t->next = timeout;break;}}} }/* 取消定时事件 */ void sys_untimeout(sys_timeout_handler handler, void *arg) {struct sys_timeo *prev_t, *t;if(next_timeout == NULL) {return;}/* 将定时事件从链表中取出,并释放空间 */for(t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {if((t->h == handler) && (t->arg == arg)) {if(prev_t == NULL) {next_timeout = t->next;} else {prev_t->next = t->next;}if(t->next != NULL) {t->next->time += t->time;}memp_free(MEMP_SYS_TIMEOUT, t);return;}}return; }/* 等待最早的事件超时或者等待邮箱消息 */ void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) {u32_t time_needed;struct sys_timeo *tmptimeout;sys_timeout_handler handler;void *arg;again:/* 没有定时事件 */if(!next_timeout){time_needed = sys_arch_mbox_fetch(mbox, msg, 0);}/* 有定时事件 */else{/* 等待邮箱消息 */if(next_timeout->time > 0){time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);}else{time_needed = SYS_ARCH_TIMEOUT;}/* 接收超时 */if(time_needed == SYS_ARCH_TIMEOUT){/* 删除定时事件 */tmptimeout = next_timeout;next_timeout = tmptimeout->next;handler = tmptimeout->h;arg = tmptimeout->arg;memp_free(MEMP_SYS_TIMEOUT, tmptimeout);/* 调用定时事件 */if(handler != NULL){LOCK_TCPIP_CORE();handler(arg);UNLOCK_TCPIP_CORE();}LWIP_TCPIP_THREAD_ALIVE();goto again;}/* 接收到邮箱消息 */ else{/* 更新定时事件 */if(time_needed < next_timeout->time){next_timeout->time -= time_needed;}else{next_timeout->time = 0;}}} }
最后看一下协议栈中的几个定时事件
/* TCP定时器活跃标志位 */ static int tcpip_tcp_timer_active;/* TCP定时事件回调函数 */ static void tcpip_tcp_timer(void *arg) {/* TCP定时器回调函数(周期250ms) */tcp_tmr();/* 存在活跃(正在交互)的TCP控制块 *//* 或存在等待2MSL状态的TCP控制块 */if(tcp_active_pcbs || tcp_tw_pcbs) {/* 再次启动定时事件 */sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);} else {tcpip_tcp_timer_active = 0;} }/* 根据条件启动TCP定时事件 */ void tcp_timer_needed(void) {/* TCP定时事件未启动 *//* 存在活跃(正在交互)的TCP控制块 *//* 或存在等待2MSL状态的TCP控制块 */if(!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {/* 启动TCP定时事件 */tcpip_tcp_timer_active = 1;sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);} }/* IP重组定时事件回调函数 */ static void ip_reass_timer(void *arg) {/* 重组IP数据报定时器回调函数(周期1秒) */ip_reass_tmr();/* 启动IP重组定时事件 */sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); }/* ARP定时事件回调函数 */ static void arp_timer(void *arg) {/* ARP定时器回调函数(周期5秒) */etharp_tmr();/* 启动ARP定时事件 */sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); }
总结
- 上一篇: 「知识图谱」领域近期值得读的 6 篇顶会
- 下一篇: 区块链将如何影响你的生活?链圈大佬、美图