Index: CHANGELOG
===================================================================
RCS file: /sources/lwip/lwip/CHANGELOG,v
retrieving revision 1.122
diff -u -r1.122 CHANGELOG
--- CHANGELOG	17 Apr 2007 14:50:08 -0000	1.122
+++ CHANGELOG	20 Apr 2007 19:18:51 -0000
@@ -23,6 +23,12 @@
 
   ++ New features:
 
+  2007-04-20 Simon Goldschmidt, Frédéric Bernon, Dmitry Potapov
+  * *.c/*.h: Bugfix to bugs #1902, #19167 and patch #5785: new implementation of
+    timeouts based on system time.
+    sys_jiffies() must be implemented and the 2 new types timestamp_t (normally u32_t)
+    and timediff_t (normally s32_t) must be defined.
+
   2007-04-11 Jonathan Larmour
   * sys.h, api_lib.c: Provide new sys_mbox_tryfetch function. Require ports to provide new
     sys_arch_mbox_tryfetch function to get a message if one is there, otherwise return
Index: src/core/memp.c
===================================================================
RCS file: /sources/lwip/lwip/src/core/memp.c,v
retrieving revision 1.31
diff -u -r1.31 memp.c
--- src/core/memp.c	9 Mar 2007 07:15:05 -0000	1.31
+++ src/core/memp.c	20 Apr 2007 20:26:00 -0000
@@ -70,7 +70,7 @@
 #if ARP_QUEUEING
   MEM_ALIGN_SIZE(sizeof(struct etharp_q_entry)),
 #endif
-  MEM_ALIGN_SIZE(sizeof(struct sys_timeo))
+  MEM_ALIGN_SIZE(sizeof(struct sys_timer))
 };
 
 static const u16_t memp_num[MEMP_MAX] = {
@@ -105,7 +105,7 @@
 #if ARP_QUEUEING
   MEMP_TYPE_SIZE(MEMP_NUM_ARP_QUEUE, struct etharp_q_entry) +
 #endif
-  MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)];
+  MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timer)];
 
 #if !SYS_LIGHTWEIGHT_PROT
 static sys_sem_t mutex;
Index: src/core/sys.c
===================================================================
RCS file: /sources/lwip/lwip/src/core/sys.c,v
retrieving revision 1.23
diff -u -r1.23 sys.c
--- src/core/sys.c	11 Apr 2007 23:16:49 -0000	1.23
+++ src/core/sys.c	20 Apr 2007 21:10:01 -0000
@@ -39,57 +39,93 @@
 
 struct sswt_cb
 {
-    s16_t timeflag;
-    sys_sem_t *psem;
+  s16_t timeflag;
+  sys_sem_t *psem;
 };
 
 
 #if LWIP_SO_RCVTIMEO
-void sys_mbox_fetch_timeout(sys_mbox_t mbox, void **msg, u32_t timeout)
+void sys_mbox_fetch_timeout(sys_mbox_t mbox, void **msg, timediff_t timeout)
 #else
 void sys_mbox_fetch(sys_mbox_t mbox, void **msg)
 #endif /* LWIP_SO_RCVTIMEO */
 {
-  u32_t time;
-  struct sys_timeouts *timeouts;
-  struct sys_timeo *tmptimeout;
-  sys_timeout_handler h;
+  timestamp_t time_ms_now;
+  timediff_t time_ms_waited, time_to_next_timer, time_ms_wait;
+  struct sys_timers *timeouts;
+  struct sys_timer *tmptimeout;
+  sys_timer_handler h;
   void *arg;
 
- again:
-  timeouts = sys_arch_timeouts();
+#if LWIP_SO_RCVTIMEO  
+  LWIP_ASSERT("timeout must be > 0", (timeout > 0));
+#endif
+
+again:
+  timeouts = sys_arch_timers();
 
   if (!timeouts || !timeouts->next) {
+    /* no timeouts */
 #if LWIP_SO_RCVTIMEO  
-    time = sys_arch_mbox_fetch(mbox, msg, timeout);
+    time_ms_waited = sys_arch_mbox_fetch(mbox, msg, timeout);
+    if (time_ms_waited == SYS_ARCH_TIMEOUT) {
+      if (msg != NULL) {
+        *msg = NULL;
+      }
+    }
 #else
-    time = sys_arch_mbox_fetch(mbox, msg, 0);
+    /* return value is not needed */
+    sys_arch_mbox_fetch(mbox, msg, 0);
 #endif /* LWIP_SO_RCVTIMEO */
   } else {
-    if (timeouts->next->time > 0) {
-#if LWIP_SO_RCVTIMEO  
-      time = sys_arch_mbox_fetch(mbox, msg, (timeout?((timeout<timeouts->next->time)?timeout:timeouts->next->time):timeouts->next->time));
+    /* timeouts->next->time == 0 is valid since jiffies can wrap around */
+    time_ms_now = SYS_JIFFIES_TO_MS(sys_jiffies());
+    time_to_next_timer = TIMESTAMP_DIFF(timeouts->next->time_expire, time_ms_now);
+#if LWIP_SO_RCVTIMEO
+    if (timeout && (timeout < time_to_next_timer)) {
+      /* external timeout given and next timer doesn't expire earlier */
+      time_ms_wait = timeout;
+    } else {
+      /* no external timeout given or next timer expires earlier */
+      time_ms_wait = time_to_next_timer;
+    }
 #else
-      time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
+    time_ms_wait = time_to_next_timer;
 #endif /* LWIP_SO_RCVTIMEO */
+    if(time_ms_wait <= 0) {
+      /* time_expire is in the past, execute timer callback now */
+      time_ms_waited = SYS_ARCH_TIMEOUT;
     } else {
-      time = SYS_ARCH_TIMEOUT;
+      /* time_expire is in the future -> proceed as normal */
+      time_ms_waited = sys_arch_mbox_fetch(mbox, msg, time_ms_wait);
     }
 
-    if (time == SYS_ARCH_TIMEOUT) {
-#if LWIP_SO_RCVTIMEO  
-      if ((timeout) && (timeout<timeouts->next->time)) {        
-      /* If time == SYS_ARCH_TIMEOUT, and we have wait "fetch's timeout" and not "timer's timeout",
-         The timeout variable is the number of milliseconds we have waited for the message. */
-        timeouts->next->time -= timeout;
-      } else {
-      /* The timeouts->next->time variable is the number of milliseconds we have waited for the message.  */
-        if (timeouts->next->time < timeout) {
-          timeout -= timeouts->next->time;
+    if (time_ms_waited == SYS_ARCH_TIMEOUT) {
+#if LWIP_SO_RCVTIMEO
+      if (timeout != 0) {
+        /* external timeout given */
+        if (timeout >= time_to_next_timer) {
+          /* timer expired, substract the time waited from timeout,
+             call timer handler and fetch again */
+          if (timeout != 0) {
+            if (timeout > time_to_next_timer) {
+              timeout -= time_to_next_timer;
+            } else {
+              /* timeout and next timer expired together */
+              if (msg != NULL) {
+                *msg = NULL;
+                return;
+              }
+            }
+          }
         } else {
-          /* either timeout == 0, or timeout must == timeouts->next->time */
-          if (timeout) timeout = SYS_ARCH_TIMEOUT;
+          /* timeout before any timer expired, return */
+          if (msg != NULL) {
+            *msg = NULL;
+            return;
+          }
         }
+      }
 #endif /* LWIP_SO_RCVTIMEO */
 
       /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
@@ -105,93 +141,21 @@
         h(arg);
       }
       
-#if LWIP_SO_RCVTIMEO  
-      if (timeout != SYS_ARCH_TIMEOUT)
-#endif /* LWIP_SO_RCVTIMEO */
-      
       /* We try again to fetch a message from the mbox. */
       goto again;
-#if LWIP_SO_RCVTIMEO  
-      }
-#endif /* LWIP_SO_RCVTIMEO */
-    } 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;
-      }
     }
 
   }
-  
-#if LWIP_SO_RCVTIMEO
-  if ((time == SYS_ARCH_TIMEOUT) && (msg))
-   { (*msg)=NULL;
-   }
-#endif /* LWIP_SO_RCVTIMEO */
 }
 
 void
