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.
Fork of mbed-os by
lwip_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 #include "lwip/def.h" 00058 #include "lwip/mem.h" 00059 #include "lwip/sys.h" 00060 #include "lwip/stats.h" 00061 #include "lwip/err.h" 00062 00063 #include <string.h> 00064 00065 #if MEM_LIBC_MALLOC || MEM_USE_POOLS 00066 /** mem_init is not used when using pools instead of a heap or using 00067 * C library malloc(). 00068 */ 00069 void 00070 mem_init(void) 00071 { 00072 } 00073 00074 /** mem_trim is not used when using pools instead of a heap or using 00075 * C library malloc(): we can't free part of a pool element and the stack 00076 * support mem_trim() to return a different pointer 00077 */ 00078 void* 00079 mem_trim(void *mem, mem_size_t size) 00080 { 00081 LWIP_UNUSED_ARG(size); 00082 return mem; 00083 } 00084 #endif /* MEM_LIBC_MALLOC || MEM_USE_POOLS */ 00085 00086 #if MEM_LIBC_MALLOC 00087 /* lwIP heap implemented using C library malloc() */ 00088 00089 /* in case C library malloc() needs extra protection, 00090 * allow these defines to be overridden. 00091 */ 00092 #ifndef mem_clib_free 00093 #define mem_clib_free free 00094 #endif 00095 #ifndef mem_clib_malloc 00096 #define mem_clib_malloc malloc 00097 #endif 00098 #ifndef mem_clib_calloc 00099 #define mem_clib_calloc calloc 00100 #endif 00101 00102 #if LWIP_STATS && MEM_STATS 00103 #define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t)) 00104 #else 00105 #define MEM_LIBC_STATSHELPER_SIZE 0 00106 #endif 00107 00108 /** 00109 * Allocate a block of memory with a minimum of 'size' bytes. 00110 * 00111 * @param size is the minimum size of the requested block in bytes. 00112 * @return pointer to allocated memory or NULL if no free memory was found. 00113 * 00114 * Note that the returned value must always be aligned (as defined by MEM_ALIGNMENT). 00115 */ 00116 void * 00117 mem_malloc(mem_size_t size) 00118 { 00119 void* ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE); 00120 if (ret == NULL) { 00121 MEM_STATS_INC(err); 00122 } else { 00123 LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret); 00124 #if LWIP_STATS && MEM_STATS 00125 *(mem_size_t*)ret = size; 00126 ret = (u8_t*)ret + MEM_LIBC_STATSHELPER_SIZE; 00127 MEM_STATS_INC_USED(used, size); 00128 #endif 00129 } 00130 return ret; 00131 } 00132 00133 /** Put memory back on the heap 00134 * 00135 * @param rmem is the pointer as returned by a previous call to mem_malloc() 00136 */ 00137 void 00138 mem_free(void *rmem) 00139 { 00140 LWIP_ASSERT("rmem != NULL", (rmem != NULL)); 00141 LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); 00142 #if LWIP_STATS && MEM_STATS 00143 rmem = (u8_t*)rmem - MEM_LIBC_STATSHELPER_SIZE; 00144 MEM_STATS_DEC_USED(used, *(mem_size_t*)rmem); 00145 #endif 00146 mem_clib_free(rmem); 00147 } 00148 00149 #elif MEM_USE_POOLS 00150 00151 /* lwIP heap implemented with different sized pools */ 00152 00153 /** 00154 * Allocate memory: determine the smallest pool that is big enough 00155 * to contain an element of 'size' and get an element from that pool. 00156 * 00157 * @param size the size in bytes of the memory needed 00158 * @return a pointer to the allocated memory or NULL if the pool is empty 00159 */ 00160 void * 00161 mem_malloc(mem_size_t size) 00162 { 00163 void *ret; 00164 struct memp_malloc_helper *element; 00165 memp_t poolnr; 00166 mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); 00167 00168 for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { 00169 #if MEM_USE_POOLS_TRY_BIGGER_POOL 00170 again: 00171 #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ 00172 /* is this pool big enough to hold an element of the required size 00173 plus a struct memp_malloc_helper that saves the pool this element came from? */ 00174 if (required_size <= memp_pools[poolnr]->size) { 00175 break; 00176 } 00177 } 00178 if (poolnr > MEMP_POOL_LAST) { 00179 LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); 00180 MEM_STATS_INC(err); 00181 return NULL; 00182 } 00183 element = (struct memp_malloc_helper*)memp_malloc(poolnr); 00184 if (element == NULL) { 00185 /* No need to DEBUGF or ASSERT: This error is already 00186 taken care of in memp.c */ 00187 #if MEM_USE_POOLS_TRY_BIGGER_POOL 00188 /** Try a bigger pool if this one is empty! */ 00189 if (poolnr < MEMP_POOL_LAST) { 00190 poolnr++; 00191 goto again; 00192 } 00193 #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ 00194 MEM_STATS_INC(err); 00195 return NULL; 00196 } 00197 00198 /* save the pool number this element came from */ 00199 element->poolnr = poolnr; 00200 /* and return a pointer to the memory directly after the struct memp_malloc_helper */ 00201 ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); 00202 00203 #if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) 00204 /* truncating to u16_t is safe because struct memp_desc::size is u16_t */ 00205 element->size = (u16_t)size; 00206 MEM_STATS_INC_USED(used, element->size); 00207 #endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */ 00208 #if MEMP_OVERFLOW_CHECK 00209 /* initialize unused memory (diff between requested size and selected pool's size) */ 00210 memset((u8_t*)ret + size, 0xcd, memp_pools[poolnr]->size - size); 00211 #endif /* MEMP_OVERFLOW_CHECK */ 00212 return ret; 00213 } 00214 00215 /** 00216 * Free memory previously allocated by mem_malloc. Loads the pool number 00217 * and calls memp_free with that pool number to put the element back into 00218 * its pool 00219 * 00220 * @param rmem the memory element to free 00221 */ 00222 void 00223 mem_free(void *rmem) 00224 { 00225 struct memp_malloc_helper *hmem; 00226 00227 LWIP_ASSERT("rmem != NULL", (rmem != NULL)); 00228 LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); 00229 00230 /* get the original struct memp_malloc_helper */ 00231 /* cast through void* to get rid of alignment warnings */ 00232 hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))); 00233 00234 LWIP_ASSERT("hmem != NULL", (hmem != NULL)); 00235 LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); 00236 LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); 00237 00238 MEM_STATS_DEC_USED(used, hmem->size); 00239 #if MEMP_OVERFLOW_CHECK 00240 { 00241 u16_t i; 00242 LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size", 00243 hmem->size <= memp_pools[hmem->poolnr]->size); 00244 /* check that unused memory remained untouched (diff between requested size and selected pool's size) */ 00245 for (i = hmem->size; i < memp_pools[hmem->poolnr]->size; i++) { 00246 u8_t data = *((u8_t*)rmem + i); 00247 LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd); 00248 } 00249 } 00250 #endif /* MEMP_OVERFLOW_CHECK */ 00251 00252 /* and put it in the pool we saved earlier */ 00253 memp_free(hmem->poolnr, hmem); 00254 } 00255 00256 #else /* MEM_USE_POOLS */ 00257 /* lwIP replacement for your libc malloc() */ 00258 00259 /** 00260 * The heap is made up as a list of structs of this type. 00261 * This does not have to be aligned since for getting its size, 00262 * we only use the macro SIZEOF_STRUCT_MEM, which automatically aligns. 00263 */ 00264 struct mem { 00265 /** index (-> ram[next]) of the next struct */ 00266 mem_size_t next; 00267 /** index (-> ram[prev]) of the previous struct */ 00268 mem_size_t prev; 00269 /** 1: this area is used; 0: this area is unused */ 00270 u8_t used; 00271 }; 00272 00273 /** All allocated blocks will be MIN_SIZE bytes big, at least! 00274 * MIN_SIZE can be overridden to suit your needs. Smaller values save space, 00275 * larger values could prevent too small blocks to fragment the RAM too much. */ 00276 #ifndef MIN_SIZE 00277 #define MIN_SIZE 12 00278 #endif /* MIN_SIZE */ 00279 /* some alignment macros: we define them here for better source code layout */ 00280 #define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) 00281 #define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) 00282 #define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) 00283 00284 /** If you want to relocate the heap to external memory, simply define 00285 * LWIP_RAM_HEAP_POINTER as a void-pointer to that location. 00286 * If so, make sure the memory at that location is big enough (see below on 00287 * how that space is calculated). */ 00288 #ifndef LWIP_RAM_HEAP_POINTER 00289 /** the heap. we need one struct mem at the end and some room for alignment */ 00290 LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U*SIZEOF_STRUCT_MEM)); 00291 #define LWIP_RAM_HEAP_POINTER ram_heap 00292 #endif /* LWIP_RAM_HEAP_POINTER */ 00293 00294 /** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ 00295 static u8_t *ram; 00296 /** the last entry, always unused! */ 00297 static struct mem *ram_end; 00298 /** pointer to the lowest free block, this is used for faster search */ 00299 static struct mem *lfree; 00300 00301 /** concurrent access protection */ 00302 #if !NO_SYS 00303 static sys_mutex_t mem_mutex; 00304 #endif 00305 00306 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00307 00308 static volatile u8_t mem_free_count; 00309 00310 /* Allow mem_free from other (e.g. interrupt) context */ 00311 #define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) 00312 #define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) 00313 #define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) 00314 #define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) 00315 #define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) 00316 #define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) 00317 00318 #else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00319 00320 /* Protect the heap only by using a semaphore */ 00321 #define LWIP_MEM_FREE_DECL_PROTECT() 00322 #define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) 00323 #define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) 00324 /* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ 00325 #define LWIP_MEM_ALLOC_DECL_PROTECT() 00326 #define LWIP_MEM_ALLOC_PROTECT() 00327 #define LWIP_MEM_ALLOC_UNPROTECT() 00328 00329 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00330 00331 00332 /** 00333 * "Plug holes" by combining adjacent empty struct mems. 00334 * After this function is through, there should not exist 00335 * one empty struct mem pointing to another empty struct mem. 00336 * 00337 * @param mem this points to a struct mem which just has been freed 00338 * @internal this function is only called by mem_free() and mem_trim() 00339 * 00340 * This assumes access to the heap is protected by the calling function 00341 * already. 00342 */ 00343 static void 00344 plug_holes(struct mem *mem) 00345 { 00346 struct mem *nmem; 00347 struct mem *pmem; 00348 00349 LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); 00350 LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); 00351 LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); 00352 00353 /* plug hole forward */ 00354 LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); 00355 00356 nmem = (struct mem *)(void *)&ram[mem->next]; 00357 if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { 00358 /* if mem->next is unused and not end of ram, combine mem and mem->next */ 00359 if (lfree == nmem) { 00360 lfree = mem; 00361 } 00362 mem->next = nmem->next; 00363 ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram); 00364 } 00365 00366 /* plug hole backward */ 00367 pmem = (struct mem *)(void *)&ram[mem->prev]; 00368 if (pmem != mem && pmem->used == 0) { 00369 /* if mem->prev is unused, combine mem and mem->prev */ 00370 if (lfree == mem) { 00371 lfree = pmem; 00372 } 00373 pmem->next = mem->next; 00374 ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram); 00375 } 00376 } 00377 00378 /** 00379 * Zero the heap and initialize start, end and lowest-free 00380 */ 00381 void 00382 mem_init(void) 00383 { 00384 struct mem *mem; 00385 00386 LWIP_ASSERT("Sanity check alignment", 00387 (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); 00388 00389 /* align the heap */ 00390 ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); 00391 /* initialize the start of the heap */ 00392 mem = (struct mem *)(void *)ram; 00393 mem->next = MEM_SIZE_ALIGNED; 00394 mem->prev = 0; 00395 mem->used = 0; 00396 /* initialize the end of the heap */ 00397 ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; 00398 ram_end->used = 1; 00399 ram_end->next = MEM_SIZE_ALIGNED; 00400 ram_end->prev = MEM_SIZE_ALIGNED; 00401 00402 /* initialize the lowest-free pointer to the start of the heap */ 00403 lfree = (struct mem *)(void *)ram; 00404 00405 MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); 00406 00407 if (sys_mutex_new(&mem_mutex) != ERR_OK) { 00408 LWIP_ASSERT("failed to create mem_mutex", 0); 00409 } 00410 } 00411 00412 /** 00413 * Put a struct mem back on the heap 00414 * 00415 * @param rmem is the data portion of a struct mem as returned by a previous 00416 * call to mem_malloc() 00417 */ 00418 void 00419 mem_free(void *rmem) 00420 { 00421 struct mem *mem; 00422 LWIP_MEM_FREE_DECL_PROTECT(); 00423 00424 if (rmem == NULL) { 00425 LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); 00426 return; 00427 } 00428 LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); 00429 00430 LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && 00431 (u8_t *)rmem < (u8_t *)ram_end); 00432 00433 if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { 00434 SYS_ARCH_DECL_PROTECT(lev); 00435 LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); 00436 /* protect mem stats from concurrent access */ 00437 SYS_ARCH_PROTECT(lev); 00438 MEM_STATS_INC(illegal); 00439 SYS_ARCH_UNPROTECT(lev); 00440 return; 00441 } 00442 /* protect the heap from concurrent access */ 00443 LWIP_MEM_FREE_PROTECT(); 00444 /* Get the corresponding struct mem ... */ 00445 /* cast through void* to get rid of alignment warnings */ 00446 mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); 00447 /* ... which has to be in a used state ... */ 00448 LWIP_ASSERT("mem_free: mem->used", mem->used); 00449 /* ... and is now unused. */ 00450 mem->used = 0; 00451 00452 if (mem < lfree) { 00453 /* the newly freed struct is now the lowest */ 00454 lfree = mem; 00455 } 00456 00457 MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); 00458 00459 /* finally, see if prev or next are free also */ 00460 plug_holes(mem); 00461 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00462 mem_free_count = 1; 00463 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00464 LWIP_MEM_FREE_UNPROTECT(); 00465 } 00466 00467 /** 00468 * Shrink memory returned by mem_malloc(). 00469 * 00470 * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked 00471 * @param newsize required size after shrinking (needs to be smaller than or 00472 * equal to the previous size) 00473 * @return for compatibility reasons: is always == rmem, at the moment 00474 * or NULL if newsize is > old size, in which case rmem is NOT touched 00475 * or freed! 00476 */ 00477 void * 00478 mem_trim(void *rmem, mem_size_t newsize) 00479 { 00480 mem_size_t size; 00481 mem_size_t ptr, ptr2; 00482 struct mem *mem, *mem2; 00483 /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ 00484 LWIP_MEM_FREE_DECL_PROTECT(); 00485 00486 /* Expand the size of the allocated memory region so that we can 00487 adjust for alignment. */ 00488 newsize = LWIP_MEM_ALIGN_SIZE(newsize); 00489 00490 if (newsize < MIN_SIZE_ALIGNED) { 00491 /* every data block must be at least MIN_SIZE_ALIGNED long */ 00492 newsize = MIN_SIZE_ALIGNED; 00493 } 00494 00495 if (newsize > MEM_SIZE_ALIGNED) { 00496 return NULL; 00497 } 00498 00499 LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && 00500 (u8_t *)rmem < (u8_t *)ram_end); 00501 00502 if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { 00503 SYS_ARCH_DECL_PROTECT(lev); 00504 LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); 00505 /* protect mem stats from concurrent access */ 00506 SYS_ARCH_PROTECT(lev); 00507 MEM_STATS_INC(illegal); 00508 SYS_ARCH_UNPROTECT(lev); 00509 return rmem; 00510 } 00511 /* Get the corresponding struct mem ... */ 00512 /* cast through void* to get rid of alignment warnings */ 00513 mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); 00514 /* ... and its offset pointer */ 00515 ptr = (mem_size_t)((u8_t *)mem - ram); 00516 00517 size = mem->next - ptr - SIZEOF_STRUCT_MEM; 00518 LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); 00519 if (newsize > size) { 00520 /* not supported */ 00521 return NULL; 00522 } 00523 if (newsize == size) { 00524 /* No change in size, simply return */ 00525 return rmem; 00526 } 00527 00528 /* protect the heap from concurrent access */ 00529 LWIP_MEM_FREE_PROTECT(); 00530 00531 mem2 = (struct mem *)(void *)&ram[mem->next]; 00532 if (mem2->used == 0) { 00533 /* The next struct is unused, we can simply move it at little */ 00534 mem_size_t next; 00535 /* remember the old next pointer */ 00536 next = mem2->next; 00537 /* create new struct mem which is moved directly after the shrinked mem */ 00538 ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; 00539 if (lfree == mem2) { 00540 lfree = (struct mem *)(void *)&ram[ptr2]; 00541 } 00542 mem2 = (struct mem *)(void *)&ram[ptr2]; 00543 mem2->used = 0; 00544 /* restore the next pointer */ 00545 mem2->next = next; 00546 /* link it back to mem */ 00547 mem2->prev = ptr; 00548 /* link mem to it */ 00549 mem->next = ptr2; 00550 /* last thing to restore linked list: as we have moved mem2, 00551 * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not 00552 * the end of the heap */ 00553 if (mem2->next != MEM_SIZE_ALIGNED) { 00554 ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; 00555 } 00556 MEM_STATS_DEC_USED(used, (size - newsize)); 00557 /* no need to plug holes, we've already done that */ 00558 } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { 00559 /* Next struct is used but there's room for another struct mem with 00560 * at least MIN_SIZE_ALIGNED of data. 00561 * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem 00562 * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). 00563 * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty 00564 * region that couldn't hold data, but when mem->next gets freed, 00565 * the 2 regions would be combined, resulting in more free memory */ 00566 ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; 00567 mem2 = (struct mem *)(void *)&ram[ptr2]; 00568 if (mem2 < lfree) { 00569 lfree = mem2; 00570 } 00571 mem2->used = 0; 00572 mem2->next = mem->next; 00573 mem2->prev = ptr; 00574 mem->next = ptr2; 00575 if (mem2->next != MEM_SIZE_ALIGNED) { 00576 ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; 00577 } 00578 MEM_STATS_DEC_USED(used, (size - newsize)); 00579 /* the original mem->next is used, so no need to plug holes! */ 00580 } 00581 /* else { 00582 next struct mem is used but size between mem and mem2 is not big enough 00583 to create another struct mem 00584 -> don't do anyhting. 00585 -> the remaining space stays unused since it is too small 00586 } */ 00587 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00588 mem_free_count = 1; 00589 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00590 LWIP_MEM_FREE_UNPROTECT(); 00591 return rmem; 00592 } 00593 00594 /** 00595 * Allocate a block of memory with a minimum of 'size' bytes. 00596 * 00597 * @param size is the minimum size of the requested block in bytes. 00598 * @return pointer to allocated memory or NULL if no free memory was found. 00599 * 00600 * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). 00601 */ 00602 void * 00603 mem_malloc(mem_size_t size) 00604 { 00605 mem_size_t ptr, ptr2; 00606 struct mem *mem, *mem2; 00607 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00608 u8_t local_mem_free_count = 0; 00609 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00610 LWIP_MEM_ALLOC_DECL_PROTECT(); 00611 00612 if (size == 0) { 00613 return NULL; 00614 } 00615 00616 /* Expand the size of the allocated memory region so that we can 00617 adjust for alignment. */ 00618 size = LWIP_MEM_ALIGN_SIZE(size); 00619 00620 if (size < MIN_SIZE_ALIGNED) { 00621 /* every data block must be at least MIN_SIZE_ALIGNED long */ 00622 size = MIN_SIZE_ALIGNED; 00623 } 00624 00625 if (size > MEM_SIZE_ALIGNED) { 00626 return NULL; 00627 } 00628 00629 /* protect the heap from concurrent access */ 00630 sys_mutex_lock(&mem_mutex); 00631 LWIP_MEM_ALLOC_PROTECT(); 00632 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00633 /* run as long as a mem_free disturbed mem_malloc or mem_trim */ 00634 do { 00635 local_mem_free_count = 0; 00636 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00637 00638 /* Scan through the heap searching for a free block that is big enough, 00639 * beginning with the lowest free block. 00640 */ 00641 for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size; 00642 ptr = ((struct mem *)(void *)&ram[ptr])->next) { 00643 mem = (struct mem *)(void *)&ram[ptr]; 00644 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00645 mem_free_count = 0; 00646 LWIP_MEM_ALLOC_UNPROTECT(); 00647 /* allow mem_free or mem_trim to run */ 00648 LWIP_MEM_ALLOC_PROTECT(); 00649 if (mem_free_count != 0) { 00650 /* If mem_free or mem_trim have run, we have to restart since they 00651 could have altered our current struct mem. */ 00652 local_mem_free_count = 1; 00653 break; 00654 } 00655 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00656 00657 if ((!mem->used) && 00658 (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { 00659 /* mem is not used and at least perfect fit is possible: 00660 * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ 00661 00662 if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { 00663 /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing 00664 * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') 00665 * -> split large block, create empty remainder, 00666 * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if 00667 * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, 00668 * struct mem would fit in but no data between mem2 and mem2->next 00669 * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty 00670 * region that couldn't hold data, but when mem->next gets freed, 00671 * the 2 regions would be combined, resulting in more free memory 00672 */ 00673 ptr2 = ptr + SIZEOF_STRUCT_MEM + size; 00674 /* create mem2 struct */ 00675 mem2 = (struct mem *)(void *)&ram[ptr2]; 00676 mem2->used = 0; 00677 mem2->next = mem->next; 00678 mem2->prev = ptr; 00679 /* and insert it between mem and mem->next */ 00680 mem->next = ptr2; 00681 mem->used = 1; 00682 00683 if (mem2->next != MEM_SIZE_ALIGNED) { 00684 ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; 00685 } 00686 MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); 00687 } else { 00688 /* (a mem2 struct does no fit into the user data space of mem and mem->next will always 00689 * be used at this point: if not we have 2 unused structs in a row, plug_holes should have 00690 * take care of this). 00691 * -> near fit or exact fit: do not split, no mem2 creation 00692 * also can't move mem->next directly behind mem, since mem->next 00693 * will always be used at this point! 00694 */ 00695 mem->used = 1; 00696 MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram)); 00697 } 00698 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00699 mem_malloc_adjust_lfree: 00700 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00701 if (mem == lfree) { 00702 struct mem *cur = lfree; 00703 /* Find next free block after mem and update lowest free pointer */ 00704 while (cur->used && cur != ram_end) { 00705 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00706 mem_free_count = 0; 00707 LWIP_MEM_ALLOC_UNPROTECT(); 00708 /* prevent high interrupt latency... */ 00709 LWIP_MEM_ALLOC_PROTECT(); 00710 if (mem_free_count != 0) { 00711 /* If mem_free or mem_trim have run, we have to restart since they 00712 could have altered our current struct mem or lfree. */ 00713 goto mem_malloc_adjust_lfree; 00714 } 00715 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00716 cur = (struct mem *)(void *)&ram[cur->next]; 00717 } 00718 lfree = cur; 00719 LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); 00720 } 00721 LWIP_MEM_ALLOC_UNPROTECT(); 00722 sys_mutex_unlock(&mem_mutex); 00723 LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", 00724 (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); 00725 LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", 00726 ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); 00727 LWIP_ASSERT("mem_malloc: sanity check alignment", 00728 (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); 00729 00730 return (u8_t *)mem + SIZEOF_STRUCT_MEM; 00731 } 00732 } 00733 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 00734 /* if we got interrupted by a mem_free, try again */ 00735 } while (local_mem_free_count != 0); 00736 #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 00737 LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); 00738 MEM_STATS_INC(err); 00739 LWIP_MEM_ALLOC_UNPROTECT(); 00740 sys_mutex_unlock(&mem_mutex); 00741 return NULL; 00742 } 00743 00744 #endif /* MEM_USE_POOLS */ 00745 00746 #if MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) 00747 void * 00748 mem_calloc(mem_size_t count, mem_size_t size) 00749 { 00750 return mem_clib_calloc(count, size); 00751 } 00752 00753 #else /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ 00754 /** 00755 * Contiguously allocates enough space for count objects that are size bytes 00756 * of memory each and returns a pointer to the allocated memory. 00757 * 00758 * The allocated memory is filled with bytes of value zero. 00759 * 00760 * @param count number of objects to allocate 00761 * @param size size of the objects to allocate 00762 * @return pointer to allocated memory / NULL pointer if there is an error 00763 */ 00764 void * 00765 mem_calloc(mem_size_t count, mem_size_t size) 00766 { 00767 void *p; 00768 00769 /* allocate 'count' objects of size 'size' */ 00770 p = mem_malloc(count * size); 00771 if (p) { 00772 /* zero the memory */ 00773 memset(p, 0, (size_t)count * (size_t)size); 00774 } 00775 return p; 00776 } 00777 #endif /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */
Generated on Tue Jul 12 2022 13:15:53 by
