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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章