-sys_sem_wait(sys_sem_t sem)
+sys_timer_create(timediff_t msecs, sys_timer_handler h, void *arg)
 {
-  u32_t time;
-  struct sys_timeouts *timeouts;
-  struct sys_timeo *tmptimeout;
-  sys_timeout_handler h;
-  void *arg;
-
- again:
-
-  timeouts = sys_arch_timeouts();
-
-  if (!timeouts || !timeouts->next) {
-    sys_arch_sem_wait(sem, 0);
-  } 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, ("ssw h=%p(%p)\n", (void *)h, (void *)arg));
-        h(arg);
-      }
+  struct sys_timers *timeouts;
+  struct sys_timer *timeout, *t;
+  timestamp_t time_expire;
 
-
-      /* We try again to fetch a message from the mbox. */
-      goto again;
-    } 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;
-      }
-    }
-
-  }
-}
-
-void
-sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
-{
-  struct sys_timeouts *timeouts;
-  struct sys_timeo *timeout, *t;
+  time_expire = SYS_JIFFIES_TO_MS(sys_jiffies()) + msecs;
 
   timeout = memp_malloc(MEMP_SYS_TIMEOUT);
   if (timeout == NULL) {
@@ -200,31 +164,31 @@
   timeout->next = NULL;
   timeout->h = h;
   timeout->arg = arg;
-  timeout->time = msecs;
+  timeout->time_expire = time_expire;
 
-  timeouts = sys_arch_timeouts();
+  timeouts = sys_arch_timers();
 
   LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
     (void *)timeout, msecs, (void *)h, (void *)arg));
 
   LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
 
