++ New features:
+ 2007-06-21 Simon Goldschmidt
+ * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option
+ MEM_USE_POOLS to use 4 pools with different sized elements instead of a
+ heap. This both prevents memory fragmentation and gives a higher speed
+ at the cost of more memory consumption. Turned off by default.
+
2007-06-21 Simon Goldschmidt
* api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of
netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into
#include "lwip/stats.h"
-#if (MEM_LIBC_MALLOC == 0)
+#if !MEM_LIBC_MALLOC
+#if MEM_USE_POOLS
+/* lwIP head implemented with different sized pools */
+
+/**
+ * This structure is used to save the pool one element came from.
+ */
+struct mem_helper
+{
+ memp_t poolnr;
+};
+
+/**
+ * Allocate memory: determine the smallest pool that is big enough
+ * to contain an element of 'size' and get an element from that pool.
+ *
+ * @param size the size in bytes of the memory needed
+ * @return a pointer to the allocated memory or NULL if the pool is empty
+ */
+void *
+mem_malloc(mem_size_t size)
+{
+ struct mem_helper *element;
+ int poolnr = -1;
+
+ for (poolnr = MEMP_MEM_POOL_1; poolnr < (MEMP_MEM_POOL_1 + MEM_POOL_COUNT); poolnr++) {
+ if ((size + sizeof(struct mem_helper)) <= memp_sizes[poolnr]) {
+ break;
+ }
+ }
+ if (poolnr == -1) {
+ LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
+ return NULL;
+ }
+ element = (struct mem_helper*)memp_malloc(poolnr);
+ if (element == NULL) {
+ /* No need to DEBUGF or ASSERT: This error is already
+ taken care of in memp.c */
+ /** @todo: we could try a bigger pool if this one is empty! */
+ return NULL;
+ }
+
+ element->poolnr = poolnr;
+ element++;
+
+ return element;
+}
+
+/**
+ * Free memory previously allocated by mem_malloc. Loads the pool number
+ * and calls memp_free with that pool number to put the element back into
+ * its pool
+ *
+ * @param rmem the memory element to free
+ */
+void
+mem_free(void *rmem)
+{
+ struct mem_helper *hmem = (struct mem_helper*)rmem;
+
+ LWIP_ASSERT("rmem != NULL", (rmem != NULL));
+ LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == MEM_ALIGN(rmem)));
+
+ hmem--;
+
+ LWIP_ASSERT("hmem != NULL", (hmem != NULL));
+ LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == MEM_ALIGN(hmem)));
+ LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
+
+ memp_free(hmem->poolnr, hmem);
+}
+
+#else /* MEM_USE_POOLS */
/* lwIP replacement for your libc malloc() */
/* This does not have to be aligned since for getting its size,
return NULL;
}
-#endif /* MEM_LIBC_MALLOC == 0 */
-
+#endif /* MEM_USE_POOLS */
+#endif /* !MEM_LIBC_MALLOC */
#endif /* MEMP_OVERFLOW_CHECK */
-static const u16_t memp_sizes[MEMP_MAX] = {
+#if !MEM_USE_POOLS
+static
+#endif
+const u16_t memp_sizes[MEMP_MAX] = {
MEMP_ALIGN_SIZE(sizeof(struct pbuf)),
MEMP_ALIGN_SIZE(sizeof(struct raw_pcb)),
MEMP_ALIGN_SIZE(sizeof(struct udp_pcb)),
MEMP_ALIGN_SIZE(sizeof(struct etharp_q_entry)),
#endif
MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(PBUF_POOL_BUFSIZE),
- MEMP_ALIGN_SIZE(sizeof(struct sys_timeo))
+ MEMP_ALIGN_SIZE(sizeof(struct sys_timeo)),
+#if MEM_USE_POOLS
+ MEMP_ALIGN_SIZE(MEM_POOL_SIZE_1),
+ MEMP_ALIGN_SIZE(MEM_POOL_SIZE_2),
+ MEMP_ALIGN_SIZE(MEM_POOL_SIZE_3),
+ MEMP_ALIGN_SIZE(MEM_POOL_SIZE_4),
+#endif
};
static const u16_t memp_num[MEMP_MAX] = {
MEMP_NUM_ARP_QUEUE,
#endif
PBUF_POOL_SIZE,
- MEMP_NUM_SYS_TIMEOUT
+ MEMP_NUM_SYS_TIMEOUT,
+#if MEM_USE_POOLS
+ MEM_POOL_NUM_1,
+ MEM_POOL_NUM_2,
+ MEM_POOL_NUM_3,
+ MEM_POOL_NUM_4,
+#endif
};
#define MEMP_TYPE_SIZE(qty, type) \
MEMP_TYPE_SIZE(MEMP_NUM_ARP_QUEUE, struct etharp_q_entry) +
#endif
MEMP_TYPE_SIZE(PBUF_POOL_SIZE, struct pbuf) +
- PBUF_POOL_SIZE * MEMP_ALIGN_SIZE(PBUF_POOL_BUFSIZE) +
- MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)];
+ ((PBUF_POOL_SIZE) * MEMP_ALIGN_SIZE(PBUF_POOL_BUFSIZE)) +
+ MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)
+#if MEM_USE_POOLS
+ + ((MEM_POOL_NUM_1) * MEMP_ALIGN_SIZE(MEM_POOL_SIZE_1))
+ + ((MEM_POOL_NUM_2) * MEMP_ALIGN_SIZE(MEM_POOL_SIZE_2))
+ + ((MEM_POOL_NUM_3) * MEMP_ALIGN_SIZE(MEM_POOL_SIZE_3))
+ + ((MEM_POOL_NUM_4) * MEMP_ALIGN_SIZE(MEM_POOL_SIZE_4))
+#endif
+];
#if MEMP_SANITY_CHECK
/**
#define mem_realloc(x, size) realloc(x,size)
#endif
#else /* MEM_LIBC_MALLOC */
+#if MEM_USE_POOLS
+/** The pool implementation of the heap currently uses 4 pools */
+#define MEM_POOL_COUNT 4
+/** mem_init is not used when using pools instead of a heap */
+#define mem_init()
+/** mem_realloc is not used when using pools instead of a heap:
+ we can't free part of a pool element and don't want to copy the rest */
+#define mem_realloc(mem, size) (mem)
+#else /* MEM_USE_POOLS */
/* lwIP alternative malloc */
void mem_init(void);
+void *mem_realloc(void *mem, mem_size_t size);
+#endif /* MEM_USE_POOLS */
void *mem_malloc(mem_size_t size);
void mem_free(void *mem);
-void *mem_realloc(void *mem, mem_size_t size);
#endif /* MEM_LIBC_MALLOC */
#ifndef LWIP_MEM_ALIGN_SIZE
#endif
MEMP_PBUF_POOL,
MEMP_SYS_TIMEOUT,
+#if MEM_USE_POOLS
+ MEMP_MEM_POOL_1,
+ MEMP_MEM_POOL_2,
+ MEMP_MEM_POOL_3,
+ MEMP_MEM_POOL_4,
+#endif
MEMP_MAX
} memp_t;
#endif
void memp_free(memp_t type, void *mem);
+#if MEM_USE_POOLS
+extern const u16_t memp_sizes[MEMP_MAX];
+#endif
+
#ifdef __cplusplus
}
#endif
#endif
/* ---------- Memory options ---------- */
+/* Use malloc/free/realloc provided by your C-library instead of the
+ lwip internal allocator. Can save code size if you already use it. */
#ifndef MEM_LIBC_MALLOC
#define MEM_LIBC_MALLOC 0
#endif
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
byte alignment -> define MEM_ALIGNMENT to 2. */
-
#ifndef MEM_ALIGNMENT
#define MEM_ALIGNMENT 1
#endif
+/* Memory can be allocated from 4 pools with element of different size.
+ When mem_malloc is called, and element of the smallest pool that can
+ provide the lenght needed is returned. */
+#ifndef MEM_USE_POOLS
+#define MEM_USE_POOLS 0
+#endif
+
+#if MEM_USE_POOLS
+/* The element sizes of the 4 pools.
+ The sizes must be increasing, e.g. the elements in pool 2 must be
+ bigger than the elements in pool 1 and so on. If this is not the case,
+ mem_malloc will not work correctly. */
+#ifndef MEM_POOL_SIZE_1
+#error You must have at least one pool if MEM_USE_POOLS is set to 1!
+#endif
+#ifndef MEM_POOL_SIZE_2
+#define MEM_POOL_SIZE_2 0
+#endif
+#ifndef MEM_POOL_SIZE_3
+#define MEM_POOL_SIZE_3 0
+#endif
+#ifndef MEM_POOL_SIZE_4
+#define MEM_POOL_SIZE_4 0
+#endif
+/* The element count of the 4 pools */
+#ifndef MEM_POOL_NUM_1
+#error You must have at least one pool if MEM_USE_POOLS is set to 1!
+#endif
+#ifndef MEM_POOL_NUM_2
+#define MEM_POOL_NUM_2 0
+#endif
+#ifndef MEM_POOL_NUM_3
+#define MEM_POOL_NUM_3 0
+#endif
+#ifndef MEM_POOL_NUM_4
+#define MEM_POOL_NUM_4 0
+#endif
+#endif
+
/* MEM_SIZE: the size of the heap memory. If the application will send
-a lot of data that needs to be copied, this should be set high. */
+ a lot of data that needs to be copied, this should be set high. */
#ifndef MEM_SIZE
#define MEM_SIZE 1600
#endif