先看一下定時事件數據結構
/* 定時回調函數指針 */
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);
}