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 /** This is the actual memory used by the pools (all pools in one big block). */
170 static u8_t memp_memory
[MEM_ALIGNMENT
- 1
171 #define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
172 #include "lwip/memp_std.h"
175 #endif /* MEMP_SEPARATE_POOLS */
177 #if MEMP_SANITY_CHECK
179 * Check that memp-lists don't form a circle
187 for (i
= 0; i
< MEMP_MAX
; i
++) {
188 for (m
= memp_tab
[i
]; m
!= NULL
; m
= m
->next
) {
190 for (n
= memp_tab
[i
]; n
!= NULL
; n
= n
->next
) {
191 if (n
== m
&& --c
< 0) {
199 #endif /* MEMP_SANITY_CHECK*/
200 #if MEMP_OVERFLOW_CHECK
201 #if defined(LWIP_DEBUG) && MEMP_STATS
202 static const char * memp_overflow_names
[] = {
203 #define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
204 #include "lwip/memp_std.h"
209 * Check if a memp element was victim of an overflow
210 * (e.g. the restricted area after it has been altered)
212 * @param p the memp element to check
213 * @param memp_type the pool p comes from
216 memp_overflow_check_element_overflow(struct memp
*p
, u16_t memp_type
)
220 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
221 m
= (u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[memp_type
];
222 for (k
= 0; k
< MEMP_SANITY_REGION_AFTER_ALIGNED
; k
++) {
224 char errstr
[128] = "detected memp overflow in pool ";
226 if(memp_type
>= 10) {
227 digit
[0] = '0' + (memp_type
/10);
228 strcat(errstr
, digit
);
230 digit
[0] = '0' + (memp_type
%10);
231 strcat(errstr
, digit
);
232 #if defined(LWIP_DEBUG) && MEMP_STATS
233 strcat(errstr
, memp_overflow_names
[memp_type
]);
235 LWIP_ASSERT(errstr
, 0);
242 * Check if a memp element was victim of an underflow
243 * (e.g. the restricted area before it has been altered)
245 * @param p the memp element to check
246 * @param memp_type the pool p comes from
249 memp_overflow_check_element_underflow(struct memp
*p
, u16_t memp_type
)
253 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
254 m
= (u8_t
*)p
+ MEMP_SIZE
- MEMP_SANITY_REGION_BEFORE_ALIGNED
;
255 for (k
= 0; k
< MEMP_SANITY_REGION_BEFORE_ALIGNED
; k
++) {
257 char errstr
[128] = "detected memp underflow in pool ";
259 if(memp_type
>= 10) {
260 digit
[0] = '0' + (memp_type
/10);
261 strcat(errstr
, digit
);
263 digit
[0] = '0' + (memp_type
%10);
264 strcat(errstr
, digit
);
265 #if defined(LWIP_DEBUG) && MEMP_STATS
266 strcat(errstr
, memp_overflow_names
[memp_type
]);
268 LWIP_ASSERT(errstr
, 0);
275 * Do an overflow check for all elements in every pool.
277 * @see memp_overflow_check_element for a description of the check
280 memp_overflow_check_all(void)
285 p
= (struct memp
*)LWIP_MEM_ALIGN(memp_memory
);
286 for (i
= 0; i
< MEMP_MAX
; ++i
) {
288 for (j
= 0; j
< memp_num
[i
]; ++j
) {
289 memp_overflow_check_element_overflow(p
, i
);
290 p
= (struct memp
*)((u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[i
] + MEMP_SANITY_REGION_AFTER_ALIGNED
);
293 p
= (struct memp
*)LWIP_MEM_ALIGN(memp_memory
);
294 for (i
= 0; i
< MEMP_MAX
; ++i
) {
296 for (j
= 0; j
< memp_num
[i
]; ++j
) {
297 memp_overflow_check_element_underflow(p
, i
);
298 p
= (struct memp
*)((u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[i
] + MEMP_SANITY_REGION_AFTER_ALIGNED
);
304 * Initialize the restricted areas of all memp elements in every pool.
307 memp_overflow_init(void)
313 p
= (struct memp
*)LWIP_MEM_ALIGN(memp_memory
);
314 for (i
= 0; i
< MEMP_MAX
; ++i
) {
316 for (j
= 0; j
< memp_num
[i
]; ++j
) {
317 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
318 m
= (u8_t
*)p
+ MEMP_SIZE
- MEMP_SANITY_REGION_BEFORE_ALIGNED
;
319 memset(m
, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED
);
321 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
322 m
= (u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[i
];
323 memset(m
, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED
);
325 p
= (struct memp
*)((u8_t
*)p
+ MEMP_SIZE
+ memp_sizes
[i
] + MEMP_SANITY_REGION_AFTER_ALIGNED
);
329 #endif /* MEMP_OVERFLOW_CHECK */
332 * Initialize this module.
334 * Carves out memp_memory into linked lists for each pool-type.
342 for (i
= 0; i
< MEMP_MAX
; ++i
) {
343 MEMP_STATS_AVAIL(used
, i
, 0);
344 MEMP_STATS_AVAIL(max
, i
, 0);
345 MEMP_STATS_AVAIL(err
, i
, 0);
346 MEMP_STATS_AVAIL(avail
, i
, memp_num
[i
]);
349 #if !MEMP_SEPARATE_POOLS
350 memp
= (struct memp
*)LWIP_MEM_ALIGN(memp_memory
);
351 #endif /* !MEMP_SEPARATE_POOLS */
352 /* for every pool: */
353 for (i
= 0; i
< MEMP_MAX
; ++i
) {
355 #if MEMP_SEPARATE_POOLS
356 memp
= (struct memp
*)memp_bases
[i
];
357 #endif /* MEMP_SEPARATE_POOLS */
358 /* create a linked list of memp elements */
359 for (j
= 0; j
< memp_num
[i
]; ++j
) {
360 memp
->next
= memp_tab
[i
];
362 memp
= (struct memp
*)(void *)((u8_t
*)memp
+ MEMP_SIZE
+ memp_sizes
[i
]
363 #if MEMP_OVERFLOW_CHECK
364 + MEMP_SANITY_REGION_AFTER_ALIGNED
369 #if MEMP_OVERFLOW_CHECK
370 memp_overflow_init();
371 /* check everything a first time to see if it worked */
372 memp_overflow_check_all();
373 #endif /* MEMP_OVERFLOW_CHECK */
377 * Get an element from a specific pool.
379 * @param type the pool to get an element from
381 * the debug version has two more parameters:
382 * @param file file name calling this function
383 * @param line number of line where this function is called
385 * @return a pointer to the allocated memory or a NULL pointer on error
388 #if !MEMP_OVERFLOW_CHECK
389 memp_malloc(memp_t type
)
391 memp_malloc_fn(memp_t type
, const char* file
, const int line
)
395 SYS_ARCH_DECL_PROTECT(old_level
);
397 LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type
< MEMP_MAX
), return NULL
;);
399 SYS_ARCH_PROTECT(old_level
);
400 #if MEMP_OVERFLOW_CHECK >= 2
401 memp_overflow_check_all();
402 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
404 memp
= memp_tab
[type
];
407 memp_tab
[type
] = memp
->next
;
408 #if MEMP_OVERFLOW_CHECK
412 #endif /* MEMP_OVERFLOW_CHECK */
413 MEMP_STATS_INC_USED(used
, type
);
414 LWIP_ASSERT("memp_malloc: memp properly aligned",
415 ((mem_ptr_t
)memp
% MEM_ALIGNMENT
) == 0);
416 memp
= (struct memp
*)(void *)((u8_t
*)memp
+ MEMP_SIZE
);
418 LWIP_DEBUGF(MEMP_DEBUG
| LWIP_DBG_LEVEL_SERIOUS
, ("memp_malloc: out of memory in pool %s\n", memp_desc
[type
]));
419 MEMP_STATS_INC(err
, type
);
422 SYS_ARCH_UNPROTECT(old_level
);
428 * Put an element back into its pool.
430 * @param type the pool where to put mem
431 * @param mem the memp element to free
434 memp_free(memp_t type
, void *mem
)
437 SYS_ARCH_DECL_PROTECT(old_level
);
442 LWIP_ASSERT("memp_free: mem properly aligned",
443 ((mem_ptr_t
)mem
% MEM_ALIGNMENT
) == 0);
445 memp
= (struct memp
*)(void *)((u8_t
*)mem
- MEMP_SIZE
);
447 SYS_ARCH_PROTECT(old_level
);
448 #if MEMP_OVERFLOW_CHECK
449 #if MEMP_OVERFLOW_CHECK >= 2
450 memp_overflow_check_all();
452 memp_overflow_check_element_overflow(memp
, type
);
453 memp_overflow_check_element_underflow(memp
, type
);
454 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
455 #endif /* MEMP_OVERFLOW_CHECK */
457 MEMP_STATS_DEC(used
, type
);
459 memp
->next
= memp_tab
[type
];
460 memp_tab
[type
] = memp
;
462 #if MEMP_SANITY_CHECK
463 LWIP_ASSERT("memp sanity", memp_sanity());
464 #endif /* MEMP_SANITY_CHECK */
466 SYS_ARCH_UNPROTECT(old_level
);
469 #endif /* MEMP_MEM_MALLOC */