+  /* Insert the new timer */
   if (timeouts->next == NULL) {
+    /* no timer yet, set as first */
     timeouts->next = timeout;
     return;
   }
 
-  if (timeouts->next->time > msecs) {
-    timeouts->next->time -= msecs;
+  if (timeouts->next->time_expire > time_expire) {
+    /* the new timer expires earlier than the previous first timer,
+       set it as first in the list */
     timeout->next = timeouts->next;
     timeouts->next = timeout;
   } else {
+    /* insert new timer at the correct place in the list */
     for(t = timeouts->next; 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;
-        }
+      if ((t->next == NULL) || (t->next->time_expire > timeout->time_expire)) {
         timeout->next = t->next;
         t->next = timeout;
         break;
@@ -239,90 +203,28 @@
 */
 
 void
-sys_untimeout(sys_timeout_handler h, void *arg)
+sys_timer_remove(sys_timer_handler h, void *arg)
 {
-    struct sys_timeouts *timeouts;
-    struct sys_timeo *prev_t, *t;
-
-    timeouts = sys_arch_timeouts();
+  struct sys_timers *timeouts;
+  struct sys_timer *prev_t, *t;
 
-    if (timeouts->next == NULL)
-        return;
+  timeouts = sys_arch_timers();
 
-    for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next)
-    {
-        if ((t->h == h) && (t->arg == arg))
-        {
-            /* We have a match */
-            /* Unlink from previous in list */
-            if (prev_t == NULL)
-                timeouts->next = t->next;
-            else
-                prev_t->next = t->next;
-            /* If not the last one, add time of this one back to next */
-            if (t->next != NULL)
-                t->next->time += t->time;
-            memp_free(MEMP_SYS_TIMEOUT, t);
-            return;
-        }
-    }
+  if (timeouts->next == NULL)
     return;
-}
-
-
-
-
 
-static void
-sswt_handler(void *arg)
-{
-    struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;
-
-    /* Timeout. Set flag to TRUE and signal semaphore */
-    sswt_cb->timeflag = 1;
-    sys_sem_signal(*(sswt_cb->psem));
-}
-
-/* Wait for a semaphore with timeout (specified in ms) */
-/* timeout = 0: wait forever */
-/* Returns 0 on timeout. 1 otherwise */
-
-int
-sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)
-{
-    struct sswt_cb sswt_cb;
-
-    sswt_cb.psem = &sem;
-    sswt_cb.timeflag = 0;
-
-    /* If timeout is zero, then just wait forever */
-    if (timeout > 0)
-        /* Create a timer and pass it the address of our flag */
-        sys_timeout(timeout, sswt_handler, &sswt_cb);
-    sys_sem_wait(sem);
-    /* Was it a timeout? */
-    if (sswt_cb.timeflag)
-    {
-        /* timeout */
-        return 0;
-    } else {
-        /* Not a timeout. Remove timeout entry */
-        sys_untimeout(sswt_handler, &sswt_cb);
-        return 1;
+  for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
+    if ((t->h == h) && (t->arg == arg)) {
+      /* We have a match */
+      /* Unlink from previous in list */
+      if (prev_t == NULL)
+        timeouts->next = t->next;
+      else
+        prev_t->next = t->next;
+      memp_free(MEMP_SYS_TIMEOUT, t);
+      return;
     }
-
-}
-
-
-void
-sys_msleep(u32_t ms)
-{
-  sys_sem_t delaysem = sys_sem_new(0);
-
-  sys_sem_wait_timeout(delaysem, ms);
-
-  sys_sem_free(delaysem);
+  }
+  return;
 }
-
-
 #endif /* NO_SYS */
Index: src/include/lwip/sys.h
===================================================================
RCS file: /sources/lwip/lwip/src/include/lwip/sys.h,v
retrieving revision 1.23
diff -u -r1.23 sys.h
--- src/include/lwip/sys.h	11 Apr 2007 15:41:03 -0000	1.23
+++ src/include/lwip/sys.h	20 Apr 2007 20:00:37 -0000
@@ -46,8 +46,8 @@
 struct sys_timeo {u8_t dummy;};
 
 #define sys_init()
-#define sys_timeout(m,h,a)
-#define sys_untimeout(m,a)
+#define sys_timer_create(m,h,a)
+#define sys_timer_remove(m,a)
 #define sys_sem_new(c) c
 #define sys_sem_signal(s)
 #define sys_sem_wait(s)
@@ -55,6 +55,7 @@
 #define sys_mbox_new() 0
 #define sys_mbox_fetch_timeout(m,d,t)
 #define sys_mbox_fetch(m,d)
+#define sys_mbox_tryfetch(m,d)
 #define sys_mbox_post(m,d)
 #define sys_mbox_free(m)
 
@@ -65,31 +66,31 @@
 #include "arch/sys_arch.h"
 
 /** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */
-#define SYS_ARCH_TIMEOUT 0xffffffffUL
+#define SYS_ARCH_TIMEOUT ((timediff_t)-1)
 
 /* sys_mbox_tryfetch returns SYS_MBOX_EMPTY if appropriate.
  * For now we use the same magic value, but we allow this to change in future.
  */
 #define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT 
 
-typedef void (* sys_timeout_handler)(void *arg);
+typedef void (* sys_timer_handler)(void *arg);
 
-struct sys_timeo {
-  struct sys_timeo *next;
-  u32_t time;
-  sys_timeout_handler h;
+struct sys_timer {
+  struct sys_timer *next;
+  timestamp_t time_expire;
+  sys_timer_handler h;
   void *arg;
 };
 
-struct sys_timeouts {
-  struct sys_timeo *next;
+struct sys_timers {
+  struct sys_timer *next;
 };
 
 /* sys_init() must be called before anthing else. */
 void sys_init(void);
 
 /*
- * sys_timeout():
+ * sys_timer_create():
  *
  * Schedule a timeout a specified amount of milliseconds in the
  * future. When the timeout occurs, the specified timeout handler will
@@ -97,38 +98,60 @@
  * called.
  *
  */
-void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
-void sys_untimeout(sys_timeout_handler h, void *arg);
-struct sys_timeouts *sys_arch_timeouts(void);
+void sys_timer_create(timediff_t msecs, sys_timer_handler h, void *arg);
+void sys_timer_remove(sys_timer_handler h, void *arg);
+void sys_check_timers(void);
+struct sys_timers *sys_arch_timers(void);
 
 /* Semaphore functions. */
 sys_sem_t sys_sem_new(u8_t count);
 void sys_sem_signal(sys_sem_t sem);
-u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout);
+/* timeout = 0 means wait forever */
+timediff_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout);
 void sys_sem_free(sys_sem_t sem);
-void sys_sem_wait(sys_sem_t sem);
-int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout);
+/* since no timeout processing is done in sys_sem_wait & sys_sem_wait_timeout,
+   define the, directly to sys_arch_sem_wait */
+#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0)
+/* timeout = 0 means wait forever */
+#define sys_sem_wait_timeout(sem, timeout) sys_arch_sem_wait(sem, timeout)
 
 /* Time functions. */
 #ifndef sys_msleep
 void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */
-#endif
+#endif /* sys_msleep */
 #ifndef sys_jiffies
-u32_t sys_jiffies(void); /* since power up. */
-#endif
+timestamp_t sys_jiffies(void); /* system timer ticks since power up. */
+#endif /* sys_jiffies */
+
+#ifndef SYS_JIFFIES_TO_MS
+#if SYS_ARCH_TICKS_PER_SECOND == 1000
+#define SYS_JIFFIES_TO_MS(j) (j)
+#elif SYS_ARCH_TICKS_PER_SECOND > 1000
+#define SYS_JIFFIES_TO_MS(j) (j/(SYS_ARCH_TICKS_PER_SECOND/1000))
+#else /* SYS_ARCH_TICKS_PER_SECOND < 1000 */
+#define SYS_JIFFIES_TO_MS(j) (j*(1000/SYS_ARCH_TICKS_PER_SECOND))
+#endif /* SYS_ARCH_TICKS_PER_SECOND */
+#endif /* SYS_JIFFIES_TO_MS */
+
+/* portable way to calculate time */
+#define TIMESTAMP_DIFF(t1, t2)            ((timediff_t)((t1) - (t2)))
+#define TIMESTAMP_ADD(timestamp, timeout) ((timestamp_t)((timestamp)+(timeout))) 
+
 
 /* Mailbox functions. */
 sys_mbox_t sys_mbox_new(void);
 void sys_mbox_post(sys_mbox_t mbox, void *msg);
-u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout);
+/* timeout = 0 means wait forever */
+timediff_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout);
 #ifndef sys_arch_mbox_tryfetch /* Allow port to override with a macro */
-u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg);
+timediff_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg);
 #endif
 /* For now, we map straight to sys_arch implementation. */
 #define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg)
 void sys_mbox_free(sys_mbox_t mbox);
 #if LWIP_SO_RCVTIMEO
-void sys_mbox_fetch_timeout(sys_mbox_t mbox, void **msg, u32_t timeout);
+/* timeout = 0 means wait forever */
+void sys_mbox_fetch_timeout(sys_mbox_t mbox, void **msg, timediff_t timeout);
 #define sys_mbox_fetch(m,d) sys_mbox_fetch_timeout(m,d,0)
 #else
 void sys_mbox_fetch(sys_mbox_t mbox, void **msg);
@@ -137,10 +160,6 @@
 /* Thread functions. */
 sys_thread_t sys_thread_new(void (* thread)(void *arg), void *arg, int prio);
 
-/* The following functions are used only in Unix code, and
-   can be omitted when porting the stack. */
-/* Returns the current time in microseconds. */
-unsigned long sys_now(void);
 
 #endif /* NO_SYS */
