Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mem.c Source File

mem.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Dynamic memory manager
00004  *
00005  * This is a lightweight replacement for the standard C library malloc().
00006  *
00007  * If you want to use the standard C library malloc() instead, define
00008  * MEM_LIBC_MALLOC to 1 in your lwipopts.h
00009  *
00010  * To let mem_malloc() use pools (prevents fragmentation and is much faster than
00011  * a heap but might waste some memory), define MEM_USE_POOLS to 1, define
00012  * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
00013  * of pools like this (more pools can be added between _START and _END):
00014  *
00015  * Define three pools with sizes 256, 512, and 1512 bytes
00016  * LWIP_MALLOC_MEMPOOL_START
00017  * LWIP_MALLOC_MEMPOOL(20, 256)
00018  * LWIP_MALLOC_MEMPOOL(10, 512)
00019  * LWIP_MALLOC_MEMPOOL(5, 1512)
00020  * LWIP_MALLOC_MEMPOOL_END
00021  */
00022 
00023 /*
00024  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00025  * All rights reserved.
00026  *
00027  * Redistribution and use in source and binary forms, with or without modification,
00028  * are permitted provided that the following conditions are met:
00029  *
00030  * 1. Redistributions of source code must retain the above copyright notice,
00031  *    this list of conditions and the following disclaimer.
00032  * 2. Redistributions in binary form must reproduce the above copyright notice,
00033  *    this list of conditions and the following disclaimer in the documentation
00034  *    and/or other materials provided with the distribution.
00035  * 3. The name of the author may not be used to endorse or promote products
00036  *    derived from this software without specific prior written permission.
00037  *
00038  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00039  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00040  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00041  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00042  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00043  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00044  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00045  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00046  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00047  * OF SUCH DAMAGE.
00048  *
00049  * This file is part of the lwIP TCP/IP stack.
00050  *
00051  * Author: Adam Dunkels <adam@sics.se>
00052  *         Simon Goldschmidt
00053  *
00054  */
00055 
00056 #include "lwip/opt.h"
00057 
00058 #if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */
00059 
00060 #include "lwip/def.h"
00061 #include "lwip/mem.h"
00062 #include "lwip/sys.h"
00063 #include "lwip/stats.h"
00064 #include "lwip/err.h"
00065 
00066 #include <string.h>
00067 
00068 #if MEM_USE_POOLS
00069 /* lwIP head implemented with different sized pools */
00070 
00071 /**
00072  * Allocate memory: determine the smallest pool that is big enough
00073  * to contain an element of 'size' and get an element from that pool.
00074  *
00075  * @param size the size in bytes of the memory needed
00076  * @return a pointer to the allocated memory or NULL if the pool is empty
00077  */
00078 void *
00079 mem_malloc(mem_size_t size)
00080 {
00081   struct memp_malloc_helper *element;
00082   memp_t poolnr;
00083   mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
00084 
00085   for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) {
00086 #if MEM_USE_POOLS_TRY_BIGGER_POOL
00087 again:
00088 #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
00089     /* is this pool big enough to hold an element of the required size
00090        plus a struct memp_malloc_helper that saves the pool this element came from? */
00091     if (required_size <= memp_sizes[poolnr]) {
00092       break;
00093     }
00094   }
00095   if (poolnr > MEMP_POOL_LAST) {
00096     LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
00097     return NULL;
00098   }
00099   element = (struct memp_malloc_helper*)memp_malloc(poolnr);
00100   if (element == NULL) {
00101     /* No need to DEBUGF or ASSERT: This error is already
00102        taken care of in memp.c */
00103 #if MEM_USE_POOLS_TRY_BIGGER_POOL
00104     /** Try a bigger pool if this one is empty! */
00105     if (poolnr < MEMP_POOL_LAST) {
00106       poolnr++;
00107       goto again;
00108     }
00109 #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
00110     return NULL;
00111   }
00112 
00113   /* save the pool number this element came from */
00114   element->poolnr = poolnr;
00115   /* and return a pointer to the memory directly after the struct memp_malloc_helper */
00116   element++;
00117 
00118   return element;
00119 }
00120 
00121 /**
00122  * Free memory previously allocated by mem_malloc. Loads the pool number
00123  * and calls memp_free with that pool number to put the element back into
00124  * its pool
00125  *
00126  * @param rmem the memory element to free
00127  */
00128 void
00129 mem_free(void *rmem)
00130 {
00131   struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
00132 
00133   LWIP_ASSERT("rmem != NULL", (rmem != NULL));
00134   LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
00135 
00136   /* get the original struct memp_malloc_helper */
00137   hmem--;
00138 
00139   LWIP_ASSERT("hmem != NULL", (hmem != NULL));
00140   LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
00141   LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
00142 
00143   /* and put it in the pool we saved earlier */
00144   memp_free(hmem->poolnr, hmem);
00145 }
00146 
00147 #else /* MEM_USE_POOLS */
00148 /* lwIP replacement for your libc malloc() */
00149 
00150 /**
00151  * The heap is made up as a list of structs of this type.
00152  * This does not have to be aligned since for getting its size,
00153  * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
00154  */
00155 struct mem {
00156   /** index (-> ram[next]) of the next struct */
00157   mem_size_t next;
00158   /** index (-> ram[prev]) of the previous struct */
00159   mem_size_t prev;
00160   /** 1: this area is used; 0: this area is unused */
00161   u8_t used;
00162 };
00163 
00164 /** All allocated blocks will be MIN_SIZE bytes big, at least!
00165  * MIN_SIZE can be overridden to suit your needs. Smaller values save space,
00166  * larger values could prevent too small blocks to fragment the RAM too much. */
00167 #ifndef MIN_SIZE
00168 #define MIN_SIZE             12
00169 #endif /* MIN_SIZE */
00170 /* some alignment macros: we define them here for better source code layout */
00171 #define MIN_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MIN_SIZE)
00172 #define SIZEOF_STRUCT_MEM    LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
00173 #define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
00174 
00175 /** If you want to relocate the heap to external memory, simply define
00176  * LWIP_RAM_HEAP_POINTER as a void-pointer to that location.
00177  * If so, make sure the memory at that location is big enough (see below on
00178  * how that space is calculated). */
00179 #ifndef LWIP_RAM_HEAP_POINTER
00180 /** the heap. we need one struct mem at the end and some room for alignment */
00181 u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT] MEM_POSITION;
00182 #define LWIP_RAM_HEAP_POINTER ram_heap
00183 #endif /* LWIP_RAM_HEAP_POINTER */
00184 
00185 /** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
00186 static u8_t *ram;
00187 /** the last entry, always unused! */
00188 static struct mem *ram_end;
00189 /** pointer to the lowest free block, this is used for faster search */
00190 static struct mem *lfree;
00191 
00192 #if (NO_SYS==0) //Pointless if monothreaded app
00193 /** concurrent access protection */
00194 static sys_mutex_t mem_mutex;
00195 #endif
00196 
00197 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
00198 
00199 static volatile u8_t mem_free_count;
00200 
00201 /* Allow mem_free from other (e.g. interrupt) context */
00202 #define LWIP_MEM_FREE_DECL_PROTECT()  SYS_ARCH_DECL_PROTECT(lev_free)
00203 #define LWIP_MEM_FREE_PROTECT()       SYS_ARCH_PROTECT(lev_free)
00204 #define LWIP_MEM_FREE_UNPROTECT()     SYS_ARCH_UNPROTECT(lev_free)
00205 #define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
00206 #define LWIP_MEM_ALLOC_PROTECT()      SYS_ARCH_PROTECT(lev_alloc)
00207 #define LWIP_MEM_ALLOC_UNPROTECT()    SYS_ARCH_UNPROTECT(lev_alloc)
00208 
00209 #else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
00210 
00211 /* Protect the heap only by using a semaphore */
00212 #define LWIP_MEM_FREE_DECL_PROTECT()
00213 #define LWIP_MEM_FREE_PROTECT()    sys_mutex_lock(&mem_mutex)
00214 #define LWIP_MEM_FREE_UNPROTECT()  sys_mutex_unlock(&mem_mutex)
00215 /* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
00216 #define LWIP_MEM_ALLOC_DECL_PROTECT()
00217 #define LWIP_MEM_ALLOC_PROTECT()
00218 #define LWIP_MEM_ALLOC_UNPROTECT()
00219 
00220 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
00221 
00222 
00223 /**
00224  * "Plug holes" by combining adjacent empty struct mems.
00225  * After this function is through, there should not exist
00226  * one empty struct mem pointing to another empty struct mem.
00227  *
00228  * @param mem this points to a struct mem which just has been freed
00229  * @internal this function is only called by mem_free() and mem_trim()
00230  *
00231  * This assumes access to the heap is protected by the calling function
00232  * already.
00233  */
00234 static void
00235 plug_holes(struct mem *mem)
00236 {
00237   struct mem *nmem;
00238   struct mem *pmem;
00239 
00240   LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
00241   LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
00242   LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
00243 
00244   /* plug hole forward */
00245   LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
00246 
00247   nmem = (struct mem *)(void *)&ram[mem->next];
00248   if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
00249     /* if mem->next is unused and not end of ram, combine mem and mem->next */
00250     if (lfree == nmem) {
00251       lfree = mem;
00252     }
00253     mem->next = nmem->next;
00254     ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
00255   }
00256 
00257   /* plug hole backward */
00258   pmem = (struct mem *)(void *)&ram[mem->prev];
00259   if (pmem != mem && pmem->used == 0) {
00260     /* if mem->prev is unused, combine mem and mem->prev */
00261     if (lfree == mem) {
00262       lfree = pmem;
00263     }
00264     pmem->next = mem->next;
00265     ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
00266   }
00267 }
00268 
00269 /**
00270  * Zero the heap and initialize start, end and lowest-free
00271  */
00272 void
00273 mem_init(void)
00274 {
00275   struct mem *mem;
00276 
00277   LWIP_ASSERT("Sanity check alignment",
00278     (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);
00279 
00280   /* align the heap */
00281   ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);
00282   /* initialize the start of the heap */
00283   mem = (struct mem *)(void *)ram;
00284   mem->next = MEM_SIZE_ALIGNED;
00285   mem->prev = 0;
00286   mem->used = 0;
00287   /* initialize the end of the heap */
00288   ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED];
00289   ram_end->used = 1;
00290   ram_end->next = MEM_SIZE_ALIGNED;
00291   ram_end->prev = MEM_SIZE_ALIGNED;
00292 
00293   /* initialize the lowest-free pointer to the start of the heap */
00294   lfree = (struct mem *)(void *)ram;
00295 
00296   MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
00297 
00298   if(sys_mutex_new(&mem_mutex) != ERR_OK) {
00299     LWIP_ASSERT("failed to create mem_mutex", 0);
00300   }
00301 }
00302 
00303 /**
00304  * Put a struct mem back on the heap
00305  *
00306  * @param rmem is the data portion of a struct mem as returned by a previous
00307  *             call to mem_malloc()
00308  */
00309 void
00310 mem_free(void *rmem)
00311 {
00312   struct mem *mem;
00313   LWIP_MEM_FREE_DECL_PROTECT();
00314 
00315   if (rmem == NULL) {
00316     LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
00317     return;
00318   }
00319   LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
00320 
00321   LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
00322     (u8_t *)rmem < (u8_t *)ram_end);
00323 
00324   if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
00325     SYS_ARCH_DECL_PROTECT(lev);
00326     LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
00327     /* protect mem stats from concurrent access */
00328     SYS_ARCH_PROTECT(lev);
00329     MEM_STATS_INC(illegal);
00330     SYS_ARCH_UNPROTECT(lev);
00331     return;
00332   }
00333   /* protect the heap from concurrent access */
00334   LWIP_MEM_FREE_PROTECT();
00335   /* Get the corresponding struct mem ... */
00336   mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
00337   /* ... which has to be in a used state ... */
00338   LWIP_ASSERT("mem_free: mem->used", mem->used);
00339   /* ... and is now unused. */
00340   mem->used = 0;
00341 
00342   if (mem < lfree) {
00343     /* the newly freed struct is now the lowest */
00344     lfree = mem;
00345   }
00346 
00347   MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));
00348 
00349   /* finally, see if prev or next are free also */
00350   plug_holes(mem);
00351 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
00352   mem_free_count = 1;
00353 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
00354   LWIP_MEM_FREE_UNPROTECT();
00355 }
00356 
00357 /**
00358  * Shrink memory returned by mem_malloc().
00359  *
00360  * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked
00361  * @param newsize required size after shrinking (needs to be smaller than or
00362  *                equal to the previous size)
00363  * @return for compatibility reasons: is always == rmem, at the moment
00364  *         or NULL if newsize is > old size, in which case rmem is NOT touched
00365  *         or freed!
00366  */
00367 void *
00368 mem_trim(void *rmem, mem_size_t newsize)
00369 {
00370   mem_size_t size;
00371   mem_size_t ptr, ptr2;
00372   struct mem *mem, *mem2;
00373   /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
00374   LWIP_MEM_FREE_DECL_PROTECT();
00375 
00376   /* Expand the size of the allocated memory region so that we can
00377      adjust for alignment. */
00378   newsize = LWIP_MEM_ALIGN_SIZE(newsize);
00379 
00380   if(newsize < MIN_SIZE_ALIGNED) {
00381     /* every data block must be at least MIN_SIZE_ALIGNED long */
00382     newsize = MIN_SIZE_ALIGNED;
00383   }
00384 
00385   if (newsize > MEM_SIZE_ALIGNED) {
00386     return NULL;
00387   }
00388 
00389   LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
00390    (u8_t *)rmem < (u8_t *)ram_end);
00391 
00392   if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
00393     SYS_ARCH_DECL_PROTECT(lev);
00394     LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n"));
00395     /* protect mem stats from concurrent access */
00396     SYS_ARCH_PROTECT(lev);
00397     MEM_STATS_INC(illegal);
00398     SYS_ARCH_UNPROTECT(lev);
00399     return rmem;
00400   }
00401   /* Get the corresponding struct mem ... */
00402   mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
00403   /* ... and its offset pointer */
00404   ptr = (mem_size_t)((u8_t *)mem - ram);
00405 
00406   size = mem->next - ptr - SIZEOF_STRUCT_MEM;
00407   LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size);
00408   if (newsize > size) {
00409     /* not supported */
00410     return NULL;
00411   }
00412   if (newsize == size) {
00413     /* No change in size, simply return */
00414     return rmem;
00415   }
00416 
00417   /* protect the heap from concurrent access */
00418   LWIP_MEM_FREE_PROTECT();
00419 
00420   mem2 = (struct mem *)(void *)&ram[mem->next];
00421   if(mem2->used == 0) {
00422     /* The next struct is unused, we can simply move it at little */
00423     mem_size_t next;
00424     /* remember the old next pointer */
00425     next = mem2->next;
00426     /* create new struct mem which is moved directly after the shrinked mem */
00427     ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
00428     if (lfree == mem2) {
00429       lfree = (struct mem *)(void *)&ram[ptr2];
00430     }
00431     mem2 = (struct mem *)(void *)&ram[ptr2];
00432     mem2->used = 0;
00433     /* restore the next pointer */
00434     mem2->next = next;
00435     /* link it back to mem */
00436     mem2->prev = ptr;
00437     /* link mem to it */
00438     mem->next = ptr2;
00439     /* last thing to restore linked list: as we have moved mem2,
00440      * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
00441      * the end of the heap */
00442     if (mem2->next != MEM_SIZE_ALIGNED) {
00443       ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
00444     }
00445     MEM_STATS_DEC_USED(used, (size - newsize));
00446     /* no need to plug holes, we've already done that */
00447   } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
00448     /* Next struct is used but there's room for another struct mem with
00449      * at least MIN_SIZE_ALIGNED of data.
00450      * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem
00451      * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').
00452      * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
00453      *       region that couldn't hold data, but when mem->next gets freed,
00454      *       the 2 regions would be combined, resulting in more free memory */
00455     ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
00456     mem2 = (struct mem *)(void *)&ram[ptr2];
00457     if (mem2 < lfree) {
00458       lfree = mem2;
00459     }
00460     mem2->used = 0;
00461     mem2->next = mem->next;
00462     mem2->prev = ptr;
00463     mem->next = ptr2;
00464     if (mem2->next != MEM_SIZE_ALIGNED) {
00465       ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
00466     }
00467     MEM_STATS_DEC_USED(used, (size - newsize));
00468     /* the original mem->next is used, so no need to plug holes! */
00469   }
00470   /* else {
00471     next struct mem is used but size between mem and mem2 is not big enough
00472     to create another struct mem
00473     -> don't do anyhting. 
00474     -> the remaining space stays unused since it is too small
00475   } */
00476 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
00477   mem_free_count = 1;
00478 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
00479   LWIP_MEM_FREE_UNPROTECT();
00480   return rmem;
00481 }
00482 
00483 /**
00484  * Adam's mem_malloc() plus solution for bug #17922
00485  * Allocate a block of memory with a minimum of 'size' bytes.
00486  *
00487  * @param size is the minimum size of the requested block in bytes.
00488  * @return pointer to allocated memory or NULL if no free memory was found.
00489  *
00490  * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).
00491  */
00492 void *
00493 mem_malloc(mem_size_t size)
00494 {
00495   mem_size_t ptr, ptr2;
00496   struct mem *mem, *mem2;
00497 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
00498   u8_t local_mem_free_count = 0;
00499 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
00500   LWIP_MEM_ALLOC_DECL_PROTECT();
00501 
00502   if (size == 0) {
00503     return NULL;
00504   }
00505 
00506   /* Expand the size of the allocated memory region so that we can
00507      adjust for alignment. */
00508   size = LWIP_MEM_ALIGN_SIZE(size);
00509 
00510   if(size < MIN_SIZE_ALIGNED) {
00511     /* every data block must be at least MIN_SIZE_ALIGNED long */
00512     size = MIN_SIZE_ALIGNED;
00513   }
00514 
00515   if (size > MEM_SIZE_ALIGNED) {
00516     return NULL;
00517   }
00518 
00519   /* protect the heap from concurrent access */
00520   sys_mutex_lock(&mem_mutex);
00521   LWIP_MEM_ALLOC_PROTECT();
00522 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
00523   /* run as long as a mem_free disturbed mem_malloc */
00524   do {
00525     local_mem_free_count = 0;
00526 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
00527 
00528     /* Scan through the heap searching for a free block that is big enough,
00529      * beginning with the lowest free block.
00530      */
00531     for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size;
00532          ptr = ((struct mem *)(void *)&ram[ptr])->next) {
00533       mem = (struct mem *)(void *)&ram[ptr];
00534 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
00535       mem_free_count = 0;
00536       LWIP_MEM_ALLOC_UNPROTECT();
00537       /* allow mem_free to run */
00538       LWIP_MEM_ALLOC_PROTECT();
00539       if (mem_free_count != 0) {
00540         local_mem_free_count = mem_free_count;
00541       }
00542       mem_free_count = 0;
00543 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
00544 
00545       if ((!mem->used) &&
00546           (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
00547         /* mem is not used and at least perfect fit is possible:
00548          * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
00549 
00550         if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
00551           /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
00552            * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
00553            * -> split large block, create empty remainder,
00554            * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
00555            * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
00556            * struct mem would fit in but no data between mem2 and mem2->next
00557            * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
00558            *       region that couldn't hold data, but when mem->next gets freed,
00559            *       the 2 regions would be combined, resulting in more free memory
00560            */
00561           ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
00562           /* create mem2 struct */
00563           mem2 = (struct mem *)(void *)&ram[ptr2];
00564           mem2->used = 0;
00565           mem2->next = mem->next;
00566           mem2->prev = ptr;
00567           /* and insert it between mem and mem->next */
00568           mem->next = ptr2;
00569           mem->used = 1;
00570 
00571           if (mem2->next != MEM_SIZE_ALIGNED) {
00572             ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
00573           }
00574           MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
00575         } else {
00576           /* (a mem2 struct does no fit into the user data space of mem and mem->next will always
00577            * be used at this point: if not we have 2 unused structs in a row, plug_holes should have
00578            * take care of this).
00579            * -> near fit or excact fit: do not split, no mem2 creation
00580            * also can't move mem->next directly behind mem, since mem->next
00581            * will always be used at this point!
00582            */
00583           mem->used = 1;
00584           MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
00585         }
00586 
00587         if (mem == lfree) {
00588           /* Find next free block after mem and update lowest free pointer */
00589           while (lfree->used && lfree != ram_end) {
00590             LWIP_MEM_ALLOC_UNPROTECT();
00591             /* prevent high interrupt latency... */
00592             LWIP_MEM_ALLOC_PROTECT();
00593             lfree = (struct mem *)(void *)&ram[lfree->next];
00594           }
00595           LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
00596         }
00597         LWIP_MEM_ALLOC_UNPROTECT();
00598         sys_mutex_unlock(&mem_mutex);
00599         LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
00600          (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
00601         LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
00602          ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
00603         LWIP_ASSERT("mem_malloc: sanity check alignment",
00604           (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
00605 
00606         return (u8_t *)mem + SIZEOF_STRUCT_MEM;
00607       }
00608     }
00609 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
00610     /* if we got interrupted by a mem_free, try again */
00611   } while(local_mem_free_count != 0);
00612 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
00613   LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
00614   MEM_STATS_INC(err);
00615   LWIP_MEM_ALLOC_UNPROTECT();
00616   sys_mutex_unlock(&mem_mutex);
00617   return NULL;
00618 }
00619 
00620 #endif /* MEM_USE_POOLS */
00621 /**
00622  * Contiguously allocates enough space for count objects that are size bytes
00623  * of memory each and returns a pointer to the allocated memory.
00624  *
00625  * The allocated memory is filled with bytes of value zero.
00626  *
00627  * @param count number of objects to allocate
00628  * @param size size of the objects to allocate
00629  * @return pointer to allocated memory / NULL pointer if there is an error
00630  */
00631 void *mem_calloc(mem_size_t count, mem_size_t size)
00632 {
00633   void *p;
00634 
00635   /* allocate 'count' objects of size 'size' */
00636   p = mem_malloc(count * size);
00637   if (p) {
00638     /* zero the memory */
00639     memset(p, 0, count * size);
00640   }
00641   return p;
00642 }
00643 
00644 #endif /* !MEM_LIBC_MALLOC */