Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
mem.c
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 00065 #include <string.h> 00066 00067 #if MEM_USE_POOLS 00068 /* lwIP head implemented with different sized pools */ 00069 00070 /** 00071 * Allocate memory: determine the smallest pool that is big enough 00072 * to contain an element of 'size' and get an element from that pool. 00073 * 00074 * @param size the size in bytes of the memory needed 00075 * @return a pointer to the allocated memory or NULL if the pool is empty 00076 */ 00077 void * 00078 mem_malloc(mem_size_t size) 00079 { 00080 struct memp_malloc_helper *element; 00081 memp_t poolnr; 00082 mem_size_t required_size = size + sizeof(struct memp_malloc_helper); 00083 00084 for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) { 00085 #if MEM_USE_POOLS_TRY_BIGGER_POOL 00086 again: 00087 #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ 00088 /* is this pool big enough to hold an element of the required size 00089 plus a struct memp_malloc_helper that saves the pool this element came from? */ 00090 if (required_size <= memp_sizes[poolnr]) { 00091 break; 00092 } 00093 } 00094 if (poolnr > MEMP_POOL_LAST) { 00095 LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); 00096 return NULL; 00097 } 00098 element = (struct memp_malloc_helper*)memp_malloc(poolnr); 00099 if (element == NULL) { 00100 /* No need to DEBUGF or ASSERT: This error is already 00101 taken care of in memp.c */ 00102 #if MEM_USE_POOLS_TRY_BIGGER_POOL 00103 /** Try a bigger pool if this one is empty! */ 00104 if (poolnr < MEMP_POOL_LAST) { 00105 poolnr++; 00106 goto again; 00107 } 00108 #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ 00109 return NULL; 00110 } 00111 00112 /* save the pool number this element came from */ 00113 element->poolnr = poolnr; 00114 /* and return a pointer to the memory directly after the struct memp_malloc_helper */ 00115 element++; 00116 00117 return element; 00118 } 00119 00120 /** 00121 * Free memory previously allocated by mem_malloc. Loads the pool number 00122 * and calls memp_free with that pool number to put the element back into 00123 * its pool 00124 * 00125 * @param rmem the memory element to free 00126 */ 00127 void 00128 mem_free(void *rmem) 00129 { 00130 struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem; 00131 00132 LWIP_ASSERT("rmem != NULL", (rmem != NULL)); 00133 LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); 00134 00135 /* get the original struct memp_malloc_helper */ 00136 hmem--; 00137 00138 LWIP_ASSERT("hmem != NULL", (hmem != NULL)); 00139 LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); 00140 LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); 00141 00142 /* and put it in the pool we saved earlier */ 00143 memp_free(hmem->poolnr, hmem); 00144 } 00145 00146 #else /* MEM_USE_POOLS */ 00147 /* lwIP replacement for your libc malloc() */ 00148 00149 /** 00150 * The heap is made up as a list of structs of this type. 00151 * This does not have to be aligned since for getting its size, 00152 * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes. 00153 */ 00154 struct mem { 00155 /** index (-> ram[next]) of the next struct */ 00156 mem_size_t next; 00157 /** index (-> ram[next]) of the next struct */ 00158 mem_size_t prev; 00159 /** 1: this area is used; 0: this area is unused */ 00160 u8_t used; 00161 }; 00162 00163 /** All allocated blocks will be MIN_SIZE bytes big, at least! 00164 * MIN_SIZE can be overridden to suit your needs. Smaller values save space, 00165 * larger values could prevent too small blocks to fragment the RAM too much. */ 00166 #ifndef MIN_SIZE 00167 #define MIN_SIZE 12 00168 #endif /* MIN_SIZE */ 00169 /* some alignment macros: we define them here for better source code layout */ 00170 #define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) 00171 #define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) 00172 #define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) 00173 00174 #ifndef MEM_POSITION 00175 #define MEM_POSITION 00176 #endif 00177 00178 /** the heap. we need one struct mem at the end and some room for alignment */ 00179 static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT] MEM_POSITION; 00180 /** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ 00181 static u8_t *ram; 00182 /** the last entry, always unused! */ 00183 static struct mem *ram_end; 00184 /** pointer to the lowest free block, this is used for faster search */ 00185 static struct mem *lfree; 00186 00187 /** concurrent access protection */ 00188 //static sys_sem_t mem_sem; 00189 00190 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00191 00192 static volatile u8_t mem_free_count; 00193 00194 /* Allow mem_free from other (e.g. interrupt) context */ 00195 #define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) 00196 #define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) 00197 #define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) 00198 #define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) 00199 #define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) 00200 #define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) 00201 00202 #else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00203 00204 /* Protect the heap only by using a semaphore */ 00205 #define LWIP_MEM_FREE_DECL_PROTECT() 00206 #define LWIP_MEM_FREE_PROTECT() sys_arch_sem_wait(mem_sem, 0) 00207 #define LWIP_MEM_FREE_UNPROTECT() sys_sem_signal(mem_sem) 00208 /* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ 00209 #define LWIP_MEM_ALLOC_DECL_PROTECT() 00210 #define LWIP_MEM_ALLOC_PROTECT() 00211 #define LWIP_MEM_ALLOC_UNPROTECT() 00212 00213 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00214 00215 00216 /** 00217 * "Plug holes" by combining adjacent empty struct mems. 00218 * After this function is through, there should not exist 00219 * one empty struct mem pointing to another empty struct mem. 00220 * 00221 * @param mem this points to a struct mem which just has been freed 00222 * @internal this function is only called by mem_free() and mem_realloc() 00223 * 00224 * This assumes access to the heap is protected by the calling function 00225 * already. 00226 */ 00227 static void 00228 plug_holes(struct mem *mem) 00229 { 00230 struct mem *nmem; 00231 struct mem *pmem; 00232 00233 LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); 00234 LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); 00235 LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); 00236 00237 /* plug hole forward */ 00238 LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); 00239 00240 nmem = (struct mem *)&ram[mem->next]; 00241 if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { 00242 /* if mem->next is unused and not end of ram, combine mem and mem->next */ 00243 if (lfree == nmem) { 00244 lfree = mem; 00245 } 00246 mem->next = nmem->next; 00247 ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram; 00248 } 00249 00250 /* plug hole backward */ 00251 pmem = (struct mem *)&ram[mem->prev]; 00252 if (pmem != mem && pmem->used == 0) { 00253 /* if mem->prev is unused, combine mem and mem->prev */ 00254 if (lfree == mem) { 00255 lfree = pmem; 00256 } 00257 pmem->next = mem->next; 00258 ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram; 00259 } 00260 } 00261 00262 /** 00263 * Zero the heap and initialize start, end and lowest-free 00264 */ 00265 void 00266 mem_init(void) 00267 { 00268 struct mem *mem; 00269 00270 LWIP_ASSERT("Sanity check alignment", 00271 (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); 00272 00273 /* align the heap */ 00274 ram = LWIP_MEM_ALIGN(ram_heap); 00275 /* initialize the start of the heap */ 00276 mem = (struct mem *)ram; 00277 mem->next = MEM_SIZE_ALIGNED; 00278 mem->prev = 0; 00279 mem->used = 0; 00280 /* initialize the end of the heap */ 00281 ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED]; 00282 ram_end->used = 1; 00283 ram_end->next = MEM_SIZE_ALIGNED; 00284 ram_end->prev = MEM_SIZE_ALIGNED; 00285 00286 //mem_sem = sys_sem_new(1); 00287 00288 /* initialize the lowest-free pointer to the start of the heap */ 00289 lfree = (struct mem *)ram; 00290 00291 MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); 00292 } 00293 00294 /** 00295 * Put a struct mem back on the heap 00296 * 00297 * @param rmem is the data portion of a struct mem as returned by a previous 00298 * call to mem_malloc() 00299 */ 00300 void 00301 mem_free(void *rmem) 00302 { 00303 struct mem *mem; 00304 LWIP_MEM_FREE_DECL_PROTECT(); 00305 00306 if (rmem == NULL) { 00307 LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n")); 00308 return; 00309 } 00310 LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); 00311 00312 LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && 00313 (u8_t *)rmem < (u8_t *)ram_end); 00314 00315 if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { 00316 SYS_ARCH_DECL_PROTECT(lev); 00317 LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n")); 00318 /* protect mem stats from concurrent access */ 00319 SYS_ARCH_PROTECT(lev); 00320 MEM_STATS_INC(illegal); 00321 SYS_ARCH_UNPROTECT(lev); 00322 return; 00323 } 00324 /* protect the heap from concurrent access */ 00325 LWIP_MEM_FREE_PROTECT(); 00326 /* Get the corresponding struct mem ... */ 00327 mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); 00328 /* ... which has to be in a used state ... */ 00329 LWIP_ASSERT("mem_free: mem->used", mem->used); 00330 /* ... and is now unused. */ 00331 mem->used = 0; 00332 00333 if (mem < lfree) { 00334 /* the newly freed struct is now the lowest */ 00335 lfree = mem; 00336 } 00337 00338 MEM_STATS_DEC_USED(used, mem->next - ((u8_t *)mem - ram)); 00339 00340 /* finally, see if prev or next are free also */ 00341 plug_holes(mem); 00342 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00343 mem_free_count = 1; 00344 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00345 LWIP_MEM_FREE_UNPROTECT(); 00346 } 00347 00348 /** 00349 * In contrast to its name, mem_realloc can only shrink memory, not expand it. 00350 * Since the only use (for now) is in pbuf_realloc (which also can only shrink), 00351 * this shouldn't be a problem! 00352 * 00353 * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked 00354 * @param newsize required size after shrinking (needs to be smaller than or 00355 * equal to the previous size) 00356 * @return for compatibility reasons: is always == rmem, at the moment 00357 * or NULL if newsize is > old size, in which case rmem is NOT touched 00358 * or freed! 00359 */ 00360 void * 00361 mem_realloc(void *rmem, mem_size_t newsize) 00362 { 00363 mem_size_t size; 00364 mem_size_t ptr, ptr2; 00365 struct mem *mem, *mem2; 00366 /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ 00367 LWIP_MEM_FREE_DECL_PROTECT(); 00368 00369 /* Expand the size of the allocated memory region so that we can 00370 adjust for alignment. */ 00371 newsize = LWIP_MEM_ALIGN_SIZE(newsize); 00372 00373 if(newsize < MIN_SIZE_ALIGNED) { 00374 /* every data block must be at least MIN_SIZE_ALIGNED long */ 00375 newsize = MIN_SIZE_ALIGNED; 00376 } 00377 00378 if (newsize > MEM_SIZE_ALIGNED) { 00379 return NULL; 00380 } 00381 00382 LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram && 00383 (u8_t *)rmem < (u8_t *)ram_end); 00384 00385 if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { 00386 SYS_ARCH_DECL_PROTECT(lev); 00387 LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n")); 00388 /* protect mem stats from concurrent access */ 00389 SYS_ARCH_PROTECT(lev); 00390 MEM_STATS_INC(illegal); 00391 SYS_ARCH_UNPROTECT(lev); 00392 return rmem; 00393 } 00394 /* Get the corresponding struct mem ... */ 00395 mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); 00396 /* ... and its offset pointer */ 00397 ptr = (u8_t *)mem - ram; 00398 00399 size = mem->next - ptr - SIZEOF_STRUCT_MEM; 00400 LWIP_ASSERT("mem_realloc can only shrink memory", newsize <= size); 00401 if (newsize > size) { 00402 /* not supported */ 00403 return NULL; 00404 } 00405 if (newsize == size) { 00406 /* No change in size, simply return */ 00407 return rmem; 00408 } 00409 00410 /* protect the heap from concurrent access */ 00411 LWIP_MEM_FREE_PROTECT(); 00412 00413 MEM_STATS_DEC_USED(used, (size - newsize)); 00414 00415 mem2 = (struct mem *)&ram[mem->next]; 00416 if(mem2->used == 0) { 00417 /* The next struct is unused, we can simply move it at little */ 00418 mem_size_t next; 00419 /* remember the old next pointer */ 00420 next = mem2->next; 00421 /* create new struct mem which is moved directly after the shrinked mem */ 00422 ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; 00423 if (lfree == mem2) { 00424 lfree = (struct mem *)&ram[ptr2]; 00425 } 00426 mem2 = (struct mem *)&ram[ptr2]; 00427 mem2->used = 0; 00428 /* restore the next pointer */ 00429 mem2->next = next; 00430 /* link it back to mem */ 00431 mem2->prev = ptr; 00432 /* link mem to it */ 00433 mem->next = ptr2; 00434 /* last thing to restore linked list: as we have moved mem2, 00435 * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not 00436 * the end of the heap */ 00437 if (mem2->next != MEM_SIZE_ALIGNED) { 00438 ((struct mem *)&ram[mem2->next])->prev = ptr2; 00439 } 00440 /* no need to plug holes, we've already done that */ 00441 } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { 00442 /* Next struct is used but there's room for another struct mem with 00443 * at least MIN_SIZE_ALIGNED of data. 00444 * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem 00445 * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). 00446 * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty 00447 * region that couldn't hold data, but when mem->next gets freed, 00448 * the 2 regions would be combined, resulting in more free memory */ 00449 ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; 00450 mem2 = (struct mem *)&ram[ptr2]; 00451 if (mem2 < lfree) { 00452 lfree = mem2; 00453 } 00454 mem2->used = 0; 00455 mem2->next = mem->next; 00456 mem2->prev = ptr; 00457 mem->next = ptr2; 00458 if (mem2->next != MEM_SIZE_ALIGNED) { 00459 ((struct mem *)&ram[mem2->next])->prev = ptr2; 00460 } 00461 /* the original mem->next is used, so no need to plug holes! */ 00462 } 00463 /* else { 00464 next struct mem is used but size between mem and mem2 is not big enough 00465 to create another struct mem 00466 -> don't do anyhting. 00467 -> the remaining space stays unused since it is too small 00468 } */ 00469 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00470 mem_free_count = 1; 00471 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00472 LWIP_MEM_FREE_UNPROTECT(); 00473 return rmem; 00474 } 00475 00476 /** 00477 * Adam's mem_malloc() plus solution for bug #17922 00478 * Allocate a block of memory with a minimum of 'size' bytes. 00479 * 00480 * @param size is the minimum size of the requested block in bytes. 00481 * @return pointer to allocated memory or NULL if no free memory was found. 00482 * 00483 * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). 00484 */ 00485 void * 00486 mem_malloc(mem_size_t size) 00487 { 00488 mem_size_t ptr, ptr2; 00489 struct mem *mem, *mem2; 00490 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00491 u8_t local_mem_free_count = 0; 00492 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00493 LWIP_MEM_ALLOC_DECL_PROTECT(); 00494 00495 if (size == 0) { 00496 return NULL; 00497 } 00498 00499 /* Expand the size of the allocated memory region so that we can 00500 adjust for alignment. */ 00501 size = LWIP_MEM_ALIGN_SIZE(size); 00502 00503 if(size < MIN_SIZE_ALIGNED) { 00504 /* every data block must be at least MIN_SIZE_ALIGNED long */ 00505 size = MIN_SIZE_ALIGNED; 00506 } 00507 00508 if (size > MEM_SIZE_ALIGNED) { 00509 return NULL; 00510 } 00511 00512 /* protect the heap from concurrent access */ 00513 sys_arch_sem_wait(mem_sem, 0); 00514 LWIP_MEM_ALLOC_PROTECT(); 00515 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00516 /* run as long as a mem_free disturbed mem_malloc */ 00517 do { 00518 local_mem_free_count = 0; 00519 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00520 00521 /* Scan through the heap searching for a free block that is big enough, 00522 * beginning with the lowest free block. 00523 */ 00524 for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size; 00525 ptr = ((struct mem *)&ram[ptr])->next) { 00526 mem = (struct mem *)&ram[ptr]; 00527 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00528 mem_free_count = 0; 00529 LWIP_MEM_ALLOC_UNPROTECT(); 00530 /* allow mem_free to run */ 00531 LWIP_MEM_ALLOC_PROTECT(); 00532 if (mem_free_count != 0) { 00533 local_mem_free_count = mem_free_count; 00534 } 00535 mem_free_count = 0; 00536 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00537 00538 if ((!mem->used) && 00539 (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { 00540 /* mem is not used and at least perfect fit is possible: 00541 * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ 00542 00543 if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { 00544 /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing 00545 * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') 00546 * -> split large block, create empty remainder, 00547 * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if 00548 * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, 00549 * struct mem would fit in but no data between mem2 and mem2->next 00550 * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty 00551 * region that couldn't hold data, but when mem->next gets freed, 00552 * the 2 regions would be combined, resulting in more free memory 00553 */ 00554 ptr2 = ptr + SIZEOF_STRUCT_MEM + size; 00555 /* create mem2 struct */ 00556 mem2 = (struct mem *)&ram[ptr2]; 00557 mem2->used = 0; 00558 mem2->next = mem->next; 00559 mem2->prev = ptr; 00560 /* and insert it between mem and mem->next */ 00561 mem->next = ptr2; 00562 mem->used = 1; 00563 00564 if (mem2->next != MEM_SIZE_ALIGNED) { 00565 ((struct mem *)&ram[mem2->next])->prev = ptr2; 00566 } 00567 MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); 00568 } else { 00569 /* (a mem2 struct does no fit into the user data space of mem and mem->next will always 00570 * be used at this point: if not we have 2 unused structs in a row, plug_holes should have 00571 * take care of this). 00572 * -> near fit or excact fit: do not split, no mem2 creation 00573 * also can't move mem->next directly behind mem, since mem->next 00574 * will always be used at this point! 00575 */ 00576 mem->used = 1; 00577 MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram)); 00578 } 00579 00580 if (mem == lfree) { 00581 /* Find next free block after mem and update lowest free pointer */ 00582 while (lfree->used && lfree != ram_end) { 00583 LWIP_MEM_ALLOC_UNPROTECT(); 00584 /* prevent high interrupt latency... */ 00585 LWIP_MEM_ALLOC_PROTECT(); 00586 lfree = (struct mem *)&ram[lfree->next]; 00587 } 00588 LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); 00589 } 00590 LWIP_MEM_ALLOC_UNPROTECT(); 00591 sys_sem_signal(mem_sem); 00592 LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", 00593 (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); 00594 LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", 00595 ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); 00596 LWIP_ASSERT("mem_malloc: sanity check alignment", 00597 (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); 00598 00599 return (u8_t *)mem + SIZEOF_STRUCT_MEM; 00600 } 00601 } 00602 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00603 /* if we got interrupted by a mem_free, try again */ 00604 } while(local_mem_free_count != 0); 00605 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00606 LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); 00607 MEM_STATS_INC(err); 00608 LWIP_MEM_ALLOC_UNPROTECT(); 00609 sys_sem_signal(mem_sem); 00610 return NULL; 00611 } 00612 00613 #endif /* MEM_USE_POOLS */ 00614 /** 00615 * Contiguously allocates enough space for count objects that are size bytes 00616 * of memory each and returns a pointer to the allocated memory. 00617 * 00618 * The allocated memory is filled with bytes of value zero. 00619 * 00620 * @param count number of objects to allocate 00621 * @param size size of the objects to allocate 00622 * @return pointer to allocated memory / NULL pointer if there is an error 00623 */ 00624 void *mem_calloc(mem_size_t count, mem_size_t size) 00625 { 00626 void *p; 00627 00628 /* allocate 'count' objects of size 'size' */ 00629 p = mem_malloc(count * size); 00630 if (p) { 00631 /* zero the memory */ 00632 memset(p, 0, count * size); 00633 } 00634 return p; 00635 } 00636 #endif /* !MEM_LIBC_MALLOC */
Generated on Tue Jul 12 2022 19:24:05 by
1.7.2