Index: mem.c
===================================================================
RCS file: /sources/lwip/lwip/src/core/mem.c,v
retrieving revision 1.61
diff -u -r1.61 mem.c
--- mem.c	27 Jun 2008 18:37:53 -0000	1.61
+++ mem.c	27 Jun 2008 20:54:21 -0000
@@ -178,26 +178,32 @@
 /** pointer to the lowest free block, this is used for faster search */
 static struct mem *lfree;
 
-
-#if LWIP_USE_HEAP_FROM_INTERRUPT
-
-/* Protect the heap by disabeling interrupts */
-#define LWIP_MEM_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev)
-#define LWIP_MEM_PROTECT()      SYS_ARCH_PROTECT(lev)
-#define LWIP_MEM_UNPROTECT()    SYS_ARCH_UNPROTECT(lev)
-
-#else /* LWIP_USE_HEAP_FROM_INTERRUPT */
-
-/* Protect the heap using a semaphore */
-
 /** concurrent access protection */
 static sys_sem_t mem_sem;
 
-#define LWIP_MEM_DECL_PROTECT()
-#define LWIP_MEM_PROTECT()    sys_arch_sem_wait(mem_sem, 0)
-#define LWIP_MEM_UNPROTECT()  sys_sem_signal(mem_sem)
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
 
-#endif /* LWIP_USE_HEAP_FROM_INTERRUPT */
+/* Allow mem_free from other (e.g. interrupt) context */
+#define LWIP_MEM_FREE_DECL_PROTECT()  SYS_ARCH_DECL_PROTECT(lev_free)
+#define LWIP_MEM_FREE_PROTECT()       SYS_ARCH_PROTECT(lev_free)
+#define LWIP_MEM_FREE_UNPROTECT()     SYS_ARCH_UNPROTECT(lev_free)
+#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
+#define LWIP_MEM_ALLOC_PROTECT()      SYS_ARCH_PROTECT(lev_alloc)
+#define LWIP_MEM_ALLOC_UNPROTECT()    SYS_ARCH_UNPROTECT(lev_alloc)
+
+static volatile u8_t mem_free_count;
+
+#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+
+/* Protect the heap only by using a semaphore */
+#define LWIP_MEM_FREE_DECL_PROTECT()
+#define LWIP_MEM_FREE_PROTECT()    sys_arch_sem_wait(mem_sem, 0)
+#define LWIP_MEM_FREE_UNPROTECT()  sys_sem_signal(mem_sem)
+#define LWIP_MEM_ALLOC_DECL_PROTECT()
+#define LWIP_MEM_ALLOC_PROTECT()
+#define LWIP_MEM_ALLOC_UNPROTECT()
+
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
 
 
 /**
@@ -270,9 +276,7 @@
   ram_end->next = MEM_SIZE_ALIGNED;
   ram_end->prev = MEM_SIZE_ALIGNED;
 
-#if !LWIP_USE_HEAP_FROM_INTERRUPT
   mem_sem = sys_sem_new(1);
-#endif /* LWIP_USE_HEAP_FROM_INTERRUPT */
 
   /* initialize the lowest-free pointer to the start of the heap */
   lfree = (struct mem *)ram;
@@ -290,7 +294,7 @@
 mem_free(void *rmem)
 {
   struct mem *mem;
-  LWIP_MEM_DECL_PROTECT();
+  LWIP_MEM_FREE_DECL_PROTECT();
 
   if (rmem == NULL) {
     LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));
@@ -298,18 +302,19 @@
   }
   LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
 
-  /* protect the heap from concurrent access */
-  LWIP_MEM_PROTECT();
-
   LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
     (u8_t *)rmem < (u8_t *)ram_end);
 
   if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
+    SYS_ARCH_DECL_PROTECT(lev);
     LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
-    MEM_STATS_INC(err);
-    LWIP_MEM_UNPROTECT();
+    SYS_ARCH_PROTECT(lev);
+    MEM_STATS_INC(illegal);
+    SYS_ARCH_UNPROTECT(lev);
     return;
   }
+  /* protect the heap from concurrent access */
+  LWIP_MEM_FREE_PROTECT();
   /* Get the corresponding struct mem ... */
   mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
   /* ... which has to be in a used state ... */
@@ -326,7 +331,8 @@
 
   /* finally, see if prev or next are free also */
   plug_holes(mem);
