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 篇顶会
- 下一篇: 区块链将如何影响你的生活?链圈大佬、美图