3 * Dynamic pool memory manager
5 * lwIP has dedicated pools for many structures (netconn, protocol control blocks,
6 * packet buffers, ...). All these pools are managed here.
10 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or without modification,
14 * are permitted provided that the following conditions are met:
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * 3. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 * This file is part of the lwIP TCP/IP stack.
37 * Author: Adam Dunkels <adam@sics.se>
43 #include "lwip/memp.h"
44 #include "lwip/pbuf.h"
47 #include "lwip/tcp_impl.h"
48 #include "lwip/igmp.h"
50 #include "lwip/api_msg.h"
51 #include "lwip/tcpip.h"
53 #include "lwip/timers.h"
54 #include "lwip/stats.h"
55 #include "netif/etharp.h"
56 #include "lwip/ip_frag.h"
57 #include "lwip/snmp_structs.h"
58 #include "lwip/snmp_msg.h"
60 #include "netif/ppp_oe.h"
64 #if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
68 #if MEMP_OVERFLOW_CHECK
71 #endif /* MEMP_OVERFLOW_CHECK */
74 #if MEMP_OVERFLOW_CHECK
75 /* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
76 * and at the end of each element, initialize them as 0xcd and check
78 /* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
79 * every single element in each pool is checked!
80 * This is VERY SLOW but also very helpful. */
81 /* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
82 * lwipopts.h to change the amount reserved for checking. */
83 #ifndef MEMP_SANITY_REGION_BEFORE
84 #define MEMP_SANITY_REGION_BEFORE 16
85 #endif /* MEMP_SANITY_REGION_BEFORE*/
86 #if MEMP_SANITY_REGION_BEFORE > 0
87 #define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
89 #define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
90 #endif /* MEMP_SANITY_REGION_BEFORE*/
91 #ifndef MEMP_SANITY_REGION_AFTER
92 #define MEMP_SANITY_REGION_AFTER 16
93 #endif /* MEMP_SANITY_REGION_AFTER*/
94 #if MEMP_SANITY_REGION_AFTER > 0
95 #define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
97 #define MEMP_SANITY_REGION_AFTER_ALIGNED 0
98 #endif /* MEMP_SANITY_REGION_AFTER*/
100 /* MEMP_SIZE: save space for struct memp and for sanity check */
101 #define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
102 #define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
104 #else /* MEMP_OVERFLOW_CHECK */
107 * We don't need to preserve the struct memp while not allocated, so we
108 * can save a little space and set MEMP_SIZE to 0.
111 #define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
113 #endif /* MEMP_OVERFLOW_CHECK */
115 /** This array holds the first free element of each pool.
116 * Elements form a linked list. */
117 static struct memp
*memp_tab
[MEMP_MAX
];
119 #else /* MEMP_MEM_MALLOC */
121 #define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
123 #endif /* MEMP_MEM_MALLOC */
125 /** This array holds the element sizes of each pool. */
126 #if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
129 const u16_t memp_sizes
[MEMP_MAX
] = {
130 #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
131 #include "lwip/memp_std.h"
134 #if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
136 /** This array holds the number of elements in each pool. */
137 static const u16_t memp_num
[MEMP_MAX
] = {
138 #define LWIP_MEMPOOL(name,num,size,desc) (num),
139 #include "lwip/memp_std.h"
142 /** This array holds a textual description of each pool. */
144 static const char *memp_desc
[MEMP_MAX
] = {
145 #define LWIP_MEMPOOL(name,num,size,desc) (desc),
146 #include "lwip/memp_std.h"
148 #endif /* LWIP_DEBUG */
150 #if MEMP_SEPARATE_POOLS
152 /** This creates each memory pool. These are named memp_memory_XXX_base (where
153 * XXX is the name of the pool defined in memp_std.h).
154 * To relocate a pool, declare it as extern in cc.h. Example for GCC:
155 * extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
157 #define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
158 [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))];
159 #include "lwip/memp_std.h"
161 /** This array holds the base of each memory pool. */
162 static u8_t
*const memp_bases
[] = {
163 #define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base,
164 #include "lwip/memp_std.h"
167 #else /* MEMP_SEPARATE_POOLS */
169 #if defined(TARGET_LPC1768)
170 # define ETHMEM_SECTION __attribute((section("AHBSRAM1")))
172 # define ETHMEM_SECTION
175 /** This is the actual memory used by the pools (all pools in one big block). */
176 static u8_t memp_memory
[MEM_ALIGNMENT
- 1
177 #define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
178 #include "lwip/memp_std.h"
181 #endif /* MEMP_SEPARATE_POOLS */
183 #if MEMP_SANITY_CHECK
185 * Check that memp-lists don't form a circle
193 for (i
= 0; i
< MEMP_MAX
; i
++) {
194 for (m
= memp_tab
[i
]; m
!= NULL
; m
= m
->next
) {
196 for (n
= memp_tab
[i
]; n
!= NULL
; n
= n
->next
) {
197 if (n
== m
&& --c
< 0) {
205 #endif /* MEMP_SANITY_CHECK*/
206 #if MEMP_OVERFLOW_CHECK
207 #if defined(LWIP_DEBUG) && MEMP_STATS
208 static const char * memp_overflow_names
[] = {
209 #define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
210 #include "lwip/memp_std.h"
215 * Check if a memp element was victim of an overflow
216 * (e.g. the restricted area after it has been altered)
218 * @param p the memp element to check
219 * @param memp_type the pool p comes from
222 memp_overflow_check_element_overflow(struct memp
*p
, u16_t memp_type
)
226 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
227 m
= (u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[memp_type
];
228 for (k
= 0; k
< MEMP_SANITY_REGION_AFTER_ALIGNED
; k
++) {
230 char errstr
[128] = "detected memp overflow in pool ";
232 if(memp_type
>= 10) {
233 digit
[0] = '0' + (memp_type
/10);
234 strcat(errstr
, digit
);
236 digit
[0] = '0' + (memp_type
%10);
237 strcat(errstr
, digit
);
238 #if defined(LWIP_DEBUG) && MEMP_STATS
239 strcat(errstr
, memp_overflow_names
[memp_type
]);
241 LWIP_ASSERT(errstr
, 0);
248 * Check if a memp element was victim of an underflow
249 * (e.g. the restricted area before it has been altered)
251 * @param p the memp element to check
252 * @param memp_type the pool p comes from
255 memp_overflow_check_element_underflow(struct memp
*p
, u16_t memp_type
)
259 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
260 m
= (u8_t
*)p
+ MEMP_SIZE
- MEMP_SANITY_REGION_BEFORE_ALIGNED
;
261 for (k
= 0; k
< MEMP_SANITY_REGION_BEFORE_ALIGNED
; k
++) {
263 char errstr
[128] = "detected memp underflow in pool ";
265 if(memp_type
>= 10) {
266 digit
[0] = '0' + (memp_type
/10);
267 strcat(errstr
, digit
);
269 digit
[0] = '0' + (memp_type
%10);
270 strcat(errstr
, digit
);
271 #if defined(LWIP_DEBUG) && MEMP_STATS
272 strcat(errstr
, memp_overflow_names
[memp_type
]);
274 LWIP_ASSERT(errstr
, 0);
281 * Do an overflow check for all elements in every pool.
283 * @see memp_overflow_check_element for a description of the check
286 memp_overflow_check_all(void)
291 p
= (struct memp
*)LWIP_MEM_ALIGN(memp_memory
);
292 for (i
= 0; i
< MEMP_MAX
; ++i
) {
294 for (j
= 0; j
< memp_num
[i
]; ++j
) {
295 memp_overflow_check_element_overflow(p
, i
);
296 p
= (struct memp
*)((u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[i
] + MEMP_SANITY_REGION_AFTER_ALIGNED
);
299 p
= (struct memp
*)LWIP_MEM_ALIGN(memp_memory
);
300 for (i
= 0; i
< MEMP_MAX
; ++i
) {
302 for (j
= 0; j
< memp_num
[i
]; ++j
) {
303 memp_overflow_check_element_underflow(p
, i
);
304 p
= (struct memp
*)((u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[i
] + MEMP_SANITY_REGION_AFTER_ALIGNED
);
310 * Initialize the restricted areas of all memp elements in every pool.
313 memp_overflow_init(void)
319 p
= (struct memp
*)LWIP_MEM_ALIGN(memp_memory
);
320 for (i
= 0; i
< MEMP_MAX
; ++i
) {
322 for (j
= 0; j
< memp_num
[i
]; ++j
) {
323 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
324 m
= (u8_t
*)p
+ MEMP_SIZE
- MEMP_SANITY_REGION_BEFORE_ALIGNED
;
325 memset(m
, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED
);
327 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
328 m
= (u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[i
];
329 memset(m
, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED
);
331 p
= (struct memp
*)((u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[i
] + MEMP_SANITY_REGION_AFTER_ALIGNED
);
335 #endif /* MEMP_OVERFLOW_CHECK */
338 * Initialize this module.
340 * Carves out memp_memory into linked lists for each pool-type.
348 for (i
= 0; i
< MEMP_MAX
; ++i
) {
349 MEMP_STATS_AVAIL(used
, i
, 0);
350 MEMP_STATS_AVAIL(max
, i
, 0);
351 MEMP_STATS_AVAIL(err
, i
, 0);
352 MEMP_STATS_AVAIL(avail
, i
, memp_num
[i
]);
355 #if !MEMP_SEPARATE_POOLS
356 memp
= (struct memp
*)LWIP_MEM_ALIGN(memp_memory
);
357 #endif /* !MEMP_SEPARATE_POOLS */
358 /* for every pool: */
359 for (i
= 0; i
< MEMP_MAX
; ++i
) {
361 #if MEMP_SEPARATE_POOLS
362 memp
= (struct memp
*)memp_bases
[i
];
363 #endif /* MEMP_SEPARATE_POOLS */
364 /* create a linked list of memp elements */
365 for (j
= 0; j
< memp_num
[i
]; ++j
) {
366 memp
->next
= memp_tab
[i
];
368 memp
= (struct memp
*)(void *)((u8_t
*)memp
+ MEMP_SIZE
+ memp_sizes
[i
]
369 #if MEMP_OVERFLOW_CHECK
370 + MEMP_SANITY_REGION_AFTER_ALIGNED
375 #if MEMP_OVERFLOW_CHECK
376 memp_overflow_init();
377 /* check everything a first time to see if it worked */
378 memp_overflow_check_all();
379 #endif /* MEMP_OVERFLOW_CHECK */
383 * Get an element from a specific pool.
385 * @param type the pool to get an element from
387 * the debug version has two more parameters:
388 * @param file file name calling this function
389 * @param line number of line where this function is called
391 * @return a pointer to the allocated memory or a NULL pointer on error
394 #if !MEMP_OVERFLOW_CHECK
395 memp_malloc(memp_t type
)
397 memp_malloc_fn(memp_t type
, const char* file
, const int line
)
401 SYS_ARCH_DECL_PROTECT(old_level
);
403 LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type
< MEMP_MAX
), return NULL
;);
405 SYS_ARCH_PROTECT(old_level
);
406 #if MEMP_OVERFLOW_CHECK >= 2
407 memp_overflow_check_all();
408 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
410 memp
= memp_tab
[type
];
413 memp_tab
[type
] = memp
->next
;
414 #if MEMP_OVERFLOW_CHECK
418 #endif /* MEMP_OVERFLOW_CHECK */
419 MEMP_STATS_INC_USED(used
, type
);
420 LWIP_ASSERT("memp_malloc: memp properly aligned",
421 ((mem_ptr_t
)memp
% MEM_ALIGNMENT
) == 0);
422 memp
= (struct memp
*)(void *)((u8_t
*)memp
+ MEMP_SIZE
);
424 LWIP_DEBUGF(MEMP_DEBUG
| LWIP_DBG_LEVEL_SERIOUS
, ("memp_malloc: out of memory in pool %s\n", memp_desc
[type
]));
425 MEMP_STATS_INC(err
, type
);
428 SYS_ARCH_UNPROTECT(old_level
);
434 * Put an element back into its pool.
436 * @param type the pool where to put mem
437 * @param mem the memp element to free
440 memp_free(memp_t type
, void *mem
)
443 SYS_ARCH_DECL_PROTECT(old_level
);
448 LWIP_ASSERT("memp_free: mem properly aligned",
449 ((mem_ptr_t
)mem
% MEM_ALIGNMENT
) == 0);
451 memp
= (struct memp
*)(void *)((u8_t
*)mem
- MEMP_SIZE
);
453 SYS_ARCH_PROTECT(old_level
);
454 #if MEMP_OVERFLOW_CHECK
455 #if MEMP_OVERFLOW_CHECK >= 2
456 memp_overflow_check_all();
458 memp_overflow_check_element_overflow(memp
, type
);
459 memp_overflow_check_element_underflow(memp
, type
);
460 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
461 #endif /* MEMP_OVERFLOW_CHECK */
463 MEMP_STATS_DEC(used
, type
);
465 memp
->next
= memp_tab
[type
];
466 memp_tab
[type
] = memp
;
468 #if MEMP_SANITY_CHECK
469 LWIP_ASSERT("memp sanity", memp_sanity());
470 #endif /* MEMP_SANITY_CHECK */
472 SYS_ARCH_UNPROTECT(old_level
);
475 #endif /* MEMP_MEM_MALLOC */