lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lwip-users] sys_timeout handler will not be called


From: kuwa
Subject: [lwip-users] sys_timeout handler will not be called
Date: Thu, 05 Feb 2004 21:40:43 +0900 (LMT)

Hi,

I'm currently using lwIP (0.7.0) with uC/OS-II and
trying to invoke three timers within one task by using sys_timeout().
Three timers are ARP timer(10sec), DHCP fine timer (500msec) and DHCP
coarse timer (60sec).

My code looks like this:

void arp_timer(void *arg)
{
  etharp_tmr();
  sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL);
}

void dhcp_fine_timer(void *arg)
{
  dhcp_fine_tmr();
  sys_timeout(DHCP_FINE_TIMER_MSECS, (sys_timeout_handler)dhcp_fine_timer, 
NULL);
}

void dhcp_coarse_timer(void *arg)
{
  dhcp_coarse_tmr();
  sys_timeout((u32_t)DHCP_COARSE_TIMER_SECS * 1000,
              (sys_timeout_handler)dhcp_coarse_timer, NULL);
}

void MainTask(void *pdat)
{
  /* Initialize lwIP stack. */
  ...

  /* Register DHCP two timers */
  sys_timeout(DHCP_FINE_TIMER_MSECS,
              (sys_timeout_handler)dhcp_fine_timer, NULL);
  sys_timeout((u32_t)DHCP_COARSE_TIMER_SECS * 1000,
              (sys_timeout_handler)dhcp_coarse_timer, NULL);

  /* Add Default I/F.
     ARP timer (arp_timer()) is registered in ethernetif_init() (in this task)
     by calling sys_timeout. */
  IP4_ADDR(&ipaddr, 0, 0, 0, 0);
  IP4_ADDR(&netmask, 255, 255, 255, 255);
  IP4_ADDR(&gw, 0, 0, 0, 0);
  netif_add(&netif, &ipaddr, &netmask, &gw, NULL,
            ethernetif_init, tcpip_input);
  netif_set_default(&netif);

  /* start DHCP */
  err = dhcp_start(&netif);
  if (err != ERR_OK) {
    printf("DHCP start failed\n");
  }

  /* Wait forever */
  sys_msleep(0);        /* All the timers, which are registered
                           by calling sys_timeout() in this task
                           are scheduled. */
}


By the above code, it seems that all these timers work fine at first.
(All of three timeout handlers are called correctly.)

However after a period of time, all of these timers will stop.  (Three
timeout handlers will not be called.)

In that situation I found that timeouts->next is NULL (at the line #1
of the below citaion) in sys_sem_wait() which is called from
sys_msleep() of MainTask().

void
sys_sem_wait(sys_sem_t sem)
{
  u32_t time;
  struct sys_timeouts *timeouts;
  struct sys_timeout *tmptimeout;
  sys_timeout_handler h;
  void *arg;

  /*  while (sys_arch_sem_wait(sem, 1000) == 0);
      return;*/

 again:

  timeouts = sys_arch_timeouts();

  if (!timeouts || !timeouts->next) {           /* #1 */
    sys_arch_sem_wait(sem, 0);                  /* #2 */
  } else {
    if (timeouts->next->time > 0) {
      time = sys_arch_sem_wait(sem, timeouts->next->time);
    } else {
      time = SYS_ARCH_TIMEOUT;
    }

    ...snip...
}

MainTask() calls sys_msleep(), and sys_msleep() calls sys_sem_wait().
Then sys_sem_wait() calls timeout handler and timeout data is removed
from timeouts list.

I'm gussing that a timeout handler (or some functions called from a
timeout handler) call sys_sem_wait() again (removed from timeouts
list), and timeouts list eventually has been empty.  And wait forever
at the line #2.

As a workaround, I replace sys_msleep() call in MainTask() with the
following sys_timer_kicker() call, which is almost copied from
sys_sem_wait().

It seems that works fine.  How would you think about my guess and
this workaround?


void sys_timer_kicker(void)
{
  u32_t time;
  struct sys_timeouts *timeouts;
  struct sys_timeout *tmptimeout;
  sys_timeout_handler h;
  void *arg;
  sys_sem_t sem;

  sem = sys_sem_new(0);
  sys_sem_name(sem, "for sys_timeout");

  for (;;) {
    timeouts = sys_arch_timeouts();
    if (!timeouts || !timeouts->next) {
      /* Wait for a while */
      sys_arch_sem_wait(sem, 50);

    } else {
      if (timeouts->next->time > 0) {
        time = sys_arch_sem_wait(sem, timeouts->next->time);
      } else {
        time = SYS_ARCH_TIMEOUT;
      }

      if (time == SYS_ARCH_TIMEOUT) {
        /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
           could be fetched. We should now call the timeout handler and
           deallocate the memory allocated for the timeout. */
        tmptimeout = timeouts->next;
        timeouts->next = tmptimeout->next;
        h = tmptimeout->h;
        arg = tmptimeout->arg;
        memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
        if (h != NULL) {
          LWIP_DEBUGF(SYS_DEBUG, ("stk h=%p(%p)\n", (void *)h, (void *)arg));
          h(arg);
        }
      } else {
        /* If time != SYS_ARCH_TIMEOUT, a message was received before the 
timeout
         occured. The time variable is set to the number of
         milliseconds we waited for the message. */
        if (time <= timeouts->next->time) {
          timeouts->next->time -= time;
        } else {
          timeouts->next->time = 0;
        }
      }
    }   /* We try again to fetch a message from the mbox. */
  }
}

--
Shuji KUWAHARA





reply via email to

[Prev in Thread] Current Thread [Next in Thread]