Implement possibility to declare private memory pools. This is useful to decouple some apps from the core (SNMP stack) or make contrib app useage simpler (httpserver_raw) .

This commit is contained in:
Dirk Ziegelmeier 2015-11-12 08:45:04 +01:00
parent d38db89626
commit c838e1ed5b
6 changed files with 370 additions and 281 deletions

View File

@ -66,6 +66,11 @@
#include <string.h> #include <string.h>
#if MEM_USE_POOLS #if MEM_USE_POOLS
#if MEMP_MEM_MALLOC
#error MEM_USE_POOLS and MEMP_MEM_MALLOC cannot be used together
#endif
/* lwIP head implemented with different sized pools */ /* lwIP head implemented with different sized pools */
/** /**
@ -89,7 +94,7 @@ again:
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
/* is this pool big enough to hold an element of the required size /* is this pool big enough to hold an element of the required size
plus a struct memp_malloc_helper that saves the pool this element came from? */ plus a struct memp_malloc_helper that saves the pool this element came from? */
if (required_size <= memp_sizes[poolnr]) { if (required_size <= memp_pools[poolnr]->size) {
break; break;
} }
} }
@ -119,7 +124,7 @@ again:
#if MEMP_OVERFLOW_CHECK #if MEMP_OVERFLOW_CHECK
/* initialize unused memory */ /* initialize unused memory */
element->size = size; element->size = size;
memset((u8_t*)ret + size, 0xcd, memp_sizes[poolnr] - size); memset((u8_t*)ret + size, 0xcd, memp_pools[poolnr]->size - size);
#endif /* MEMP_OVERFLOW_CHECK */ #endif /* MEMP_OVERFLOW_CHECK */
return ret; return ret;
} }
@ -150,9 +155,9 @@ mem_free(void *rmem)
{ {
u16_t i; u16_t i;
LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size", LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size",
hmem->size <= memp_sizes[hmem->poolnr]); hmem->size <= memp_pools[hmem->poolnr]->size);
/* check that unused memory remained untouched */ /* check that unused memory remained untouched */
for (i = hmem->size; i < memp_sizes[hmem->poolnr]; i++) { for (i = hmem->size; i < memp_pools[hmem->poolnr]->size; i++) {
u8_t data = *((u8_t*)rmem + i); u8_t data = *((u8_t*)rmem + i);
LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd); LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd);
} }

View File