-  LWIP_MEM_UNPROTECT();
+  mem_free_count = 1;
+  LWIP_MEM_FREE_UNPROTECT();
 }
 
 /**
@@ -338,6 +344,8 @@
  * @param newsize required size after shrinking (needs to be smaller than or
  *                equal to the previous size)
  * @return for compatibility reasons: is always == rmem, at the moment
+ *         or NULL if newsize is > old size, in which case rmem is NOT touched
+ *         or freed!
  */
 void *
 mem_realloc(void *rmem, mem_size_t newsize)
@@ -345,7 +353,8 @@
   mem_size_t size;
   mem_size_t ptr, ptr2;
   struct mem *mem, *mem2;
-  LWIP_MEM_DECL_PROTECT();
+  /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
+  LWIP_MEM_FREE_DECL_PROTECT();
 
   /* Expand the size of the allocated memory region so that we can
      adjust for alignment. */
@@ -364,7 +373,11 @@
    (u8_t *)rmem < (u8_t *)ram_end);
 
   if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
+    SYS_ARCH_DECL_PROTECT(lev);
     LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));
+    SYS_ARCH_PROTECT(lev);
+    MEM_STATS_INC(illegal);
+    SYS_ARCH_UNPROTECT(lev);
     return rmem;
   }
   /* Get the corresponding struct mem ... */
@@ -384,7 +397,7 @@
   }
 
   /* protect the heap from concurrent access */
-  LWIP_MEM_PROTECT();
+  LWIP_MEM_FREE_PROTECT();
 
   MEM_STATS_DEC_USED(used, (size - newsize));
 
@@ -442,7 +455,8 @@
     -> don't do anyhting. 
     -> the remaining space stays unused since it is too small
   } */
-  LWIP_MEM_UNPROTECT();
+  mem_free_count = 1;
+  LWIP_MEM_FREE_UNPROTECT();
   return rmem;
 }
 
@@ -460,7 +474,8 @@
 {
   mem_size_t ptr, ptr2;
   struct mem *mem, *mem2;
-  LWIP_MEM_DECL_PROTECT();
+  u8_t local_mem_free_count = 0;
+  LWIP_MEM_ALLOC_DECL_PROTECT();
 
   if (size == 0) {
     return NULL;
@@ -480,7 +495,11 @@
   }
 
   /* protect the heap from concurrent access */
-  LWIP_MEM_PROTECT();
+  sys_arch_sem_wait(mem_sem, 0);
+  LWIP_MEM_ALLOC_PROTECT();
+  /* run as long as a mem_free disturbed mem_malloc */
+  do {
+  local_mem_free_count = 0;
 
   /* Scan through the heap searching for a free block that is big enough,
    * beginning with the lowest free block.
@@ -488,6 +507,16 @@
   for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
        ptr = ((struct mem *)&ram[ptr])->next) {
     mem = (struct mem *)&ram[ptr];
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+    mem_free_count = 0;
+    LWIP_MEM_ALLOC_UNPROTECT();
+    /* allow mem_free to run */
+    LWIP_MEM_ALLOC_PROTECT();
+    if (mem_free_count != 0) {
+      local_mem_free_count = mem_free_count;
+    }
+    mem_free_count = 0;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
 
     if ((!mem->used) &&
         (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
@@ -534,11 +563,15 @@
       if (mem == lfree) {
         /* Find next free block after mem and update lowest free pointer */
         while (lfree->used && lfree != ram_end) {
+          LWIP_MEM_ALLOC_UNPROTECT();
+          /* prevent high interrupt latency... */
+          LWIP_MEM_ALLOC_PROTECT();
           lfree = (struct mem *)&ram[lfree->next];
         }
         LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
       }
-      LWIP_MEM_UNPROTECT();
+      LWIP_MEM_ALLOC_UNPROTECT();
+      sys_sem_signal(mem_sem);
       LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
        (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
       LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
@@ -549,9 +582,12 @@
       return (u8_t *)mem + SIZEOF_STRUCT_MEM;
     }
   }
+    /* if we got interrupted by a mem_free, try again */
+  } while(local_mem_free_count != 0);
   LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
   MEM_STATS_INC(err);
-  LWIP_MEM_UNPROTECT();
+  LWIP_MEM_ALLOC_UNPROTECT();
+  sys_sem_signal(mem_sem);
   return NULL;
 }
 
