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 #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 = (memp_t)(poolnr + 1)) { 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 00181 #if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) 00182 # if defined (__ICCARM__) 00183 # define ETHMEM_SECTION 00184 # elif defined(TOOLCHAIN_GCC_CR) 00185 # define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32"))) 00186 # else 00187 # define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned)) 00188 # endif 00189 #elif defined(TARGET_LPC1768) 00190 # define ETHMEM_SECTION __attribute((section("AHBSRAM0"))) 00191 #else 00192 # define ETHMEM_SECTION 00193 #endif 00194 00195 /** the heap. we need one struct mem at the end and some room for alignment */ 00196 u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT] ETHMEM_SECTION; 00197 #define LWIP_RAM_HEAP_POINTER ram_heap 00198 #endif /* LWIP_RAM_HEAP_POINTER */ 00199 00200 /** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ 00201 static u8_t *ram; 00202 /** the last entry, always unused! */ 00203 static struct mem *ram_end; 00204 /** pointer to the lowest free block, this is used for faster search */ 00205 static struct mem *lfree; 00206 00207 /** concurrent access protection */ 00208 static sys_mutex_t mem_mutex; 00209 00210 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00211 00212 static volatile u8_t mem_free_count; 00213 00214 /* Allow mem_free from other (e.g. interrupt) context */ 00215 #define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) 00216 #define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) 00217 #define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) 00218 #define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) 00219 #define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) 00220 #define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) 00221 00222 #else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00223 00224 /* Protect the heap only by using a semaphore */ 00225 #define LWIP_MEM_FREE_DECL_PROTECT() 00226 #define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) 00227 #define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) 00228 /* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ 00229 #define LWIP_MEM_ALLOC_DECL_PROTECT() 00230 #define LWIP_MEM_ALLOC_PROTECT() 00231 #define LWIP_MEM_ALLOC_UNPROTECT() 00232 00233 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00234 00235 00236 /** 00237 * "Plug holes" by combining adjacent empty struct mems. 00238 * After this function is through, there should not exist 00239 * one empty struct mem pointing to another empty struct mem. 00240 * 00241 * @param mem this points to a struct mem which just has been freed 00242 * @internal this function is only called by mem_free() and mem_trim() 00243 * 00244 * This assumes access to the heap is protected by the calling function 00245 * already. 00246 */ 00247 static void 00248 plug_holes(struct mem *mem) 00249 { 00250 struct mem *nmem; 00251 struct mem *pmem; 00252 00253 LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); 00254 LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); 00255 LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); 00256 00257 /* plug hole forward */ 00258 LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); 00259 00260 nmem = (struct mem *)(void *)&ram[mem->next]; 00261 if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { 00262 /* if mem->next is unused and not end of ram, combine mem and mem->next */ 00263 if (lfree == nmem) { 00264 lfree = mem; 00265 } 00266 mem->next = nmem->next; 00267 ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram); 00268 } 00269 00270 /* plug hole backward */ 00271 pmem = (struct mem *)(void *)&ram[mem->prev]; 00272 if (pmem != mem && pmem->used == 0) { 00273 /* if mem->prev is unused, combine mem and mem->prev */ 00274 if (lfree == mem) { 00275 lfree = pmem; 00276 } 00277 pmem->next = mem->next; 00278 ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram); 00279 } 00280 } 00281 00282 /** 00283 * Zero the heap and initialize start, end and lowest-free 00284 */ 00285 void 00286 mem_init(void) 00287 { 00288 struct mem *mem; 00289 00290 LWIP_ASSERT("Sanity check alignment", 00291 (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); 00292 00293 /* align the heap */ 00294 ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); 00295 /* initialize the start of the heap */ 00296 mem = (struct mem *)(void *)ram; 00297 mem->next = MEM_SIZE_ALIGNED; 00298 mem->prev = 0; 00299 mem->used = 0; 00300 /* initialize the end of the heap */ 00301 ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; 00302 ram_end->used = 1; 00303 ram_end->next = MEM_SIZE_ALIGNED; 00304 ram_end->prev = MEM_SIZE_ALIGNED; 00305 00306 /* initialize the lowest-free pointer to the start of the heap */ 00307 lfree = (struct mem *)(void *)ram; 00308 00309 MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); 00310 00311 if(sys_mutex_new(&mem_mutex) != ERR_OK) { 00312 LWIP_ASSERT("failed to create mem_mutex", 0); 00313 } 00314 } 00315 00316 /** 00317 * Put a struct mem back on the heap 00318 * 00319 * @param rmem is the data portion of a struct mem as returned by a previous 00320 * call to mem_malloc() 00321 */ 00322 void 00323 mem_free(void *rmem) 00324 { 00325 struct mem *mem; 00326 LWIP_MEM_FREE_DECL_PROTECT(); 00327 00328 if (rmem == NULL) { 00329 LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); 00330 return; 00331 } 00332 LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); 00333 00334 LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && 00335 (u8_t *)rmem < (u8_t *)ram_end); 00336 00337 if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { 00338 SYS_ARCH_DECL_PROTECT(lev); 00339 LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); 00340 /* protect mem stats from concurrent access */ 00341 SYS_ARCH_PROTECT(lev); 00342 MEM_STATS_INC(illegal); 00343 SYS_ARCH_UNPROTECT(lev); 00344 return; 00345 } 00346 /* protect the heap from concurrent access */ 00347 LWIP_MEM_FREE_PROTECT(); 00348 /* Get the corresponding struct mem ... */ 00349 mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); 00350 /* ... which has to be in a used state ... */ 00351 LWIP_ASSERT("mem_free: mem->used", mem->used); 00352 /* ... and is now unused. */ 00353 mem->used = 0; 00354 00355 if (mem < lfree) { 00356 /* the newly freed struct is now the lowest */ 00357 lfree = mem; 00358 } 00359 00360 MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); 00361 00362 /* finally, see if prev or next are free also */ 00363 plug_holes(mem); 00364 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00365 mem_free_count = 1; 00366 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00367 LWIP_MEM_FREE_UNPROTECT(); 00368 } 00369 00370 /** 00371 * Shrink memory returned by mem_malloc(). 00372 * 00373 * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked 00374 * @param newsize required size after shrinking (needs to be smaller than or 00375 * equal to the previous size) 00376 * @return for compatibility reasons: is always == rmem, at the moment 00377 * or NULL if newsize is > old size, in which case rmem is NOT touched 00378 * or freed! 00379 */ 00380 void * 00381 mem_trim(void *rmem, mem_size_t newsize) 00382 { 00383 mem_size_t size; 00384 mem_size_t ptr, ptr2; 00385 struct mem *mem, *mem2; 00386 /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ 00387 LWIP_MEM_FREE_DECL_PROTECT(); 00388 00389 /* Expand the size of the allocated memory region so that we can 00390 adjust for alignment. */ 00391 newsize = LWIP_MEM_ALIGN_SIZE(newsize); 00392 00393 if(newsize < MIN_SIZE_ALIGNED) { 00394 /* every data block must be at least MIN_SIZE_ALIGNED long */ 00395 newsize = MIN_SIZE_ALIGNED; 00396 } 00397 00398 if (newsize > MEM_SIZE_ALIGNED) { 00399 return NULL; 00400 } 00401 00402 LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && 00403 (u8_t *)rmem < (u8_t *)ram_end); 00404 00405 if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { 00406 SYS_ARCH_DECL_PROTECT(lev); 00407 LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); 00408 /* protect mem stats from concurrent access */ 00409 SYS_ARCH_PROTECT(lev); 00410 MEM_STATS_INC(illegal); 00411 SYS_ARCH_UNPROTECT(lev); 00412 return rmem; 00413 } 00414 /* Get the corresponding struct mem ... */ 00415 mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); 00416 /* ... and its offset pointer */ 00417 ptr = (mem_size_t)((u8_t *)mem - ram); 00418 00419 size = mem->next - ptr - SIZEOF_STRUCT_MEM; 00420 LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); 00421 if (newsize > size) { 00422 /* not supported */ 00423 return NULL; 00424 } 00425 if (newsize == size) { 00426 /* No change in size, simply return */ 00427 return rmem; 00428 } 00429 00430 /* protect the heap from concurrent access */ 00431 LWIP_MEM_FREE_PROTECT(); 00432 00433 mem2 = (struct mem *)(void *)&ram[mem->next]; 00434 if(mem2->used == 0) { 00435 /* The next struct is unused, we can simply move it at little */ 00436 mem_size_t next; 00437 /* remember the old next pointer */ 00438 next = mem2->next; 00439 /* create new struct mem which is moved directly after the shrinked mem */ 00440 ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; 00441 if (lfree == mem2) { 00442 lfree = (struct mem *)(void *)&ram[ptr2]; 00443 } 00444 mem2 = (struct mem *)(void *)&ram[ptr2]; 00445 mem2->used = 0; 00446 /* restore the next pointer */ 00447 mem2->next = next; 00448 /* link it back to mem */ 00449 mem2->prev = ptr; 00450 /* link mem to it */ 00451 mem->next = ptr2; 00452 /* last thing to restore linked list: as we have moved mem2, 00453 * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not 00454 * the end of the heap */ 00455 if (mem2->next != MEM_SIZE_ALIGNED) { 00456 ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; 00457 } 00458 MEM_STATS_DEC_USED(used, (size - newsize)); 00459 /* no need to plug holes, we've already done that */ 00460 } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { 00461 /* Next struct is used but there's room for another struct mem with 00462 * at least MIN_SIZE_ALIGNED of data. 00463 * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem 00464 * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). 00465 * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty 00466 * region that couldn't hold data, but when mem->next gets freed, 00467 * the 2 regions would be combined, resulting in more free memory */ 00468 ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; 00469 mem2 = (struct mem *)(void *)&ram[ptr2]; 00470 if (mem2 < lfree) { 00471 lfree = mem2; 00472 } 00473 mem2->used = 0; 00474 mem2->next = mem->next; 00475 mem2->prev = ptr; 00476 mem->next = ptr2; 00477 if (mem2->next != MEM_SIZE_ALIGNED) { 00478 ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; 00479 } 00480 MEM_STATS_DEC_USED(used, (size - newsize)); 00481 /* the original mem->next is used, so no need to plug holes! */ 00482 } 00483 /* else { 00484 next struct mem is used but size between mem and mem2 is not big enough 00485 to create another struct mem 00486 -> don't do anyhting. 00487 -> the remaining space stays unused since it is too small 00488 } */ 00489 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00490 mem_free_count = 1; 00491 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00492 LWIP_MEM_FREE_UNPROTECT(); 00493 return rmem; 00494 } 00495 00496 /** 00497 * Adam's mem_malloc() plus solution for bug #17922 00498 * Allocate a block of memory with a minimum of 'size' bytes. 00499 * 00500 * @param size is the minimum size of the requested block in bytes. 00501 * @return pointer to allocated memory or NULL if no free memory was found. 00502 * 00503 * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). 00504 */ 00505 void * 00506 mem_malloc(mem_size_t size) 00507 { 00508 mem_size_t ptr, ptr2; 00509 struct mem *mem, *mem2; 00510 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00511 u8_t local_mem_free_count = 0; 00512 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00513 LWIP_MEM_ALLOC_DECL_PROTECT(); 00514 00515 if (size == 0) { 00516 return NULL; 00517 } 00518 00519 /* Expand the size of the allocated memory region so that we can 00520 adjust for alignment. */ 00521 size = LWIP_MEM_ALIGN_SIZE(size); 00522 00523 if(size < MIN_SIZE_ALIGNED) { 00524 /* every data block must be at least MIN_SIZE_ALIGNED long */ 00525 size = MIN_SIZE_ALIGNED; 00526 } 00527 00528 if (size > MEM_SIZE_ALIGNED) { 00529 return NULL; 00530 } 00531 00532 /* protect the heap from concurrent access */ 00533 sys_mutex_lock(&mem_mutex); 00534 LWIP_MEM_ALLOC_PROTECT(); 00535 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00536 /* run as long as a mem_free disturbed mem_malloc */ 00537 do { 00538 local_mem_free_count = 0; 00539 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00540 00541 /* Scan through the heap searching for a free block that is big enough, 00542 * beginning with the lowest free block. 00543 */ 00544 for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size; 00545 ptr = ((struct mem *)(void *)&ram[ptr])->next) { 00546 mem = (struct mem *)(void *)&ram[ptr]; 00547 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00548 mem_free_count = 0; 00549 LWIP_MEM_ALLOC_UNPROTECT(); 00550 /* allow mem_free to run */ 00551 LWIP_MEM_ALLOC_PROTECT(); 00552 if (mem_free_count != 0) { 00553 local_mem_free_count = mem_free_count; 00554 } 00555 mem_free_count = 0; 00556 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00557 00558 if ((!mem->used) && 00559 (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { 00560 /* mem is not used and at least perfect fit is possible: 00561 * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ 00562 00563 if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { 00564 /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing 00565 * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') 00566 * -> split large block, create empty remainder, 00567 * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if 00568 * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, 00569 * struct mem would fit in but no data between mem2 and mem2->next 00570 * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty 00571 * region that couldn't hold data, but when mem->next gets freed, 00572 * the 2 regions would be combined, resulting in more free memory 00573 */ 00574 ptr2 = ptr + SIZEOF_STRUCT_MEM + size; 00575 /* create mem2 struct */ 00576 mem2 = (struct mem *)(void *)&ram[ptr2]; 00577 mem2->used = 0; 00578 mem2->next = mem->next; 00579 mem2->prev = ptr; 00580 /* and insert it between mem and mem->next */ 00581 mem->next = ptr2; 00582 mem->used = 1; 00583 00584 if (mem2->next != MEM_SIZE_ALIGNED) { 00585 ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; 00586 } 00587 MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); 00588 } else { 00589 /* (a mem2 struct does no fit into the user data space of mem and mem->next will always 00590 * be used at this point: if not we have 2 unused structs in a row, plug_holes should have 00591 * take care of this). 00592 * -> near fit or excact fit: do not split, no mem2 creation 00593 * also can't move mem->next directly behind mem, since mem->next 00594 * will always be used at this point! 00595 */ 00596 mem->used = 1; 00597 MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram)); 00598 } 00599 00600 if (mem == lfree) { 00601 /* Find next free block after mem and update lowest free pointer */ 00602 while (lfree->used && lfree != ram_end) { 00603 LWIP_MEM_ALLOC_UNPROTECT(); 00604 /* prevent high interrupt latency... */ 00605 LWIP_MEM_ALLOC_PROTECT(); 00606 lfree = (struct mem *)(void *)&ram[lfree->next]; 00607 } 00608 LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); 00609 } 00610 LWIP_MEM_ALLOC_UNPROTECT(); 00611 sys_mutex_unlock(&mem_mutex); 00612 LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", 00613 (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); 00614 LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", 00615 ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); 00616 LWIP_ASSERT("mem_malloc: sanity check alignment", 00617 (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); 00618 00619 return (u8_t *)mem + SIZEOF_STRUCT_MEM; 00620 } 00621 } 00622 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00623 /* if we got interrupted by a mem_free, try again */ 00624 } while(local_mem_free_count != 0); 00625 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00626 LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); 00627 MEM_STATS_INC(err); 00628 LWIP_MEM_ALLOC_UNPROTECT(); 00629 sys_mutex_unlock(&mem_mutex); 00630 return NULL; 00631 } 00632 00633 #endif /* MEM_USE_POOLS */ 00634 /** 00635 * Contiguously allocates enough space for count objects that are size bytes 00636 * of memory each and returns a pointer to the allocated memory. 00637 * 00638 * The allocated memory is filled with bytes of value zero. 00639 * 00640 * @param count number of objects to allocate 00641 * @param size size of the objects to allocate 00642 * @return pointer to allocated memory / NULL pointer if there is an error 00643 */ 00644 void *mem_calloc(mem_size_t count, mem_size_t size) 00645 { 00646 void *p; 00647 00648 /* allocate 'count' objects of size 'size' */ 00649 p = mem_malloc(count * size); 00650 if (p) { 00651 /* zero the memory */ 00652 memset(p, 0, count * size); 00653 } 00654 return p; 00655 } 00656 00657 #endif /* !MEM_LIBC_MALLOC */
Generated on Tue Jul 12 2022 17:34:49 by