@ -64,155 +64,47 @@
#include "lwip/nd6.h" #include "lwip/nd6.h"
#include "lwip/ip6_frag.h" #include "lwip/ip6_frag.h"
#include "lwip/mld6.h" #include "lwip/mld6.h"
#include "lwip/tcp.h"
#include "lwip/tcpip.h"
#include "lwip/priv/tcp_priv.h" #include "lwip/priv/tcp_priv.h"
#include "lwip/priv/tcpip_priv.h" #include "lwip/priv/tcpip_priv.h"
#include <string.h> #include <string.h>
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
#include "lwip/priv/memp_std.h"
struct memp { const struct memp_desc *memp_pools[MEMP_MAX] = {
struct memp *next; #define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name,
#if MEMP_OVERFLOW_CHECK
const char *file;
int line;
#endif /* MEMP_OVERFLOW_CHECK */
};
#if MEMP_OVERFLOW_CHECK
/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
* and at the end of each element, initialize them as 0xcd and check
* them later. */
/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
* every single element in each pool is checked!
* This is VERY SLOW but also very helpful. */
/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
* lwipopts.h to change the amount reserved for checking. */
#ifndef MEMP_SANITY_REGION_BEFORE
#define MEMP_SANITY_REGION_BEFORE 16
#endif /* MEMP_SANITY_REGION_BEFORE*/
#if MEMP_SANITY_REGION_BEFORE > 0
#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
#else
#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
#endif /* MEMP_SANITY_REGION_BEFORE*/
#ifndef MEMP_SANITY_REGION_AFTER
#define MEMP_SANITY_REGION_AFTER 16
#endif /* MEMP_SANITY_REGION_AFTER*/
#if MEMP_SANITY_REGION_AFTER > 0
#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
#else
#define MEMP_SANITY_REGION_AFTER_ALIGNED 0
#endif /* MEMP_SANITY_REGION_AFTER*/
/* MEMP_SIZE: save space for struct memp and for sanity check */
#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
#else /* MEMP_OVERFLOW_CHECK */
/* No sanity checks
* We don't need to preserve the struct memp while not allocated, so we
* can save a little space and set MEMP_SIZE to 0.
*/
#define MEMP_SIZE 0
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
#endif /* MEMP_OVERFLOW_CHECK */
/** This array holds the first free element of each pool.
* Elements form a linked list. */
static struct memp *memp_tab[MEMP_MAX];
#else /* MEMP_MEM_MALLOC */
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
#endif /* MEMP_MEM_MALLOC */
/** This array holds the element sizes of each pool. */
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC && !MEMP_USE_CUSTOM_POOLS
static
#endif
const u16_t memp_sizes[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
#include "lwip/priv/memp_std.h" #include "lwip/priv/memp_std.h"
}; };
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ #if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
/** This array holds the number of elements in each pool. */
static const u16_t memp_num[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) (num),
#include "lwip/priv/memp_std.h"
};
/** This array holds a textual description of each pool. */
#ifdef LWIP_DEBUG
static const char *memp_desc[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) (desc),
#include "lwip/priv/memp_std.h"
};
#endif /* LWIP_DEBUG */
#if MEMP_SEPARATE_POOLS
/** This creates each memory pool. These are named memp_memory_XXX_base (where
* XXX is the name of the pool defined in memp_std.h).
* To relocate a pool, declare it as extern in cc.h. Example for GCC:
* extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
*/
#define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
[((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))];
#include "lwip/priv/memp_std.h"
/** This array holds the base of each memory pool. */
static u8_t *const memp_bases[] = {
#define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base,
#include "lwip/priv/memp_std.h"
};
#else /* MEMP_SEPARATE_POOLS */
/** This is the actual memory used by the pools (all pools in one big block). */
static u8_t memp_memory[MEM_ALIGNMENT - 1
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
#include "lwip/priv/memp_std.h"
];
#endif /* MEMP_SEPARATE_POOLS */
#if MEMP_SANITY_CHECK #if MEMP_SANITY_CHECK
/** /**
* Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm". * Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm".
*/ */
static int static int
memp_sanity(void) memp_sanity(const struct memp_desc *desc)
{ {
s16_t i;
struct memp *t, *h; struct memp *t, *h;
for (i = 0; i < MEMP_MAX; i++) { t = *desc->tab;
t = memp_tab[i]; if (t != NULL) {
if (t != NULL) { for (h = t->next; (t != NULL) && (h != NULL); t = t->next,
for (h = t->next; (t != NULL) && (h != NULL); t = t->next, h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) {
h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) { if (t == h) {
if (t == h) { return 0;
return 0;
}
} }
} }
} }
return 1; return 1;
} }
#endif /* MEMP_SANITY_CHECK*/ #endif /* MEMP_SANITY_CHECK*/
#if MEMP_OVERFLOW_CHECK #if MEMP_OVERFLOW_CHECK
#if defined(LWIP_DEBUG) && MEMP_STATS
static const char * memp_overflow_names[] = {
#define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
#include "lwip/priv/memp_std.h"
};
#endif
/** /**
* Check if a memp element was victim of an overflow * Check if a memp element was victim of an overflow
@ -222,25 +114,16 @@ static const char * memp_overflow_names[] = {
* @param memp_type the pool p comes from * @param memp_type the pool p comes from
*/ */
static void static void
memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type) memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *desc)
{ {
u16_t k; u16_t k;
u8_t *m; u8_t *m;
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type]; m = (u8_t*)p + MEMP_SIZE + desc->size;
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
if (m[k] != 0xcd) { if (m[k] != 0xcd) {
char errstr[128] = "detected memp overflow in pool "; char errstr[128] = "detected memp overflow in pool ";
char digit[] = "0"; strcat(errstr, desc->desc);
if (memp_type >= 10) {
digit[0] = '0' + (memp_type/10);
strcat(errstr, digit);
}
digit[0] = '0' + (memp_type%10);
strcat(errstr, digit);
#if defined(LWIP_DEBUG) && MEMP_STATS
strcat(errstr, memp_overflow_names[memp_type]);
#endif
LWIP_ASSERT(errstr, 0); LWIP_ASSERT(errstr, 0);
} }
} }
@ -255,7 +138,7 @@ memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
* @param memp_type the pool p comes from * @param memp_type the pool p comes from
*/ */
static void static void
memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type) memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *desc)
{ {
u16_t k; u16_t k;
u8_t *m; u8_t *m;
@ -264,16 +147,7 @@ memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
if (m[k] != 0xcd) { if (m[k] != 0xcd) {
char errstr[128] = "detected memp underflow in pool "; char errstr[128] = "detected memp underflow in pool ";
char digit[] = "0"; strcat(errstr, desc->desc);
if (memp_type >= 10) {
digit[0] = '0' + (memp_type/10);
strcat(errstr, digit);
}
digit[0] = '0' + (memp_type%10);
strcat(errstr, digit);
#if defined(LWIP_DEBUG) && MEMP_STATS
strcat(errstr, memp_overflow_names[memp_type]);
#endif
LWIP_ASSERT(errstr, 0); LWIP_ASSERT(errstr, 0);
} }
} }
@ -291,28 +165,19 @@ memp_overflow_check_all(void)
u16_t i, j; u16_t i, j;
struct memp *p; struct memp *p;
#if !MEMP_SEPARATE_POOLS
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
#endif /* !MEMP_SEPARATE_POOLS */
for (i = 0; i < MEMP_MAX; ++i) { for (i = 0; i < MEMP_MAX; ++i) {
#if MEMP_SEPARATE_POOLS p = (struct memp *)(size_t)(memp_pools[i]->base);
p = (struct memp *)(memp_bases[i]); for (j = 0; j < memp_pools[i]->num; ++j) {
#endif /* MEMP_SEPARATE_POOLS */ memp_overflow_check_element_overflow(p, memp_pools[i]);
for (j = 0; j < memp_num[i]; ++j) { p = (struct memp*)(size_t)((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED);
memp_overflow_check_element_overflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
} }
} }
#if !MEMP_SEPARATE_POOLS
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
#endif /* !MEMP_SEPARATE_POOLS */
for (i = 0; i < MEMP_MAX; ++i) { for (i = 0; i < MEMP_MAX; ++i) {
#if MEMP_SEPARATE_POOLS p = (struct memp *)(size_t)(memp_pools[i]->base);
p = (struct memp *)(memp_bases[i]); for (j = 0; j < memp_pools[i]->num; ++j) {
#endif /* MEMP_SEPARATE_POOLS */ memp_overflow_check_element_underflow(p, memp_pools[i]);
for (j = 0; j < memp_num[i]; ++j) { p = (struct memp*)(size_t)((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED);
memp_overflow_check_element_underflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
} }
} }
} }
@ -321,34 +186,52 @@ memp_overflow_check_all(void)
* Initialize the restricted areas of all memp elements in every pool. * Initialize the restricted areas of all memp elements in every pool.
*/ */
static void static void
memp_overflow_init(void) memp_overflow_init(const struct memp_desc *desc)
{ {
u16_t i, j; u16_t i;
struct memp *p; struct memp *p;
u8_t *m; u8_t *m;
#if !MEMP_SEPARATE_POOLS p = (struct memp *)(size_t)(desc->base);
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); for (i = 0; i < desc->num; ++i) {
#endif /* !MEMP_SEPARATE_POOLS */
for (i = 0; i < MEMP_MAX; ++i) {
#if MEMP_SEPARATE_POOLS
p = (struct memp *)(memp_bases[i]);
#endif /* MEMP_SEPARATE_POOLS */
for (j = 0; j < memp_num[i]; ++j) {
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
#endif #endif
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + memp_sizes[i]; m = (u8_t*)p + MEMP_SIZE + desc->size;
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
#endif #endif
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); p = (struct memp*)(size_t)((u8_t*)p + MEMP_SIZE + desc->size + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
} }
} }
#endif /* MEMP_OVERFLOW_CHECK */ #endif /* MEMP_OVERFLOW_CHECK */
void
memp_init_pool(const struct memp_desc *desc)
{
int i;
struct memp *memp;
*desc->tab = NULL;
memp = (struct memp*)LWIP_MEM_ALIGN(desc->base);
/* create a linked list of memp elements */
for (i = 0; i < desc->num; ++i) {
memp->next = *desc->tab;
*desc->tab = memp;
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size
#if MEMP_OVERFLOW_CHECK
+ MEMP_SANITY_REGION_AFTER_ALIGNED
#endif
);
}
#if MEMP_OVERFLOW_CHECK
memp_overflow_init(desc);
#endif /* MEMP_OVERFLOW_CHECK */
}
/** /**
* Initialize this module. * Initialize this module.
* *
@ -357,43 +240,62 @@ memp_overflow_init(void)
void void
memp_init(void) memp_init(void)
{ {
struct memp *memp; u16_t i;
u16_t i, j;
for (i = 0; i < MEMP_MAX; ++i) { for (i = 0; i < MEMP_MAX; ++i) {
MEMP_STATS_AVAIL(used, i, 0); MEMP_STATS_AVAIL(used, i, 0);
MEMP_STATS_AVAIL(max, i, 0); MEMP_STATS_AVAIL(max, i, 0);
MEMP_STATS_AVAIL(err, i, 0); MEMP_STATS_AVAIL(err, i, 0);
MEMP_STATS_AVAIL(avail, i, memp_num[i]); MEMP_STATS_AVAIL(avail, i, memp_pools[i]->num);
} }
#if !MEMP_SEPARATE_POOLS
memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
#endif /* !MEMP_SEPARATE_POOLS */
/* for every pool: */ /* for every pool: */
for (i = 0; i < MEMP_MAX; ++i) { for (i = 0; i < MEMP_MAX; ++i) {
memp_tab[i] = NULL; memp_init_pool(memp_pools[i]);
#if MEMP_SEPARATE_POOLS
memp = (struct memp*)LWIP_MEM_ALIGN(memp_bases[i]);
#endif /* MEMP_SEPARATE_POOLS */
/* create a linked list of memp elements */
for (j = 0; j < memp_num[i]; ++j) {
memp->next = memp_tab[i];
memp_tab[i] = memp;
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
#if MEMP_OVERFLOW_CHECK
+ MEMP_SANITY_REGION_AFTER_ALIGNED
#endif
);
}
} }
#if MEMP_OVERFLOW_CHECK #if MEMP_OVERFLOW_CHECK
memp_overflow_init();
/* check everything a first time to see if it worked */ /* check everything a first time to see if it worked */
memp_overflow_check_all(); memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK */ #endif /* MEMP_OVERFLOW_CHECK */
} }
void *
#if !MEMP_OVERFLOW_CHECK
memp_malloc_pool(const struct memp_desc *desc)
#else
memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line)
#endif
{
struct memp *memp;
SYS_ARCH_DECL_PROTECT(old_level);
SYS_ARCH_PROTECT(old_level);
memp = *desc->tab;
#if MEMP_OVERFLOW_CHECK == 1
memp_overflow_check_element_overflow(memp, desc);
memp_overflow_check_element_underflow(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */
if (memp != NULL) {
*desc->tab = memp->next;
#if MEMP_OVERFLOW_CHECK
memp->next = NULL;
memp->file = file;
memp->line = line;
#endif /* MEMP_OVERFLOW_CHECK */
LWIP_ASSERT("memp_malloc: memp properly aligned",
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
}
SYS_ARCH_UNPROTECT(old_level);
return memp;
}
/** /**
* Get an element from a specific pool. * Get an element from a specific pool.
* *
@ -412,31 +314,30 @@ memp_malloc(memp_t type)
memp_malloc_fn(memp_t type, const char* file, const int line) memp_malloc_fn(memp_t type, const char* file, const int line)
#endif #endif
{ {
struct memp *memp; void *memp;
SYS_ARCH_DECL_PROTECT(old_level); SYS_ARCH_DECL_PROTECT(old_level);
LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;); LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
SYS_ARCH_PROTECT(old_level); SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK >= 2 #if MEMP_OVERFLOW_CHECK >= 2
memp_overflow_check_all(); memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */ #endif /* MEMP_OVERFLOW_CHECK >= 2 */
memp = memp_tab[type]; #if !MEMP_OVERFLOW_CHECK
memp = memp_malloc_pool(memp_pools[type]);
#else
memp = memp_malloc_pool_fn(memp_pools[type], file, line);
#endif
if (memp != NULL) { if (memp != NULL) {
memp_tab[type] = memp->next; MEMP_STATS_INC(used, type);
#if MEMP_OVERFLOW_CHECK if(MEMP_STATS_GET(used, type) > MEMP_STATS_GET(max, type)) {
memp->next = NULL; MEMP_STATS_AVAIL(max, type, MEMP_STATS_GET(used, type));
memp->file = file; }
memp->line = line;
#endif /* MEMP_OVERFLOW_CHECK */
MEMP_STATS_INC_USED(used, type);
LWIP_ASSERT("memp_malloc: memp properly aligned",
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
} else { } else {
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type])); LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_pools[type]->desc));
MEMP_STATS_INC(err, type); MEMP_STATS_INC(err, type);
} }
@ -445,14 +346,8 @@ memp_malloc_fn(memp_t type, const char* file, const int line)
return memp; return memp;
} }
/**
* Put an element back into its pool.
*
* @param type the pool where to put mem
* @param mem the memp element to free
*/
void void
memp_free(memp_t type, void *mem) memp_free_pool(const struct memp_desc* desc, void *mem)
{ {
struct memp *memp; struct memp *memp;
#ifdef LWIP_HOOK_MEMP_AVAILABLE #ifdef LWIP_HOOK_MEMP_AVAILABLE
@ -469,28 +364,53 @@ memp_free(memp_t type, void *mem)
memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE); memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
SYS_ARCH_PROTECT(old_level); SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK
#if MEMP_OVERFLOW_CHECK >= 2 #if MEMP_OVERFLOW_CHECK == 2
memp_overflow_check_all(); memp_overflow_check_element_overflow(memp, desc);
#else memp_overflow_check_element_underflow(memp, desc);
memp_overflow_check_element_overflow(memp, type);
memp_overflow_check_element_underflow(memp, type);
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
#endif /* MEMP_OVERFLOW_CHECK */ #endif /* MEMP_OVERFLOW_CHECK */
MEMP_STATS_DEC(used, type); memp->next = *desc->tab;
memp->next = memp_tab[type];
#ifdef LWIP_HOOK_MEMP_AVAILABLE #ifdef LWIP_HOOK_MEMP_AVAILABLE
old_first = memp_tab[type]; old_first = *desc->tab;
#endif #endif
memp_tab[type] = memp; *desc->tab = memp;
#if MEMP_SANITY_CHECK #if MEMP_SANITY_CHECK
LWIP_ASSERT("memp sanity", memp_sanity()); LWIP_ASSERT("memp sanity", memp_sanity(desc));
#endif /* MEMP_SANITY_CHECK */ #endif /* MEMP_SANITY_CHECK */
SYS_ARCH_UNPROTECT(old_level); SYS_ARCH_UNPROTECT(old_level);
}
/**
* Put an element back into its pool.
*
* @param type the pool where to put mem
* @param mem the memp element to free
*/
void
memp_free(memp_t type, void *mem)
{
#ifdef LWIP_HOOK_MEMP_AVAILABLE
struct memp *old_first;
#endif
SYS_ARCH_DECL_PROTECT(old_level);
LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;);
SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK >= 2
memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
MEMP_STATS_DEC(used, type);
memp_free_pool(memp_pools[type], mem);
SYS_ARCH_UNPROTECT(old_level);
#ifdef LWIP_HOOK_MEMP_AVAILABLE #ifdef LWIP_HOOK_MEMP_AVAILABLE
if (old_first == NULL) { if (old_first == NULL) {
LWIP_HOOK_MEMP_AVAILABLE(type); LWIP_HOOK_MEMP_AVAILABLE(type);

View File

@ -33,8 +33,6 @@
#ifndef LWIP_HDR_MEMP_H #ifndef LWIP_HDR_MEMP_H
#define LWIP_HDR_MEMP_H #define LWIP_HDR_MEMP_H
#include "lwip/opt.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -50,49 +48,60 @@ typedef enum {
MEMP_MAX MEMP_MAX
} memp_t; } memp_t;
#if MEM_USE_POOLS #include "lwip/priv/memp_priv.h"
/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */
typedef enum {
/* Get the first (via:
MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/
MEMP_POOL_HELPER_FIRST = ((u8_t)
#define LWIP_MEMPOOL(name,num,size,desc)
#define LWIP_MALLOC_MEMPOOL_START 1
#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0
#define LWIP_MALLOC_MEMPOOL_END
#include "lwip/priv/memp_std.h"
) ,
/* Get the last (via:
MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */
MEMP_POOL_HELPER_LAST = ((u8_t)
#define LWIP_MEMPOOL(name,num,size,desc)
#define LWIP_MALLOC_MEMPOOL_START
#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *
#define LWIP_MALLOC_MEMPOOL_END 1
#include "lwip/priv/memp_std.h"
)
} memp_pool_helper_t;
/* The actual start and stop values are here (cast them over) /* Private mempools example:
We use this helper type and these defines so we can avoid using const memp_t values */ * .h: only when pool is used in multiple .c files: LWIP_MEMPOOL_PROTOTYPE(my_private_pool);
#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) * .c:
#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) * - in global variables section: LWIP_MEMPOOL_DECLARE(my_private_pool, 10, sizeof(foo), "Some description")
#endif /* MEM_USE_POOLS */ * - call ONCE before using pool (e.g. in some init() function): LWIP_MEMPOOL_INIT(my_private_pool);
* - allocate: void* my_new_mem = LWIP_MEMPOOL_ALLOC(my_private_pool);
* - free: LWIP_MEMPOOL_FREE(my_private_pool, my_new_mem);
*
* To relocate a pool, declare it as extern in cc.h. Example for GCC:
* extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_my_private_pool[];
*/
#if MEMP_MEM_MALLOC || MEM_USE_POOLS || MEMP_USE_CUSTOM_POOLS extern const struct memp_desc *memp_pools[MEMP_MAX];
extern const u16_t memp_sizes[MEMP_MAX];
#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS || MEMP_USE_CUSTOM_POOLS */ #define LWIP_MEMPOOL_PROTOTYPE(name) extern const struct memp_desc *memp_ ## name
#if MEMP_MEM_MALLOC #if MEMP_MEM_MALLOC
#include "mem.h" #include "lwip/mem.h"
#define memp_init() #define memp_init()
#define memp_malloc(type) mem_malloc(memp_sizes[type]) #define memp_malloc(type) mem_malloc(memp_pools[type]->size)
#define memp_free(type, mem) mem_free(mem) #define memp_free(type, mem) mem_free(mem)
#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \
const struct memp_desc memp_ ## name = { \
LWIP_MEM_ALIGN_SIZE(size) \
};
#define LWIP_MEMPOOL_INIT(name)
#define LWIP_MEMPOOL_ALLOC(name) mem_malloc(memp_ ## name.size)
#define LWIP_MEMPOOL_FREE(name, x) mem_free(x)
#else /* MEMP_MEM_MALLOC */ #else /* MEMP_MEM_MALLOC */
#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
[((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; \
\
static struct memp *memp_tab_ ## name; \
\
const struct memp_desc memp_ ## name = { \
LWIP_MEM_ALIGN_SIZE(size), \
(num), \
DECLARE_LWIP_MEMPOOL_DESC(desc) \
memp_memory_ ## name ## _base, \
&memp_tab_ ## name \
};
#define LWIP_MEMPOOL_INIT(name) memp_init_pool(&memp_ ## name)
#define LWIP_MEMPOOL_ALLOC(name) memp_malloc_pool(&memp_ ## name)
#define LWIP_MEMPOOL_FREE(name, x) memp_free_pool(&memp_ ## name, (x))
#if MEM_USE_POOLS #if MEM_USE_POOLS
/** This structure is used to save the pool one element came from. */ /** This structure is used to save the pool one element came from. */
struct memp_malloc_helper struct memp_malloc_helper
@ -102,6 +111,7 @@ struct memp_malloc_helper
u16_t size; u16_t size;
#endif /* MEMP_OVERFLOW_CHECK */ #endif /* MEMP_OVERFLOW_CHECK */
}; };
#endif /* MEM_USE_POOLS */ #endif /* MEM_USE_POOLS */
void memp_init(void); void memp_init(void);

