1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * Dynamic memory manager 4195972f6Sopenharmony_ci * 5195972f6Sopenharmony_ci * This is a lightweight replacement for the standard C library malloc(). 6195972f6Sopenharmony_ci * 7195972f6Sopenharmony_ci * If you want to use the standard C library malloc() instead, define 8195972f6Sopenharmony_ci * MEM_LIBC_MALLOC to 1 in your lwipopts.h 9195972f6Sopenharmony_ci * 10195972f6Sopenharmony_ci * To let mem_malloc() use pools (prevents fragmentation and is much faster than 11195972f6Sopenharmony_ci * a heap but might waste some memory), define MEM_USE_POOLS to 1, define 12195972f6Sopenharmony_ci * MEMP_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list 13195972f6Sopenharmony_ci * of pools like this (more pools can be added between _START and _END): 14195972f6Sopenharmony_ci * 15195972f6Sopenharmony_ci * Define three pools with sizes 256, 512, and 1512 bytes 16195972f6Sopenharmony_ci * LWIP_MALLOC_MEMPOOL_START 17195972f6Sopenharmony_ci * LWIP_MALLOC_MEMPOOL(20, 256) 18195972f6Sopenharmony_ci * LWIP_MALLOC_MEMPOOL(10, 512) 19195972f6Sopenharmony_ci * LWIP_MALLOC_MEMPOOL(5, 1512) 20195972f6Sopenharmony_ci * LWIP_MALLOC_MEMPOOL_END 21195972f6Sopenharmony_ci */ 22195972f6Sopenharmony_ci 23195972f6Sopenharmony_ci/* 24195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 25195972f6Sopenharmony_ci * All rights reserved. 26195972f6Sopenharmony_ci * 27195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 28195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 29195972f6Sopenharmony_ci * 30195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 31195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 32195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 33195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 34195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 35195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 36195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 37195972f6Sopenharmony_ci * 38195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 39195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 41195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 42195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 43195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 44195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 45195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 46195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 47195972f6Sopenharmony_ci * OF SUCH DAMAGE. 48195972f6Sopenharmony_ci * 49195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 50195972f6Sopenharmony_ci * 51195972f6Sopenharmony_ci * Author: Adam Dunkels <adam@sics.se> 52195972f6Sopenharmony_ci * Simon Goldschmidt 53195972f6Sopenharmony_ci * 54195972f6Sopenharmony_ci */ 55195972f6Sopenharmony_ci 56195972f6Sopenharmony_ci#include "lwip/opt.h" 57195972f6Sopenharmony_ci#include "lwip/mem.h" 58195972f6Sopenharmony_ci#include "lwip/def.h" 59195972f6Sopenharmony_ci#include "lwip/sys.h" 60195972f6Sopenharmony_ci#include "lwip/stats.h" 61195972f6Sopenharmony_ci#include "lwip/err.h" 62195972f6Sopenharmony_ci 63195972f6Sopenharmony_ci#include <string.h> 64195972f6Sopenharmony_ci 65195972f6Sopenharmony_ci#if MEM_LIBC_MALLOC 66195972f6Sopenharmony_ci#include <stdlib.h> /* for malloc()/free() */ 67195972f6Sopenharmony_ci#endif 68195972f6Sopenharmony_ci 69195972f6Sopenharmony_ci/* This is overridable for tests only... */ 70195972f6Sopenharmony_ci#ifndef LWIP_MEM_ILLEGAL_FREE 71195972f6Sopenharmony_ci#define LWIP_MEM_ILLEGAL_FREE(msg) LWIP_ASSERT(msg, 0) 72195972f6Sopenharmony_ci#endif 73195972f6Sopenharmony_ci 74195972f6Sopenharmony_ci#define MEM_STATS_INC_LOCKED(x) SYS_ARCH_LOCKED(MEM_STATS_INC(x)) 75195972f6Sopenharmony_ci#define MEM_STATS_INC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_INC_USED(x, y)) 76195972f6Sopenharmony_ci#define MEM_STATS_DEC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_DEC_USED(x, y)) 77195972f6Sopenharmony_ci 78195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK 79195972f6Sopenharmony_ci#define MEM_SANITY_OFFSET MEM_SANITY_REGION_BEFORE_ALIGNED 80195972f6Sopenharmony_ci#define MEM_SANITY_OVERHEAD (MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED) 81195972f6Sopenharmony_ci#else 82195972f6Sopenharmony_ci#define MEM_SANITY_OFFSET 0 83195972f6Sopenharmony_ci#define MEM_SANITY_OVERHEAD 0 84195972f6Sopenharmony_ci#endif 85195972f6Sopenharmony_ci 86195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK 87195972f6Sopenharmony_ci/** 88195972f6Sopenharmony_ci * Check if a mep element was victim of an overflow or underflow 89195972f6Sopenharmony_ci * (e.g. the restricted area after/before it has been altered) 90195972f6Sopenharmony_ci * 91195972f6Sopenharmony_ci * @param p the mem element to check 92195972f6Sopenharmony_ci * @param size allocated size of the element 93195972f6Sopenharmony_ci * @param descr1 description of the element source shown on error 94195972f6Sopenharmony_ci * @param descr2 description of the element source shown on error 95195972f6Sopenharmony_ci */ 96195972f6Sopenharmony_civoid 97195972f6Sopenharmony_cimem_overflow_check_raw(void *p, size_t size, const char *descr1, const char *descr2) 98195972f6Sopenharmony_ci{ 99195972f6Sopenharmony_ci#if MEM_SANITY_REGION_AFTER_ALIGNED || MEM_SANITY_REGION_BEFORE_ALIGNED 100195972f6Sopenharmony_ci u16_t k; 101195972f6Sopenharmony_ci u8_t *m; 102195972f6Sopenharmony_ci 103195972f6Sopenharmony_ci#if MEM_SANITY_REGION_AFTER_ALIGNED > 0 104195972f6Sopenharmony_ci m = (u8_t *)p + size; 105195972f6Sopenharmony_ci for (k = 0; k < MEM_SANITY_REGION_AFTER_ALIGNED; k++) { 106195972f6Sopenharmony_ci if (m[k] != 0xcd) { 107195972f6Sopenharmony_ci char errstr[128]; 108195972f6Sopenharmony_ci snprintf(errstr, sizeof(errstr), "detected mem overflow in %s%s", descr1, descr2); 109195972f6Sopenharmony_ci LWIP_ASSERT(errstr, 0); 110195972f6Sopenharmony_ci } 111195972f6Sopenharmony_ci } 112195972f6Sopenharmony_ci#endif /* MEM_SANITY_REGION_AFTER_ALIGNED > 0 */ 113195972f6Sopenharmony_ci 114195972f6Sopenharmony_ci#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 115195972f6Sopenharmony_ci m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED; 116195972f6Sopenharmony_ci for (k = 0; k < MEM_SANITY_REGION_BEFORE_ALIGNED; k++) { 117195972f6Sopenharmony_ci if (m[k] != 0xcd) { 118195972f6Sopenharmony_ci char errstr[128]; 119195972f6Sopenharmony_ci snprintf(errstr, sizeof(errstr), "detected mem underflow in %s%s", descr1, descr2); 120195972f6Sopenharmony_ci LWIP_ASSERT(errstr, 0); 121195972f6Sopenharmony_ci } 122195972f6Sopenharmony_ci } 123195972f6Sopenharmony_ci#endif /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 */ 124195972f6Sopenharmony_ci#else 125195972f6Sopenharmony_ci LWIP_UNUSED_ARG(p); 126195972f6Sopenharmony_ci LWIP_UNUSED_ARG(desc); 127195972f6Sopenharmony_ci LWIP_UNUSED_ARG(descr); 128195972f6Sopenharmony_ci#endif 129195972f6Sopenharmony_ci} 130195972f6Sopenharmony_ci 131195972f6Sopenharmony_ci/** 132195972f6Sopenharmony_ci * Initialize the restricted area of a mem element. 133195972f6Sopenharmony_ci */ 134195972f6Sopenharmony_civoid 135195972f6Sopenharmony_cimem_overflow_init_raw(void *p, size_t size) 136195972f6Sopenharmony_ci{ 137195972f6Sopenharmony_ci#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 138195972f6Sopenharmony_ci u8_t *m; 139195972f6Sopenharmony_ci#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 140195972f6Sopenharmony_ci m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED; 141195972f6Sopenharmony_ci memset(m, 0xcd, MEM_SANITY_REGION_BEFORE_ALIGNED); 142195972f6Sopenharmony_ci#endif 143195972f6Sopenharmony_ci#if MEM_SANITY_REGION_AFTER_ALIGNED > 0 144195972f6Sopenharmony_ci m = (u8_t *)p + size; 145195972f6Sopenharmony_ci memset(m, 0xcd, MEM_SANITY_REGION_AFTER_ALIGNED); 146195972f6Sopenharmony_ci#endif 147195972f6Sopenharmony_ci#else /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 */ 148195972f6Sopenharmony_ci LWIP_UNUSED_ARG(p); 149195972f6Sopenharmony_ci LWIP_UNUSED_ARG(desc); 150195972f6Sopenharmony_ci#endif /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 */ 151195972f6Sopenharmony_ci} 152195972f6Sopenharmony_ci#endif /* MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK */ 153195972f6Sopenharmony_ci 154195972f6Sopenharmony_ci#if MEM_LIBC_MALLOC || MEM_USE_POOLS 155195972f6Sopenharmony_ci 156195972f6Sopenharmony_ci/** mem_init is not used when using pools instead of a heap or using 157195972f6Sopenharmony_ci * C library malloc(). 158195972f6Sopenharmony_ci */ 159195972f6Sopenharmony_civoid 160195972f6Sopenharmony_cimem_init(void) 161195972f6Sopenharmony_ci{ 162195972f6Sopenharmony_ci} 163195972f6Sopenharmony_ci 164195972f6Sopenharmony_ci/** mem_trim is not used when using pools instead of a heap or using 165195972f6Sopenharmony_ci * C library malloc(): we can't free part of a pool element and the stack 166195972f6Sopenharmony_ci * support mem_trim() to return a different pointer 167195972f6Sopenharmony_ci */ 168195972f6Sopenharmony_civoid * 169195972f6Sopenharmony_cimem_trim(void *mem, mem_size_t size) 170195972f6Sopenharmony_ci{ 171195972f6Sopenharmony_ci LWIP_UNUSED_ARG(size); 172195972f6Sopenharmony_ci return mem; 173195972f6Sopenharmony_ci} 174195972f6Sopenharmony_ci#endif /* MEM_LIBC_MALLOC || MEM_USE_POOLS */ 175195972f6Sopenharmony_ci 176195972f6Sopenharmony_ci#if MEM_LIBC_MALLOC 177195972f6Sopenharmony_ci/* lwIP heap implemented using C library malloc() */ 178195972f6Sopenharmony_ci 179195972f6Sopenharmony_ci/* in case C library malloc() needs extra protection, 180195972f6Sopenharmony_ci * allow these defines to be overridden. 181195972f6Sopenharmony_ci */ 182195972f6Sopenharmony_ci#ifndef mem_clib_free 183195972f6Sopenharmony_ci#define mem_clib_free free 184195972f6Sopenharmony_ci#endif 185195972f6Sopenharmony_ci#ifndef mem_clib_malloc 186195972f6Sopenharmony_ci#define mem_clib_malloc malloc 187195972f6Sopenharmony_ci#endif 188195972f6Sopenharmony_ci#ifndef mem_clib_calloc 189195972f6Sopenharmony_ci#define mem_clib_calloc calloc 190195972f6Sopenharmony_ci#endif 191195972f6Sopenharmony_ci 192195972f6Sopenharmony_ci#if LWIP_STATS && MEM_STATS 193195972f6Sopenharmony_ci#define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t)) 194195972f6Sopenharmony_ci#else 195195972f6Sopenharmony_ci#define MEM_LIBC_STATSHELPER_SIZE 0 196195972f6Sopenharmony_ci#endif 197195972f6Sopenharmony_ci 198195972f6Sopenharmony_ci/** 199195972f6Sopenharmony_ci * Allocate a block of memory with a minimum of 'size' bytes. 200195972f6Sopenharmony_ci * 201195972f6Sopenharmony_ci * @param size is the minimum size of the requested block in bytes. 202195972f6Sopenharmony_ci * @return pointer to allocated memory or NULL if no free memory was found. 203195972f6Sopenharmony_ci * 204195972f6Sopenharmony_ci * Note that the returned value must always be aligned (as defined by MEM_ALIGNMENT). 205195972f6Sopenharmony_ci */ 206195972f6Sopenharmony_civoid * 207195972f6Sopenharmony_cimem_malloc(mem_size_t size) 208195972f6Sopenharmony_ci{ 209195972f6Sopenharmony_ci void *ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE); 210195972f6Sopenharmony_ci if (ret == NULL) { 211195972f6Sopenharmony_ci MEM_STATS_INC_LOCKED(err); 212195972f6Sopenharmony_ci } else { 213195972f6Sopenharmony_ci LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret); 214195972f6Sopenharmony_ci#if LWIP_STATS && MEM_STATS 215195972f6Sopenharmony_ci *(mem_size_t *)ret = size; 216195972f6Sopenharmony_ci ret = (u8_t *)ret + MEM_LIBC_STATSHELPER_SIZE; 217195972f6Sopenharmony_ci MEM_STATS_INC_USED_LOCKED(used, size); 218195972f6Sopenharmony_ci#endif 219195972f6Sopenharmony_ci } 220195972f6Sopenharmony_ci return ret; 221195972f6Sopenharmony_ci} 222195972f6Sopenharmony_ci 223195972f6Sopenharmony_ci/** Put memory back on the heap 224195972f6Sopenharmony_ci * 225195972f6Sopenharmony_ci * @param rmem is the pointer as returned by a previous call to mem_malloc() 226195972f6Sopenharmony_ci */ 227195972f6Sopenharmony_civoid 228195972f6Sopenharmony_cimem_free(void *rmem) 229195972f6Sopenharmony_ci{ 230195972f6Sopenharmony_ci LWIP_ASSERT("rmem != NULL", (rmem != NULL)); 231195972f6Sopenharmony_ci LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); 232195972f6Sopenharmony_ci#if LWIP_STATS && MEM_STATS 233195972f6Sopenharmony_ci rmem = (u8_t *)rmem - MEM_LIBC_STATSHELPER_SIZE; 234195972f6Sopenharmony_ci MEM_STATS_DEC_USED_LOCKED(used, *(mem_size_t *)rmem); 235195972f6Sopenharmony_ci#endif 236195972f6Sopenharmony_ci mem_clib_free(rmem); 237195972f6Sopenharmony_ci} 238195972f6Sopenharmony_ci 239195972f6Sopenharmony_ci#elif MEM_USE_POOLS 240195972f6Sopenharmony_ci 241195972f6Sopenharmony_ci/* lwIP heap implemented with different sized pools */ 242195972f6Sopenharmony_ci 243195972f6Sopenharmony_ci/** 244195972f6Sopenharmony_ci * Allocate memory: determine the smallest pool that is big enough 245195972f6Sopenharmony_ci * to contain an element of 'size' and get an element from that pool. 246195972f6Sopenharmony_ci * 247195972f6Sopenharmony_ci * @param size the size in bytes of the memory needed 248195972f6Sopenharmony_ci * @return a pointer to the allocated memory or NULL if the pool is empty 249195972f6Sopenharmony_ci */ 250195972f6Sopenharmony_civoid * 251195972f6Sopenharmony_cimem_malloc(mem_size_t size) 252195972f6Sopenharmony_ci{ 253195972f6Sopenharmony_ci void *ret; 254195972f6Sopenharmony_ci struct memp_malloc_helper *element = NULL; 255195972f6Sopenharmony_ci memp_t poolnr; 256195972f6Sopenharmony_ci mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); 257195972f6Sopenharmony_ci 258195972f6Sopenharmony_ci for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { 259195972f6Sopenharmony_ci /* is this pool big enough to hold an element of the required size 260195972f6Sopenharmony_ci plus a struct memp_malloc_helper that saves the pool this element came from? */ 261195972f6Sopenharmony_ci if (required_size <= memp_pools[poolnr]->size) { 262195972f6Sopenharmony_ci element = (struct memp_malloc_helper *)memp_malloc(poolnr); 263195972f6Sopenharmony_ci if (element == NULL) { 264195972f6Sopenharmony_ci /* No need to DEBUGF or ASSERT: This error is already taken care of in memp.c */ 265195972f6Sopenharmony_ci#if MEM_USE_POOLS_TRY_BIGGER_POOL 266195972f6Sopenharmony_ci /** Try a bigger pool if this one is empty! */ 267195972f6Sopenharmony_ci if (poolnr < MEMP_POOL_LAST) { 268195972f6Sopenharmony_ci continue; 269195972f6Sopenharmony_ci } 270195972f6Sopenharmony_ci#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ 271195972f6Sopenharmony_ci MEM_STATS_INC_LOCKED(err); 272195972f6Sopenharmony_ci return NULL; 273195972f6Sopenharmony_ci } 274195972f6Sopenharmony_ci break; 275195972f6Sopenharmony_ci } 276195972f6Sopenharmony_ci } 277195972f6Sopenharmony_ci if (poolnr > MEMP_POOL_LAST) { 278195972f6Sopenharmony_ci LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); 279195972f6Sopenharmony_ci MEM_STATS_INC_LOCKED(err); 280195972f6Sopenharmony_ci return NULL; 281195972f6Sopenharmony_ci } 282195972f6Sopenharmony_ci 283195972f6Sopenharmony_ci /* save the pool number this element came from */ 284195972f6Sopenharmony_ci element->poolnr = poolnr; 285195972f6Sopenharmony_ci /* and return a pointer to the memory directly after the struct memp_malloc_helper */ 286195972f6Sopenharmony_ci ret = (u8_t *)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); 287195972f6Sopenharmony_ci 288195972f6Sopenharmony_ci#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) 289195972f6Sopenharmony_ci /* truncating to u16_t is safe because struct memp_desc::size is u16_t */ 290195972f6Sopenharmony_ci element->size = (u16_t)size; 291195972f6Sopenharmony_ci MEM_STATS_INC_USED_LOCKED(used, element->size); 292195972f6Sopenharmony_ci#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */ 293195972f6Sopenharmony_ci#if MEMP_OVERFLOW_CHECK 294195972f6Sopenharmony_ci /* initialize unused memory (diff between requested size and selected pool's size) */ 295195972f6Sopenharmony_ci memset((u8_t *)ret + size, 0xcd, memp_pools[poolnr]->size - size); 296195972f6Sopenharmony_ci#endif /* MEMP_OVERFLOW_CHECK */ 297195972f6Sopenharmony_ci return ret; 298195972f6Sopenharmony_ci} 299195972f6Sopenharmony_ci 300195972f6Sopenharmony_ci/** 301195972f6Sopenharmony_ci * Free memory previously allocated by mem_malloc. Loads the pool number 302195972f6Sopenharmony_ci * and calls memp_free with that pool number to put the element back into 303195972f6Sopenharmony_ci * its pool 304195972f6Sopenharmony_ci * 305195972f6Sopenharmony_ci * @param rmem the memory element to free 306195972f6Sopenharmony_ci */ 307195972f6Sopenharmony_civoid 308195972f6Sopenharmony_cimem_free(void *rmem) 309195972f6Sopenharmony_ci{ 310195972f6Sopenharmony_ci struct memp_malloc_helper *hmem; 311195972f6Sopenharmony_ci 312195972f6Sopenharmony_ci LWIP_ASSERT("rmem != NULL", (rmem != NULL)); 313195972f6Sopenharmony_ci LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); 314195972f6Sopenharmony_ci 315195972f6Sopenharmony_ci /* get the original struct memp_malloc_helper */ 316195972f6Sopenharmony_ci /* cast through void* to get rid of alignment warnings */ 317195972f6Sopenharmony_ci hmem = (struct memp_malloc_helper *)(void *)((u8_t *)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))); 318195972f6Sopenharmony_ci 319195972f6Sopenharmony_ci LWIP_ASSERT("hmem != NULL", (hmem != NULL)); 320195972f6Sopenharmony_ci LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); 321195972f6Sopenharmony_ci LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); 322195972f6Sopenharmony_ci 323195972f6Sopenharmony_ci MEM_STATS_DEC_USED_LOCKED(used, hmem->size); 324195972f6Sopenharmony_ci#if MEMP_OVERFLOW_CHECK 325195972f6Sopenharmony_ci { 326195972f6Sopenharmony_ci u16_t i; 327195972f6Sopenharmony_ci LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size", 328195972f6Sopenharmony_ci hmem->size <= memp_pools[hmem->poolnr]->size); 329195972f6Sopenharmony_ci /* check that unused memory remained untouched (diff between requested size and selected pool's size) */ 330195972f6Sopenharmony_ci for (i = hmem->size; i < memp_pools[hmem->poolnr]->size; i++) { 331195972f6Sopenharmony_ci u8_t data = *((u8_t *)rmem + i); 332195972f6Sopenharmony_ci LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd); 333195972f6Sopenharmony_ci } 334195972f6Sopenharmony_ci } 335195972f6Sopenharmony_ci#endif /* MEMP_OVERFLOW_CHECK */ 336195972f6Sopenharmony_ci 337195972f6Sopenharmony_ci /* and put it in the pool we saved earlier */ 338195972f6Sopenharmony_ci memp_free(hmem->poolnr, hmem); 339195972f6Sopenharmony_ci} 340195972f6Sopenharmony_ci 341195972f6Sopenharmony_ci#else /* MEM_USE_POOLS */ 342195972f6Sopenharmony_ci/* lwIP replacement for your libc malloc() */ 343195972f6Sopenharmony_ci 344195972f6Sopenharmony_ci/** 345195972f6Sopenharmony_ci * The heap is made up as a list of structs of this type. 346195972f6Sopenharmony_ci * This does not have to be aligned since for getting its size, 347195972f6Sopenharmony_ci * we only use the macro SIZEOF_STRUCT_MEM, which automatically aligns. 348195972f6Sopenharmony_ci */ 349195972f6Sopenharmony_cistruct mem { 350195972f6Sopenharmony_ci /** index (-> ram[next]) of the next struct */ 351195972f6Sopenharmony_ci mem_size_t next; 352195972f6Sopenharmony_ci /** index (-> ram[prev]) of the previous struct */ 353195972f6Sopenharmony_ci mem_size_t prev; 354195972f6Sopenharmony_ci /** 1: this area is used; 0: this area is unused */ 355195972f6Sopenharmony_ci u8_t used; 356195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK 357195972f6Sopenharmony_ci /** this keeps track of the user allocation size for guard checks */ 358195972f6Sopenharmony_ci mem_size_t user_size; 359195972f6Sopenharmony_ci#endif 360195972f6Sopenharmony_ci}; 361195972f6Sopenharmony_ci 362195972f6Sopenharmony_ci/** All allocated blocks will be MIN_SIZE bytes big, at least! 363195972f6Sopenharmony_ci * MIN_SIZE can be overridden to suit your needs. Smaller values save space, 364195972f6Sopenharmony_ci * larger values could prevent too small blocks to fragment the RAM too much. */ 365195972f6Sopenharmony_ci#ifndef MIN_SIZE 366195972f6Sopenharmony_ci#define MIN_SIZE 12 367195972f6Sopenharmony_ci#endif /* MIN_SIZE */ 368195972f6Sopenharmony_ci/* some alignment macros: we define them here for better source code layout */ 369195972f6Sopenharmony_ci#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) 370195972f6Sopenharmony_ci#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) 371195972f6Sopenharmony_ci#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) 372195972f6Sopenharmony_ci 373195972f6Sopenharmony_ci/** If you want to relocate the heap to external memory, simply define 374195972f6Sopenharmony_ci * LWIP_RAM_HEAP_POINTER as a void-pointer to that location. 375195972f6Sopenharmony_ci * If so, make sure the memory at that location is big enough (see below on 376195972f6Sopenharmony_ci * how that space is calculated). */ 377195972f6Sopenharmony_ci#ifndef LWIP_RAM_HEAP_POINTER 378195972f6Sopenharmony_ci/** the heap. we need one struct mem at the end and some room for alignment */ 379195972f6Sopenharmony_ciLWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U * SIZEOF_STRUCT_MEM)); 380195972f6Sopenharmony_ci#define LWIP_RAM_HEAP_POINTER ram_heap 381195972f6Sopenharmony_ci#endif /* LWIP_RAM_HEAP_POINTER */ 382195972f6Sopenharmony_ci 383195972f6Sopenharmony_ci/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ 384195972f6Sopenharmony_cistatic u8_t *ram; 385195972f6Sopenharmony_ci/** the last entry, always unused! */ 386195972f6Sopenharmony_cistatic struct mem *ram_end; 387195972f6Sopenharmony_ci 388195972f6Sopenharmony_ci/** concurrent access protection */ 389195972f6Sopenharmony_ci#if !NO_SYS 390195972f6Sopenharmony_cistatic sys_mutex_t mem_mutex; 391195972f6Sopenharmony_ci#endif 392195972f6Sopenharmony_ci 393195972f6Sopenharmony_ci#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 394195972f6Sopenharmony_ci 395195972f6Sopenharmony_cistatic volatile u8_t mem_free_count; 396195972f6Sopenharmony_ci 397195972f6Sopenharmony_ci/* Allow mem_free from other (e.g. interrupt) context */ 398195972f6Sopenharmony_ci#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) 399195972f6Sopenharmony_ci#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) 400195972f6Sopenharmony_ci#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) 401195972f6Sopenharmony_ci#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) 402195972f6Sopenharmony_ci#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) 403195972f6Sopenharmony_ci#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) 404195972f6Sopenharmony_ci#define LWIP_MEM_LFREE_VOLATILE volatile 405195972f6Sopenharmony_ci 406195972f6Sopenharmony_ci#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 407195972f6Sopenharmony_ci 408195972f6Sopenharmony_ci/* Protect the heap only by using a mutex */ 409195972f6Sopenharmony_ci#define LWIP_MEM_FREE_DECL_PROTECT() 410195972f6Sopenharmony_ci#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) 411195972f6Sopenharmony_ci#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) 412195972f6Sopenharmony_ci/* mem_malloc is protected using mutex AND LWIP_MEM_ALLOC_PROTECT */ 413195972f6Sopenharmony_ci#define LWIP_MEM_ALLOC_DECL_PROTECT() 414195972f6Sopenharmony_ci#define LWIP_MEM_ALLOC_PROTECT() 415195972f6Sopenharmony_ci#define LWIP_MEM_ALLOC_UNPROTECT() 416195972f6Sopenharmony_ci#define LWIP_MEM_LFREE_VOLATILE 417195972f6Sopenharmony_ci 418195972f6Sopenharmony_ci#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 419195972f6Sopenharmony_ci 420195972f6Sopenharmony_ci/** pointer to the lowest free block, this is used for faster search */ 421195972f6Sopenharmony_cistatic struct mem * LWIP_MEM_LFREE_VOLATILE lfree; 422195972f6Sopenharmony_ci 423195972f6Sopenharmony_ci#if MEM_SANITY_CHECK 424195972f6Sopenharmony_cistatic void mem_sanity(void); 425195972f6Sopenharmony_ci#define MEM_SANITY() mem_sanity() 426195972f6Sopenharmony_ci#else 427195972f6Sopenharmony_ci#define MEM_SANITY() 428195972f6Sopenharmony_ci#endif 429195972f6Sopenharmony_ci 430195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK 431195972f6Sopenharmony_cistatic void 432195972f6Sopenharmony_cimem_overflow_init_element(struct mem *mem, mem_size_t user_size) 433195972f6Sopenharmony_ci{ 434195972f6Sopenharmony_ci void *p = (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET; 435195972f6Sopenharmony_ci mem->user_size = user_size; 436195972f6Sopenharmony_ci mem_overflow_init_raw(p, user_size); 437195972f6Sopenharmony_ci} 438195972f6Sopenharmony_ci 439195972f6Sopenharmony_cistatic void 440195972f6Sopenharmony_cimem_overflow_check_element(struct mem *mem) 441195972f6Sopenharmony_ci{ 442195972f6Sopenharmony_ci void *p = (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET; 443195972f6Sopenharmony_ci mem_overflow_check_raw(p, mem->user_size, "heap", ""); 444195972f6Sopenharmony_ci} 445195972f6Sopenharmony_ci#else /* MEM_OVERFLOW_CHECK */ 446195972f6Sopenharmony_ci#define mem_overflow_init_element(mem, size) 447195972f6Sopenharmony_ci#define mem_overflow_check_element(mem) 448195972f6Sopenharmony_ci#endif /* MEM_OVERFLOW_CHECK */ 449195972f6Sopenharmony_ci 450195972f6Sopenharmony_cistatic struct mem * 451195972f6Sopenharmony_ciptr_to_mem(mem_size_t ptr) 452195972f6Sopenharmony_ci{ 453195972f6Sopenharmony_ci return (struct mem *)(void *)&ram[ptr]; 454195972f6Sopenharmony_ci} 455195972f6Sopenharmony_ci 456195972f6Sopenharmony_cistatic mem_size_t 457195972f6Sopenharmony_cimem_to_ptr(void *mem) 458195972f6Sopenharmony_ci{ 459195972f6Sopenharmony_ci return (mem_size_t)((u8_t *)mem - ram); 460195972f6Sopenharmony_ci} 461195972f6Sopenharmony_ci 462195972f6Sopenharmony_ci/** 463195972f6Sopenharmony_ci * "Plug holes" by combining adjacent empty struct mems. 464195972f6Sopenharmony_ci * After this function is through, there should not exist 465195972f6Sopenharmony_ci * one empty struct mem pointing to another empty struct mem. 466195972f6Sopenharmony_ci * 467195972f6Sopenharmony_ci * @param mem this points to a struct mem which just has been freed 468195972f6Sopenharmony_ci * @internal this function is only called by mem_free() and mem_trim() 469195972f6Sopenharmony_ci * 470195972f6Sopenharmony_ci * This assumes access to the heap is protected by the calling function 471195972f6Sopenharmony_ci * already. 472195972f6Sopenharmony_ci */ 473195972f6Sopenharmony_cistatic void 474195972f6Sopenharmony_ciplug_holes(struct mem *mem) 475195972f6Sopenharmony_ci{ 476195972f6Sopenharmony_ci struct mem *nmem; 477195972f6Sopenharmony_ci struct mem *pmem; 478195972f6Sopenharmony_ci 479195972f6Sopenharmony_ci LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); 480195972f6Sopenharmony_ci LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); 481195972f6Sopenharmony_ci LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); 482195972f6Sopenharmony_ci 483195972f6Sopenharmony_ci /* plug hole forward */ 484195972f6Sopenharmony_ci LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); 485195972f6Sopenharmony_ci 486195972f6Sopenharmony_ci nmem = ptr_to_mem(mem->next); 487195972f6Sopenharmony_ci if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { 488195972f6Sopenharmony_ci /* if mem->next is unused and not end of ram, combine mem and mem->next */ 489195972f6Sopenharmony_ci if (lfree == nmem) { 490195972f6Sopenharmony_ci lfree = mem; 491195972f6Sopenharmony_ci } 492195972f6Sopenharmony_ci mem->next = nmem->next; 493195972f6Sopenharmony_ci if (nmem->next != MEM_SIZE_ALIGNED) { 494195972f6Sopenharmony_ci ptr_to_mem(nmem->next)->prev = mem_to_ptr(mem); 495195972f6Sopenharmony_ci } 496195972f6Sopenharmony_ci } 497195972f6Sopenharmony_ci 498195972f6Sopenharmony_ci /* plug hole backward */ 499195972f6Sopenharmony_ci pmem = ptr_to_mem(mem->prev); 500195972f6Sopenharmony_ci if (pmem != mem && pmem->used == 0) { 501195972f6Sopenharmony_ci /* if mem->prev is unused, combine mem and mem->prev */ 502195972f6Sopenharmony_ci if (lfree == mem) { 503195972f6Sopenharmony_ci lfree = pmem; 504195972f6Sopenharmony_ci } 505195972f6Sopenharmony_ci pmem->next = mem->next; 506195972f6Sopenharmony_ci if (mem->next != MEM_SIZE_ALIGNED) { 507195972f6Sopenharmony_ci ptr_to_mem(mem->next)->prev = mem_to_ptr(pmem); 508195972f6Sopenharmony_ci } 509195972f6Sopenharmony_ci } 510195972f6Sopenharmony_ci} 511195972f6Sopenharmony_ci 512195972f6Sopenharmony_ci/** 513195972f6Sopenharmony_ci * Zero the heap and initialize start, end and lowest-free 514195972f6Sopenharmony_ci */ 515195972f6Sopenharmony_civoid 516195972f6Sopenharmony_cimem_init(void) 517195972f6Sopenharmony_ci{ 518195972f6Sopenharmony_ci struct mem *mem; 519195972f6Sopenharmony_ci 520195972f6Sopenharmony_ci LWIP_ASSERT("Sanity check alignment", 521195972f6Sopenharmony_ci (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT - 1)) == 0); 522195972f6Sopenharmony_ci 523195972f6Sopenharmony_ci /* align the heap */ 524195972f6Sopenharmony_ci ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); 525195972f6Sopenharmony_ci /* initialize the start of the heap */ 526195972f6Sopenharmony_ci mem = (struct mem *)(void *)ram; 527195972f6Sopenharmony_ci mem->next = MEM_SIZE_ALIGNED; 528195972f6Sopenharmony_ci mem->prev = 0; 529195972f6Sopenharmony_ci mem->used = 0; 530195972f6Sopenharmony_ci /* initialize the end of the heap */ 531195972f6Sopenharmony_ci ram_end = ptr_to_mem(MEM_SIZE_ALIGNED); 532195972f6Sopenharmony_ci ram_end->used = 1; 533195972f6Sopenharmony_ci ram_end->next = MEM_SIZE_ALIGNED; 534195972f6Sopenharmony_ci ram_end->prev = MEM_SIZE_ALIGNED; 535195972f6Sopenharmony_ci MEM_SANITY(); 536195972f6Sopenharmony_ci 537195972f6Sopenharmony_ci /* initialize the lowest-free pointer to the start of the heap */ 538195972f6Sopenharmony_ci lfree = (struct mem *)(void *)ram; 539195972f6Sopenharmony_ci 540195972f6Sopenharmony_ci MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); 541195972f6Sopenharmony_ci 542195972f6Sopenharmony_ci if (sys_mutex_new(&mem_mutex) != ERR_OK) { 543195972f6Sopenharmony_ci LWIP_ASSERT("failed to create mem_mutex", 0); 544195972f6Sopenharmony_ci } 545195972f6Sopenharmony_ci} 546195972f6Sopenharmony_ci 547195972f6Sopenharmony_ci/* Check if a struct mem is correctly linked. 548195972f6Sopenharmony_ci * If not, double-free is a possible reason. 549195972f6Sopenharmony_ci */ 550195972f6Sopenharmony_cistatic int 551195972f6Sopenharmony_cimem_link_valid(struct mem *mem) 552195972f6Sopenharmony_ci{ 553195972f6Sopenharmony_ci struct mem *nmem, *pmem; 554195972f6Sopenharmony_ci mem_size_t rmem_idx; 555195972f6Sopenharmony_ci rmem_idx = mem_to_ptr(mem); 556195972f6Sopenharmony_ci nmem = ptr_to_mem(mem->next); 557195972f6Sopenharmony_ci pmem = ptr_to_mem(mem->prev); 558195972f6Sopenharmony_ci if ((mem->next > MEM_SIZE_ALIGNED) || (mem->prev > MEM_SIZE_ALIGNED) || 559195972f6Sopenharmony_ci ((mem->prev != rmem_idx) && (pmem->next != rmem_idx)) || 560195972f6Sopenharmony_ci ((nmem != ram_end) && (nmem->prev != rmem_idx))) { 561195972f6Sopenharmony_ci return 0; 562195972f6Sopenharmony_ci } 563195972f6Sopenharmony_ci return 1; 564195972f6Sopenharmony_ci} 565195972f6Sopenharmony_ci 566195972f6Sopenharmony_ci#if MEM_SANITY_CHECK 567195972f6Sopenharmony_cistatic void 568195972f6Sopenharmony_cimem_sanity(void) 569195972f6Sopenharmony_ci{ 570195972f6Sopenharmony_ci struct mem *mem; 571195972f6Sopenharmony_ci u8_t last_used; 572195972f6Sopenharmony_ci 573195972f6Sopenharmony_ci /* begin with first element here */ 574195972f6Sopenharmony_ci mem = (struct mem *)ram; 575195972f6Sopenharmony_ci LWIP_ASSERT("heap element used valid", (mem->used == 0) || (mem->used == 1)); 576195972f6Sopenharmony_ci last_used = mem->used; 577195972f6Sopenharmony_ci LWIP_ASSERT("heap element prev ptr valid", mem->prev == 0); 578195972f6Sopenharmony_ci LWIP_ASSERT("heap element next ptr valid", mem->next <= MEM_SIZE_ALIGNED); 579195972f6Sopenharmony_ci LWIP_ASSERT("heap element next ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->next) == ptr_to_mem(mem->next))); 580195972f6Sopenharmony_ci 581195972f6Sopenharmony_ci /* check all elements before the end of the heap */ 582195972f6Sopenharmony_ci for (mem = ptr_to_mem(mem->next); 583195972f6Sopenharmony_ci ((u8_t *)mem > ram) && (mem < ram_end); 584195972f6Sopenharmony_ci mem = ptr_to_mem(mem->next)) { 585195972f6Sopenharmony_ci LWIP_ASSERT("heap element aligned", LWIP_MEM_ALIGN(mem) == mem); 586195972f6Sopenharmony_ci LWIP_ASSERT("heap element prev ptr valid", mem->prev <= MEM_SIZE_ALIGNED); 587195972f6Sopenharmony_ci LWIP_ASSERT("heap element next ptr valid", mem->next <= MEM_SIZE_ALIGNED); 588195972f6Sopenharmony_ci LWIP_ASSERT("heap element prev ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->prev) == ptr_to_mem(mem->prev))); 589195972f6Sopenharmony_ci LWIP_ASSERT("heap element next ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->next) == ptr_to_mem(mem->next))); 590195972f6Sopenharmony_ci 591195972f6Sopenharmony_ci if (last_used == 0) { 592195972f6Sopenharmony_ci /* 2 unused elements in a row? */ 593195972f6Sopenharmony_ci LWIP_ASSERT("heap element unused?", mem->used == 1); 594195972f6Sopenharmony_ci } else { 595195972f6Sopenharmony_ci LWIP_ASSERT("heap element unused member", (mem->used == 0) || (mem->used == 1)); 596195972f6Sopenharmony_ci } 597195972f6Sopenharmony_ci 598195972f6Sopenharmony_ci LWIP_ASSERT("heap element link valid", mem_link_valid(mem)); 599195972f6Sopenharmony_ci 600195972f6Sopenharmony_ci /* used/unused altering */ 601195972f6Sopenharmony_ci last_used = mem->used; 602195972f6Sopenharmony_ci } 603195972f6Sopenharmony_ci LWIP_ASSERT("heap end ptr sanity", mem == ptr_to_mem(MEM_SIZE_ALIGNED)); 604195972f6Sopenharmony_ci LWIP_ASSERT("heap element used valid", mem->used == 1); 605195972f6Sopenharmony_ci LWIP_ASSERT("heap element prev ptr valid", mem->prev == MEM_SIZE_ALIGNED); 606195972f6Sopenharmony_ci LWIP_ASSERT("heap element next ptr valid", mem->next == MEM_SIZE_ALIGNED); 607195972f6Sopenharmony_ci} 608195972f6Sopenharmony_ci#endif /* MEM_SANITY_CHECK */ 609195972f6Sopenharmony_ci 610195972f6Sopenharmony_ci/** 611195972f6Sopenharmony_ci * Put a struct mem back on the heap 612195972f6Sopenharmony_ci * 613195972f6Sopenharmony_ci * @param rmem is the data portion of a struct mem as returned by a previous 614195972f6Sopenharmony_ci * call to mem_malloc() 615195972f6Sopenharmony_ci */ 616195972f6Sopenharmony_civoid 617195972f6Sopenharmony_cimem_free(void *rmem) 618195972f6Sopenharmony_ci{ 619195972f6Sopenharmony_ci struct mem *mem; 620195972f6Sopenharmony_ci LWIP_MEM_FREE_DECL_PROTECT(); 621195972f6Sopenharmony_ci 622195972f6Sopenharmony_ci if (rmem == NULL) { 623195972f6Sopenharmony_ci LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); 624195972f6Sopenharmony_ci return; 625195972f6Sopenharmony_ci } 626195972f6Sopenharmony_ci if ((((mem_ptr_t)rmem) & (MEM_ALIGNMENT - 1)) != 0) { 627195972f6Sopenharmony_ci LWIP_MEM_ILLEGAL_FREE("mem_free: sanity check alignment"); 628195972f6Sopenharmony_ci LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: sanity check alignment\n")); 629195972f6Sopenharmony_ci /* protect mem stats from concurrent access */ 630195972f6Sopenharmony_ci MEM_STATS_INC_LOCKED(illegal); 631195972f6Sopenharmony_ci return; 632195972f6Sopenharmony_ci } 633195972f6Sopenharmony_ci 634195972f6Sopenharmony_ci /* Get the corresponding struct mem: */ 635195972f6Sopenharmony_ci /* cast through void* to get rid of alignment warnings */ 636195972f6Sopenharmony_ci mem = (struct mem *)(void *)((u8_t *)rmem - (SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET)); 637195972f6Sopenharmony_ci 638195972f6Sopenharmony_ci if ((u8_t *)mem < ram || (u8_t *)rmem + MIN_SIZE_ALIGNED > (u8_t *)ram_end) { 639195972f6Sopenharmony_ci LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory"); 640195972f6Sopenharmony_ci LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); 641195972f6Sopenharmony_ci /* protect mem stats from concurrent access */ 642195972f6Sopenharmony_ci MEM_STATS_INC_LOCKED(illegal); 643195972f6Sopenharmony_ci return; 644195972f6Sopenharmony_ci } 645195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK 646195972f6Sopenharmony_ci mem_overflow_check_element(mem); 647195972f6Sopenharmony_ci#endif 648195972f6Sopenharmony_ci /* protect the heap from concurrent access */ 649195972f6Sopenharmony_ci LWIP_MEM_FREE_PROTECT(); 650195972f6Sopenharmony_ci /* mem has to be in a used state */ 651195972f6Sopenharmony_ci if (!mem->used) { 652195972f6Sopenharmony_ci LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: double free"); 653195972f6Sopenharmony_ci LWIP_MEM_FREE_UNPROTECT(); 654195972f6Sopenharmony_ci LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: double free?\n")); 655195972f6Sopenharmony_ci /* protect mem stats from concurrent access */ 656195972f6Sopenharmony_ci MEM_STATS_INC_LOCKED(illegal); 657195972f6Sopenharmony_ci return; 658195972f6Sopenharmony_ci } 659195972f6Sopenharmony_ci 660195972f6Sopenharmony_ci if (!mem_link_valid(mem)) { 661195972f6Sopenharmony_ci LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: non-linked: double free"); 662195972f6Sopenharmony_ci LWIP_MEM_FREE_UNPROTECT(); 663195972f6Sopenharmony_ci LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: non-linked: double free?\n")); 664195972f6Sopenharmony_ci /* protect mem stats from concurrent access */ 665195972f6Sopenharmony_ci MEM_STATS_INC_LOCKED(illegal); 666195972f6Sopenharmony_ci return; 667195972f6Sopenharmony_ci } 668195972f6Sopenharmony_ci 669195972f6Sopenharmony_ci /* mem is now unused. */ 670195972f6Sopenharmony_ci mem->used = 0; 671195972f6Sopenharmony_ci 672195972f6Sopenharmony_ci if (mem < lfree) { 673195972f6Sopenharmony_ci /* the newly freed struct is now the lowest */ 674195972f6Sopenharmony_ci lfree = mem; 675195972f6Sopenharmony_ci } 676195972f6Sopenharmony_ci 677195972f6Sopenharmony_ci MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); 678195972f6Sopenharmony_ci 679195972f6Sopenharmony_ci /* finally, see if prev or next are free also */ 680195972f6Sopenharmony_ci plug_holes(mem); 681195972f6Sopenharmony_ci MEM_SANITY(); 682195972f6Sopenharmony_ci#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 683195972f6Sopenharmony_ci mem_free_count = 1; 684195972f6Sopenharmony_ci#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 685195972f6Sopenharmony_ci LWIP_MEM_FREE_UNPROTECT(); 686195972f6Sopenharmony_ci} 687195972f6Sopenharmony_ci 688195972f6Sopenharmony_ci/** 689195972f6Sopenharmony_ci * Shrink memory returned by mem_malloc(). 690195972f6Sopenharmony_ci * 691195972f6Sopenharmony_ci * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked 692195972f6Sopenharmony_ci * @param new_size required size after shrinking (needs to be smaller than or 693195972f6Sopenharmony_ci * equal to the previous size) 694195972f6Sopenharmony_ci * @return for compatibility reasons: is always == rmem, at the moment 695195972f6Sopenharmony_ci * or NULL if newsize is > old size, in which case rmem is NOT touched 696195972f6Sopenharmony_ci * or freed! 697195972f6Sopenharmony_ci */ 698195972f6Sopenharmony_civoid * 699195972f6Sopenharmony_cimem_trim(void *rmem, mem_size_t new_size) 700195972f6Sopenharmony_ci{ 701195972f6Sopenharmony_ci mem_size_t size, newsize; 702195972f6Sopenharmony_ci mem_size_t ptr, ptr2; 703195972f6Sopenharmony_ci struct mem *mem, *mem2; 704195972f6Sopenharmony_ci /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ 705195972f6Sopenharmony_ci LWIP_MEM_FREE_DECL_PROTECT(); 706195972f6Sopenharmony_ci 707195972f6Sopenharmony_ci /* Expand the size of the allocated memory region so that we can 708195972f6Sopenharmony_ci adjust for alignment. */ 709195972f6Sopenharmony_ci newsize = (mem_size_t)LWIP_MEM_ALIGN_SIZE(new_size); 710195972f6Sopenharmony_ci if (newsize < MIN_SIZE_ALIGNED) { 711195972f6Sopenharmony_ci /* every data block must be at least MIN_SIZE_ALIGNED long */ 712195972f6Sopenharmony_ci newsize = MIN_SIZE_ALIGNED; 713195972f6Sopenharmony_ci } 714195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK 715195972f6Sopenharmony_ci newsize += MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED; 716195972f6Sopenharmony_ci#endif 717195972f6Sopenharmony_ci if ((newsize > MEM_SIZE_ALIGNED) || (newsize < new_size)) { 718195972f6Sopenharmony_ci return NULL; 719195972f6Sopenharmony_ci } 720195972f6Sopenharmony_ci 721195972f6Sopenharmony_ci LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && 722195972f6Sopenharmony_ci (u8_t *)rmem < (u8_t *)ram_end); 723195972f6Sopenharmony_ci 724195972f6Sopenharmony_ci if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { 725195972f6Sopenharmony_ci LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); 726195972f6Sopenharmony_ci /* protect mem stats from concurrent access */ 727195972f6Sopenharmony_ci MEM_STATS_INC_LOCKED(illegal); 728195972f6Sopenharmony_ci return rmem; 729195972f6Sopenharmony_ci } 730195972f6Sopenharmony_ci /* Get the corresponding struct mem ... */ 731195972f6Sopenharmony_ci /* cast through void* to get rid of alignment warnings */ 732195972f6Sopenharmony_ci mem = (struct mem *)(void *)((u8_t *)rmem - (SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET)); 733195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK 734195972f6Sopenharmony_ci mem_overflow_check_element(mem); 735195972f6Sopenharmony_ci#endif 736195972f6Sopenharmony_ci /* ... and its offset pointer */ 737195972f6Sopenharmony_ci ptr = mem_to_ptr(mem); 738195972f6Sopenharmony_ci 739195972f6Sopenharmony_ci size = (mem_size_t)((mem_size_t)(mem->next - ptr) - (SIZEOF_STRUCT_MEM + MEM_SANITY_OVERHEAD)); 740195972f6Sopenharmony_ci LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); 741195972f6Sopenharmony_ci if (newsize > size) { 742195972f6Sopenharmony_ci /* not supported */ 743195972f6Sopenharmony_ci return NULL; 744195972f6Sopenharmony_ci } 745195972f6Sopenharmony_ci if (newsize == size) { 746195972f6Sopenharmony_ci /* No change in size, simply return */ 747195972f6Sopenharmony_ci return rmem; 748195972f6Sopenharmony_ci } 749195972f6Sopenharmony_ci 750195972f6Sopenharmony_ci /* protect the heap from concurrent access */ 751195972f6Sopenharmony_ci LWIP_MEM_FREE_PROTECT(); 752195972f6Sopenharmony_ci 753195972f6Sopenharmony_ci mem2 = ptr_to_mem(mem->next); 754195972f6Sopenharmony_ci if (mem2->used == 0) { 755195972f6Sopenharmony_ci /* The next struct is unused, we can simply move it at little */ 756195972f6Sopenharmony_ci mem_size_t next; 757195972f6Sopenharmony_ci LWIP_ASSERT("invalid next ptr", mem->next != MEM_SIZE_ALIGNED); 758195972f6Sopenharmony_ci /* remember the old next pointer */ 759195972f6Sopenharmony_ci next = mem2->next; 760195972f6Sopenharmony_ci /* create new struct mem which is moved directly after the shrinked mem */ 761195972f6Sopenharmony_ci ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + newsize); 762195972f6Sopenharmony_ci if (lfree == mem2) { 763195972f6Sopenharmony_ci lfree = ptr_to_mem(ptr2); 764195972f6Sopenharmony_ci } 765195972f6Sopenharmony_ci mem2 = ptr_to_mem(ptr2); 766195972f6Sopenharmony_ci mem2->used = 0; 767195972f6Sopenharmony_ci /* restore the next pointer */ 768195972f6Sopenharmony_ci mem2->next = next; 769195972f6Sopenharmony_ci /* link it back to mem */ 770195972f6Sopenharmony_ci mem2->prev = ptr; 771195972f6Sopenharmony_ci /* link mem to it */ 772195972f6Sopenharmony_ci mem->next = ptr2; 773195972f6Sopenharmony_ci /* last thing to restore linked list: as we have moved mem2, 774195972f6Sopenharmony_ci * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not 775195972f6Sopenharmony_ci * the end of the heap */ 776195972f6Sopenharmony_ci if (mem2->next != MEM_SIZE_ALIGNED) { 777195972f6Sopenharmony_ci ptr_to_mem(mem2->next)->prev = ptr2; 778195972f6Sopenharmony_ci } 779195972f6Sopenharmony_ci MEM_STATS_DEC_USED(used, (size - newsize)); 780195972f6Sopenharmony_ci /* no need to plug holes, we've already done that */ 781195972f6Sopenharmony_ci } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { 782195972f6Sopenharmony_ci /* Next struct is used but there's room for another struct mem with 783195972f6Sopenharmony_ci * at least MIN_SIZE_ALIGNED of data. 784195972f6Sopenharmony_ci * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem 785195972f6Sopenharmony_ci * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). 786195972f6Sopenharmony_ci * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty 787195972f6Sopenharmony_ci * region that couldn't hold data, but when mem->next gets freed, 788195972f6Sopenharmony_ci * the 2 regions would be combined, resulting in more free memory */ 789195972f6Sopenharmony_ci ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + newsize); 790195972f6Sopenharmony_ci LWIP_ASSERT("invalid next ptr", mem->next != MEM_SIZE_ALIGNED); 791195972f6Sopenharmony_ci mem2 = ptr_to_mem(ptr2); 792195972f6Sopenharmony_ci if (mem2 < lfree) { 793195972f6Sopenharmony_ci lfree = mem2; 794195972f6Sopenharmony_ci } 795195972f6Sopenharmony_ci mem2->used = 0; 796195972f6Sopenharmony_ci mem2->next = mem->next; 797195972f6Sopenharmony_ci mem2->prev = ptr; 798195972f6Sopenharmony_ci mem->next = ptr2; 799195972f6Sopenharmony_ci if (mem2->next != MEM_SIZE_ALIGNED) { 800195972f6Sopenharmony_ci ptr_to_mem(mem2->next)->prev = ptr2; 801195972f6Sopenharmony_ci } 802195972f6Sopenharmony_ci MEM_STATS_DEC_USED(used, (size - newsize)); 803195972f6Sopenharmony_ci /* the original mem->next is used, so no need to plug holes! */ 804195972f6Sopenharmony_ci } 805195972f6Sopenharmony_ci /* else { 806195972f6Sopenharmony_ci next struct mem is used but size between mem and mem2 is not big enough 807195972f6Sopenharmony_ci to create another struct mem 808195972f6Sopenharmony_ci -> don't do anyhting. 809195972f6Sopenharmony_ci -> the remaining space stays unused since it is too small 810195972f6Sopenharmony_ci } */ 811195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK 812195972f6Sopenharmony_ci mem_overflow_init_element(mem, new_size); 813195972f6Sopenharmony_ci#endif 814195972f6Sopenharmony_ci MEM_SANITY(); 815195972f6Sopenharmony_ci#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 816195972f6Sopenharmony_ci mem_free_count = 1; 817195972f6Sopenharmony_ci#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 818195972f6Sopenharmony_ci LWIP_MEM_FREE_UNPROTECT(); 819195972f6Sopenharmony_ci return rmem; 820195972f6Sopenharmony_ci} 821195972f6Sopenharmony_ci 822195972f6Sopenharmony_ci/** 823195972f6Sopenharmony_ci * Allocate a block of memory with a minimum of 'size' bytes. 824195972f6Sopenharmony_ci * 825195972f6Sopenharmony_ci * @param size_in is the minimum size of the requested block in bytes. 826195972f6Sopenharmony_ci * @return pointer to allocated memory or NULL if no free memory was found. 827195972f6Sopenharmony_ci * 828195972f6Sopenharmony_ci * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). 829195972f6Sopenharmony_ci */ 830195972f6Sopenharmony_civoid * 831195972f6Sopenharmony_cimem_malloc(mem_size_t size_in) 832195972f6Sopenharmony_ci{ 833195972f6Sopenharmony_ci mem_size_t ptr, ptr2, size; 834195972f6Sopenharmony_ci struct mem *mem, *mem2; 835195972f6Sopenharmony_ci#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 836195972f6Sopenharmony_ci u8_t local_mem_free_count = 0; 837195972f6Sopenharmony_ci#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 838195972f6Sopenharmony_ci LWIP_MEM_ALLOC_DECL_PROTECT(); 839195972f6Sopenharmony_ci 840195972f6Sopenharmony_ci if (size_in == 0) { 841195972f6Sopenharmony_ci return NULL; 842195972f6Sopenharmony_ci } 843195972f6Sopenharmony_ci 844195972f6Sopenharmony_ci /* Expand the size of the allocated memory region so that we can 845195972f6Sopenharmony_ci adjust for alignment. */ 846195972f6Sopenharmony_ci size = (mem_size_t)LWIP_MEM_ALIGN_SIZE(size_in); 847195972f6Sopenharmony_ci if (size < MIN_SIZE_ALIGNED) { 848195972f6Sopenharmony_ci /* every data block must be at least MIN_SIZE_ALIGNED long */ 849195972f6Sopenharmony_ci size = MIN_SIZE_ALIGNED; 850195972f6Sopenharmony_ci } 851195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK 852195972f6Sopenharmony_ci size += MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED; 853195972f6Sopenharmony_ci#endif 854195972f6Sopenharmony_ci if ((size > MEM_SIZE_ALIGNED) || (size < size_in)) { 855195972f6Sopenharmony_ci return NULL; 856195972f6Sopenharmony_ci } 857195972f6Sopenharmony_ci 858195972f6Sopenharmony_ci /* protect the heap from concurrent access */ 859195972f6Sopenharmony_ci sys_mutex_lock(&mem_mutex); 860195972f6Sopenharmony_ci LWIP_MEM_ALLOC_PROTECT(); 861195972f6Sopenharmony_ci#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 862195972f6Sopenharmony_ci /* run as long as a mem_free disturbed mem_malloc or mem_trim */ 863195972f6Sopenharmony_ci do { 864195972f6Sopenharmony_ci local_mem_free_count = 0; 865195972f6Sopenharmony_ci#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 866195972f6Sopenharmony_ci 867195972f6Sopenharmony_ci /* Scan through the heap searching for a free block that is big enough, 868195972f6Sopenharmony_ci * beginning with the lowest free block. 869195972f6Sopenharmony_ci */ 870195972f6Sopenharmony_ci for (ptr = mem_to_ptr(lfree); ptr < MEM_SIZE_ALIGNED - size; 871195972f6Sopenharmony_ci ptr = ptr_to_mem(ptr)->next) { 872195972f6Sopenharmony_ci mem = ptr_to_mem(ptr); 873195972f6Sopenharmony_ci#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 874195972f6Sopenharmony_ci mem_free_count = 0; 875195972f6Sopenharmony_ci LWIP_MEM_ALLOC_UNPROTECT(); 876195972f6Sopenharmony_ci /* allow mem_free or mem_trim to run */ 877195972f6Sopenharmony_ci LWIP_MEM_ALLOC_PROTECT(); 878195972f6Sopenharmony_ci if (mem_free_count != 0) { 879195972f6Sopenharmony_ci /* If mem_free or mem_trim have run, we have to restart since they 880195972f6Sopenharmony_ci could have altered our current struct mem. */ 881195972f6Sopenharmony_ci local_mem_free_count = 1; 882195972f6Sopenharmony_ci break; 883195972f6Sopenharmony_ci } 884195972f6Sopenharmony_ci#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 885195972f6Sopenharmony_ci 886195972f6Sopenharmony_ci if ((!mem->used) && 887195972f6Sopenharmony_ci (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { 888195972f6Sopenharmony_ci /* mem is not used and at least perfect fit is possible: 889195972f6Sopenharmony_ci * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ 890195972f6Sopenharmony_ci 891195972f6Sopenharmony_ci if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { 892195972f6Sopenharmony_ci /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing 893195972f6Sopenharmony_ci * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') 894195972f6Sopenharmony_ci * -> split large block, create empty remainder, 895195972f6Sopenharmony_ci * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if 896195972f6Sopenharmony_ci * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, 897195972f6Sopenharmony_ci * struct mem would fit in but no data between mem2 and mem2->next 898195972f6Sopenharmony_ci * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty 899195972f6Sopenharmony_ci * region that couldn't hold data, but when mem->next gets freed, 900195972f6Sopenharmony_ci * the 2 regions would be combined, resulting in more free memory 901195972f6Sopenharmony_ci */ 902195972f6Sopenharmony_ci ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + size); 903195972f6Sopenharmony_ci LWIP_ASSERT("invalid next ptr",ptr2 != MEM_SIZE_ALIGNED); 904195972f6Sopenharmony_ci /* create mem2 struct */ 905195972f6Sopenharmony_ci mem2 = ptr_to_mem(ptr2); 906195972f6Sopenharmony_ci mem2->used = 0; 907195972f6Sopenharmony_ci mem2->next = mem->next; 908195972f6Sopenharmony_ci mem2->prev = ptr; 909195972f6Sopenharmony_ci /* and insert it between mem and mem->next */ 910195972f6Sopenharmony_ci mem->next = ptr2; 911195972f6Sopenharmony_ci mem->used = 1; 912195972f6Sopenharmony_ci 913195972f6Sopenharmony_ci if (mem2->next != MEM_SIZE_ALIGNED) { 914195972f6Sopenharmony_ci ptr_to_mem(mem2->next)->prev = ptr2; 915195972f6Sopenharmony_ci } 916195972f6Sopenharmony_ci MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); 917195972f6Sopenharmony_ci } else { 918195972f6Sopenharmony_ci /* (a mem2 struct does no fit into the user data space of mem and mem->next will always 919195972f6Sopenharmony_ci * be used at this point: if not we have 2 unused structs in a row, plug_holes should have 920195972f6Sopenharmony_ci * take care of this). 921195972f6Sopenharmony_ci * -> near fit or exact fit: do not split, no mem2 creation 922195972f6Sopenharmony_ci * also can't move mem->next directly behind mem, since mem->next 923195972f6Sopenharmony_ci * will always be used at this point! 924195972f6Sopenharmony_ci */ 925195972f6Sopenharmony_ci mem->used = 1; 926195972f6Sopenharmony_ci MEM_STATS_INC_USED(used, mem->next - mem_to_ptr(mem)); 927195972f6Sopenharmony_ci } 928195972f6Sopenharmony_ci#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 929195972f6Sopenharmony_cimem_malloc_adjust_lfree: 930195972f6Sopenharmony_ci#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 931195972f6Sopenharmony_ci if (mem == lfree) { 932195972f6Sopenharmony_ci struct mem *cur = lfree; 933195972f6Sopenharmony_ci /* Find next free block after mem and update lowest free pointer */ 934195972f6Sopenharmony_ci while (cur->used && cur != ram_end) { 935195972f6Sopenharmony_ci#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 936195972f6Sopenharmony_ci mem_free_count = 0; 937195972f6Sopenharmony_ci LWIP_MEM_ALLOC_UNPROTECT(); 938195972f6Sopenharmony_ci /* prevent high interrupt latency... */ 939195972f6Sopenharmony_ci LWIP_MEM_ALLOC_PROTECT(); 940195972f6Sopenharmony_ci if (mem_free_count != 0) { 941195972f6Sopenharmony_ci /* If mem_free or mem_trim have run, we have to restart since they 942195972f6Sopenharmony_ci could have altered our current struct mem or lfree. */ 943195972f6Sopenharmony_ci goto mem_malloc_adjust_lfree; 944195972f6Sopenharmony_ci } 945195972f6Sopenharmony_ci#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 946195972f6Sopenharmony_ci cur = ptr_to_mem(cur->next); 947195972f6Sopenharmony_ci } 948195972f6Sopenharmony_ci lfree = cur; 949195972f6Sopenharmony_ci LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); 950195972f6Sopenharmony_ci } 951195972f6Sopenharmony_ci LWIP_MEM_ALLOC_UNPROTECT(); 952195972f6Sopenharmony_ci sys_mutex_unlock(&mem_mutex); 953195972f6Sopenharmony_ci LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", 954195972f6Sopenharmony_ci (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); 955195972f6Sopenharmony_ci LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", 956195972f6Sopenharmony_ci ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); 957195972f6Sopenharmony_ci LWIP_ASSERT("mem_malloc: sanity check alignment", 958195972f6Sopenharmony_ci (((mem_ptr_t)mem) & (MEM_ALIGNMENT - 1)) == 0); 959195972f6Sopenharmony_ci 960195972f6Sopenharmony_ci#if MEM_OVERFLOW_CHECK 961195972f6Sopenharmony_ci mem_overflow_init_element(mem, size_in); 962195972f6Sopenharmony_ci#endif 963195972f6Sopenharmony_ci MEM_SANITY(); 964195972f6Sopenharmony_ci return (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET; 965195972f6Sopenharmony_ci } 966195972f6Sopenharmony_ci } 967195972f6Sopenharmony_ci#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 968195972f6Sopenharmony_ci /* if we got interrupted by a mem_free, try again */ 969195972f6Sopenharmony_ci } while (local_mem_free_count != 0); 970195972f6Sopenharmony_ci#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ 971195972f6Sopenharmony_ci MEM_STATS_INC(err); 972195972f6Sopenharmony_ci LWIP_MEM_ALLOC_UNPROTECT(); 973195972f6Sopenharmony_ci sys_mutex_unlock(&mem_mutex); 974195972f6Sopenharmony_ci LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); 975195972f6Sopenharmony_ci return NULL; 976195972f6Sopenharmony_ci} 977195972f6Sopenharmony_ci 978195972f6Sopenharmony_ci#endif /* MEM_USE_POOLS */ 979195972f6Sopenharmony_ci 980195972f6Sopenharmony_ci#if MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) 981195972f6Sopenharmony_civoid * 982195972f6Sopenharmony_cimem_calloc(mem_size_t count, mem_size_t size) 983195972f6Sopenharmony_ci{ 984195972f6Sopenharmony_ci return mem_clib_calloc(count, size); 985195972f6Sopenharmony_ci} 986195972f6Sopenharmony_ci 987195972f6Sopenharmony_ci#else /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ 988195972f6Sopenharmony_ci/** 989195972f6Sopenharmony_ci * Contiguously allocates enough space for count objects that are size bytes 990195972f6Sopenharmony_ci * of memory each and returns a pointer to the allocated memory. 991195972f6Sopenharmony_ci * 992195972f6Sopenharmony_ci * The allocated memory is filled with bytes of value zero. 993195972f6Sopenharmony_ci * 994195972f6Sopenharmony_ci * @param count number of objects to allocate 995195972f6Sopenharmony_ci * @param size size of the objects to allocate 996195972f6Sopenharmony_ci * @return pointer to allocated memory / NULL pointer if there is an error 997195972f6Sopenharmony_ci */ 998195972f6Sopenharmony_civoid * 999195972f6Sopenharmony_cimem_calloc(mem_size_t count, mem_size_t size) 1000195972f6Sopenharmony_ci{ 1001195972f6Sopenharmony_ci void *p; 1002195972f6Sopenharmony_ci size_t alloc_size = (size_t)count * (size_t)size; 1003195972f6Sopenharmony_ci 1004195972f6Sopenharmony_ci if ((size_t)(mem_size_t)alloc_size != alloc_size) { 1005195972f6Sopenharmony_ci LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_calloc: could not allocate %"SZT_F" bytes\n", alloc_size)); 1006195972f6Sopenharmony_ci return NULL; 1007195972f6Sopenharmony_ci } 1008195972f6Sopenharmony_ci 1009195972f6Sopenharmony_ci /* allocate 'count' objects of size 'size' */ 1010195972f6Sopenharmony_ci p = mem_malloc((mem_size_t)alloc_size); 1011195972f6Sopenharmony_ci if (p) { 1012195972f6Sopenharmony_ci /* zero the memory */ 1013195972f6Sopenharmony_ci memset(p, 0, alloc_size); 1014195972f6Sopenharmony_ci } 1015195972f6Sopenharmony_ci return p; 1016195972f6Sopenharmony_ci} 1017195972f6Sopenharmony_ci#endif /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ 1018