View File

@ -142,15 +142,6 @@
#define MEM_SIZE 1600 #define MEM_SIZE 1600
#endif #endif
/**
* MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array.
* This can be used to individually change the location of each pool.
* Default is one big array for all pools
*/
#ifndef MEMP_SEPARATE_POOLS
#define MEMP_SEPARATE_POOLS 0
#endif
/** /**
* MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable
* amount of bytes before and after each memp element in every pool and fills * amount of bytes before and after each memp element in every pool and fills

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_HDR_MEMP_PRIV_H
#define LWIP_HDR_MEMP_PRIV_H
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
#if MEMP_OVERFLOW_CHECK
/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
* and at the end of each element, initialize them as 0xcd and check
* them later. */
/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
* every single element in each pool is checked!
* This is VERY SLOW but also very helpful. */
/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
* lwipopts.h to change the amount reserved for checking. */
#ifndef MEMP_SANITY_REGION_BEFORE
#define MEMP_SANITY_REGION_BEFORE 16
#endif /* MEMP_SANITY_REGION_BEFORE*/
#if MEMP_SANITY_REGION_BEFORE > 0
#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
#else
#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
#endif /* MEMP_SANITY_REGION_BEFORE*/
#ifndef MEMP_SANITY_REGION_AFTER
#define MEMP_SANITY_REGION_AFTER 16
#endif /* MEMP_SANITY_REGION_AFTER*/
#if MEMP_SANITY_REGION_AFTER > 0
#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
#else
#define MEMP_SANITY_REGION_AFTER_ALIGNED 0
#endif /* MEMP_SANITY_REGION_AFTER*/
/* MEMP_SIZE: save space for struct memp and for sanity check */
#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
#else /* MEMP_OVERFLOW_CHECK */
/* No sanity checks
* We don't need to preserve the struct memp while not allocated, so we
* can save a little space and set MEMP_SIZE to 0.
*/
#define MEMP_SIZE 0
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
#endif /* MEMP_OVERFLOW_CHECK */
struct memp {
struct memp *next;
#if MEMP_OVERFLOW_CHECK
const char *file;
int line;
#endif /* MEMP_OVERFLOW_CHECK */
};
#if MEM_USE_POOLS
/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */
typedef enum {
/* Get the first (via:
MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/
MEMP_POOL_HELPER_FIRST = ((u8_t)
#define LWIP_MEMPOOL(name,num,size,desc)
#define LWIP_MALLOC_MEMPOOL_START 1
#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0
#define LWIP_MALLOC_MEMPOOL_END
#include "lwip/priv/memp_std.h"
) ,
/* Get the last (via:
MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */
MEMP_POOL_HELPER_LAST = ((u8_t)
#define LWIP_MEMPOOL(name,num,size,desc)
#define LWIP_MALLOC_MEMPOOL_START
#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *
#define LWIP_MALLOC_MEMPOOL_END 1
#include "lwip/priv/memp_std.h"
)
} memp_pool_helper_t;
/* The actual start and stop values are here (cast them over)
We use this helper type and these defines so we can avoid using const memp_t values */
#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)
#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST)
#endif /* MEM_USE_POOLS */
struct memp_desc {
/** Element size */
u16_t size;
#if !MEMP_MEM_MALLOC
/** Number of elements */
u16_t num;
#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK
/** Textual description */
const char *desc;
#endif /* LWIP_DEBUG || MEMP_OVERFLOW_CHECK */
/** Base */
u8_t *base;
/** First free element of each pool. Elements form a linked list. */
struct memp **tab;
#endif /* MEMP_MEM_MALLOC */
};
#ifdef LWIP_DEBUG
#define DECLARE_LWIP_MEMPOOL_DESC(desc) (desc),
#else
#define DECLARE_LWIP_MEMPOOL_DESC(desc)
#endif
void memp_init_pool(const struct memp_desc *desc);
#if MEMP_OVERFLOW_CHECK
void *memp_malloc_pool_fn(const struct memp_desc* desc, const char* file, const int line);
#define memp_malloc_pool(d) memp_malloc_pool_fn((d), __FILE__, __LINE__)
#else
void *memp_malloc_pool(const struct memp_desc *desc);
#endif
void memp_free_pool(const struct memp_desc* desc, void *mem);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_MEMP_PRIV_H */

View File

@ -339,12 +339,14 @@ void stats_init(void);
#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) #define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x)
#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1) #define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1)
#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) #define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i)
#define MEMP_STATS_GET(x, i) STATS_GET(memp[i].x)
#else #else
#define MEMP_STATS_AVAIL(x, i, y) #define MEMP_STATS_AVAIL(x, i, y)
#define MEMP_STATS_INC(x, i) #define MEMP_STATS_INC(x, i)
#define MEMP_STATS_DEC(x, i) #define MEMP_STATS_DEC(x, i)
#define MEMP_STATS_INC_USED(x, i) #define MEMP_STATS_INC_USED(x, i)
#define MEMP_STATS_DISPLAY(i) #define MEMP_STATS_DISPLAY(i)
#define MEMP_STATS_GET(x, i) 0
#endif #endif
#if SYS_STATS #if SYS_STATS