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.
8 * @defgroup mempool Memory pools
9 * @ingroup infrastructure
15 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
16 * All rights reserved.
18 * Redistribution and use in source and binary forms, with or without modification,
19 * are permitted provided that the following conditions are met:
21 * 1. Redistributions of source code must retain the above copyright notice,
22 * this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright notice,
24 * this list of conditions and the following disclaimer in the documentation
25 * and/or other materials provided with the distribution.
26 * 3. The name of the author may not be used to endorse or promote products
27 * derived from this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
30 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
32 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
34 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
37 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
40 * This file is part of the lwIP TCP/IP stack.
42 * Author: Adam Dunkels <adam@sics.se>
48 #include "lwip/memp.h"
50 #include "lwip/stats.h"
54 /* Make sure we include everything we need for size calculation required by memp_std.h */
55 #include "lwip/pbuf.h"
59 #include "lwip/priv/tcp_priv.h"
60 #include "lwip/ip4_frag.h"
61 #include "lwip/netbuf.h"
63 #include "lwip/priv/tcpip_priv.h"
64 #include "lwip/priv/api_msg.h"
65 #include "lwip/sockets.h"
66 #include "lwip/priv/sockets_priv.h"
67 #include "lwip/netifapi.h"
68 #include "lwip/etharp.h"
69 #include "lwip/igmp.h"
70 #include "lwip/timeouts.h"
71 /* needed by default MEMP_NUM_SYS_TIMEOUT */
72 #include "netif/ppp/ppp_opts.h"
73 #include "lwip/netdb.h"
75 #include "lwip/priv/nd6_priv.h"
76 #include "lwip/ip6_frag.h"
77 #include "lwip/mld6.h"
79 #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
80 #include "lwip/priv/memp_std.h"
82 const struct memp_desc
* const memp_pools
[MEMP_MAX
] = {
83 #define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name,
84 #include "lwip/priv/memp_std.h"
87 #ifdef LWIP_HOOK_FILENAME
88 #include LWIP_HOOK_FILENAME
91 #if MEMP_MEM_MALLOC && MEMP_OVERFLOW_CHECK >= 2
92 #undef MEMP_OVERFLOW_CHECK
93 /* MEMP_OVERFLOW_CHECK >= 2 does not work with MEMP_MEM_MALLOC, use 1 instead */
94 #define MEMP_OVERFLOW_CHECK 1
97 #if MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC
99 * Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm".
102 memp_sanity(const struct memp_desc
*desc
)
108 for (h
= t
->next
; (t
!= NULL
) && (h
!= NULL
); t
= t
->next
,
109 h
= ((h
->next
!= NULL
) ? h
->next
->next
: NULL
)) {
118 #endif /* MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC */
120 #if MEMP_OVERFLOW_CHECK
122 * Check if a memp element was victim of an overflow
123 * (e.g. the restricted area after it has been altered)
125 * @param p the memp element to check
126 * @param desc the pool p comes from
129 memp_overflow_check_element_overflow(struct memp
*p
, const struct memp_desc
*desc
)
131 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
134 m
= (u8_t
*)p
+ MEMP_SIZE
+ desc
->size
;
135 for (k
= 0; k
< MEMP_SANITY_REGION_AFTER_ALIGNED
; k
++) {
137 char errstr
[128] = "detected memp overflow in pool ";
138 strcat(errstr
, desc
->desc
);
139 LWIP_ASSERT(errstr
, 0);
142 #else /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
144 LWIP_UNUSED_ARG(desc
);
145 #endif /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
149 * Check if a memp element was victim of an underflow
150 * (e.g. the restricted area before it has been altered)
152 * @param p the memp element to check
153 * @param desc the pool p comes from
156 memp_overflow_check_element_underflow(struct memp
*p
, const struct memp_desc
*desc
)
158 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
161 m
= (u8_t
*)p
+ MEMP_SIZE
- MEMP_SANITY_REGION_BEFORE_ALIGNED
;
162 for (k
= 0; k
< MEMP_SANITY_REGION_BEFORE_ALIGNED
; k
++) {
164 char errstr
[128] = "detected memp underflow in pool ";
165 strcat(errstr
, desc
->desc
);
166 LWIP_ASSERT(errstr
, 0);
169 #else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */
171 LWIP_UNUSED_ARG(desc
);
172 #endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */
176 * Initialize the restricted area of on memp element.
179 memp_overflow_init_element(struct memp
*p
, const struct memp_desc
*desc
)
181 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0
183 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
184 m
= (u8_t
*)p
+ MEMP_SIZE
- MEMP_SANITY_REGION_BEFORE_ALIGNED
;
185 memset(m
, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED
);
187 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
188 m
= (u8_t
*)p
+ MEMP_SIZE
+ desc
->size
;
189 memset(m
, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED
);
191 #else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
193 LWIP_UNUSED_ARG(desc
);
194 #endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
197 #if MEMP_OVERFLOW_CHECK >= 2
199 * Do an overflow check for all elements in every pool.
201 * @see memp_overflow_check_element for a description of the check
204 memp_overflow_check_all(void)
208 SYS_ARCH_DECL_PROTECT(old_level
);
209 SYS_ARCH_PROTECT(old_level
);
211 for (i
= 0; i
< MEMP_MAX
; ++i
) {
212 p
= (struct memp
*)LWIP_MEM_ALIGN(memp_pools
[i
]->base
);
213 for (j
= 0; j
< memp_pools
[i
]->num
; ++j
) {
214 memp_overflow_check_element_overflow(p
, memp_pools
[i
]);
215 memp_overflow_check_element_underflow(p
, memp_pools
[i
]);
216 p
= LWIP_ALIGNMENT_CAST(struct memp
*, ((u8_t
*)p
+ MEMP_SIZE
+ memp_pools
[i
]->size
+ MEMP_SANITY_REGION_AFTER_ALIGNED
));
219 SYS_ARCH_UNPROTECT(old_level
);
221 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
222 #endif /* MEMP_OVERFLOW_CHECK */
225 * Initialize custom memory pool.
226 * Related functions: memp_malloc_pool, memp_free_pool
228 * @param desc pool to initialize
231 memp_init_pool(const struct memp_desc
*desc
)
234 LWIP_UNUSED_ARG(desc
);
240 memp
= (struct memp
*)LWIP_MEM_ALIGN(desc
->base
);
241 /* create a linked list of memp elements */
242 for (i
= 0; i
< desc
->num
; ++i
) {
243 memp
->next
= *desc
->tab
;
245 #if MEMP_OVERFLOW_CHECK
246 memp_overflow_init_element(memp
, desc
);
247 #endif /* MEMP_OVERFLOW_CHECK */
248 /* cast through void* to get rid of alignment warnings */
249 memp
= (struct memp
*)(void *)((u8_t
*)memp
+ MEMP_SIZE
+ desc
->size
250 #if MEMP_OVERFLOW_CHECK
251 + MEMP_SANITY_REGION_AFTER_ALIGNED
256 desc
->stats
->avail
= desc
->num
;
257 #endif /* MEMP_STATS */
258 #endif /* !MEMP_MEM_MALLOC */
260 #if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY)
261 desc
->stats
->name
= desc
->desc
;
262 #endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */
266 * Initializes lwIP built-in pools.
267 * Related functions: memp_malloc, memp_free
269 * Carves out memp_memory into linked lists for each pool-type.
276 /* for every pool: */
277 for (i
= 0; i
< LWIP_ARRAYSIZE(memp_pools
); i
++) {
278 memp_init_pool(memp_pools
[i
]);
280 #if LWIP_STATS && MEMP_STATS
281 lwip_stats
.memp
[i
] = memp_pools
[i
]->stats
;
285 #if MEMP_OVERFLOW_CHECK >= 2
286 /* check everything a first time to see if it worked */
287 memp_overflow_check_all();
288 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
292 #if !MEMP_OVERFLOW_CHECK
293 do_memp_malloc_pool(const struct memp_desc
*desc
)
295 do_memp_malloc_pool_fn(const struct memp_desc
*desc
, const char* file
, const int line
)
299 SYS_ARCH_DECL_PROTECT(old_level
);
302 memp
= (struct memp
*)mem_malloc(MEMP_SIZE
+ MEMP_ALIGN_SIZE(desc
->size
));
303 SYS_ARCH_PROTECT(old_level
);
304 #else /* MEMP_MEM_MALLOC */
305 SYS_ARCH_PROTECT(old_level
);
308 #endif /* MEMP_MEM_MALLOC */
312 #if MEMP_OVERFLOW_CHECK == 1
313 memp_overflow_check_element_overflow(memp
, desc
);
314 memp_overflow_check_element_underflow(memp
, desc
);
315 #endif /* MEMP_OVERFLOW_CHECK */
317 *desc
->tab
= memp
->next
;
318 #if MEMP_OVERFLOW_CHECK
320 #endif /* MEMP_OVERFLOW_CHECK */
321 #endif /* !MEMP_MEM_MALLOC */
322 #if MEMP_OVERFLOW_CHECK
326 memp_overflow_init_element(memp
, desc
);
327 #endif /* MEMP_MEM_MALLOC */
328 #endif /* MEMP_OVERFLOW_CHECK */
329 LWIP_ASSERT("memp_malloc: memp properly aligned",
330 ((mem_ptr_t
)memp
% MEM_ALIGNMENT
) == 0);
333 if (desc
->stats
->used
> desc
->stats
->max
) {
334 desc
->stats
->max
= desc
->stats
->used
;
337 SYS_ARCH_UNPROTECT(old_level
);
338 /* cast through u8_t* to get rid of alignment warnings */
339 return ((u8_t
*)memp
+ MEMP_SIZE
);
341 LWIP_DEBUGF(MEMP_DEBUG
| LWIP_DBG_LEVEL_SERIOUS
, ("memp_malloc: out of memory in pool %s\n", desc
->desc
));
347 SYS_ARCH_UNPROTECT(old_level
);
352 * Get an element from a custom pool.
354 * @param desc the pool to get an element from
356 * @return a pointer to the allocated memory or a NULL pointer on error
359 #if !MEMP_OVERFLOW_CHECK
360 memp_malloc_pool(const struct memp_desc
*desc
)
362 memp_malloc_pool_fn(const struct memp_desc
*desc
, const char* file
, const int line
)
365 LWIP_ASSERT("invalid pool desc", desc
!= NULL
);
370 #if !MEMP_OVERFLOW_CHECK
371 return do_memp_malloc_pool(desc
);
373 return do_memp_malloc_pool_fn(desc
, file
, line
);
378 * Get an element from a specific pool.
380 * @param type the pool to get an element from
382 * @return a pointer to the allocated memory or a NULL pointer on error
385 #if !MEMP_OVERFLOW_CHECK
386 memp_malloc(memp_t type
)
388 memp_malloc_fn(memp_t type
, const char* file
, const int line
)
392 LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type
< MEMP_MAX
), return NULL
;);
394 #if MEMP_OVERFLOW_CHECK >= 2
395 memp_overflow_check_all();
396 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
398 #if !MEMP_OVERFLOW_CHECK
399 memp
= do_memp_malloc_pool(memp_pools
[type
]);
401 memp
= do_memp_malloc_pool_fn(memp_pools
[type
], file
, line
);
408 do_memp_free_pool(const struct memp_desc
* desc
, void *mem
)
411 SYS_ARCH_DECL_PROTECT(old_level
);
413 LWIP_ASSERT("memp_free: mem properly aligned",
414 ((mem_ptr_t
)mem
% MEM_ALIGNMENT
) == 0);
416 /* cast through void* to get rid of alignment warnings */
417 memp
= (struct memp
*)(void *)((u8_t
*)mem
- MEMP_SIZE
);
419 SYS_ARCH_PROTECT(old_level
);
421 #if MEMP_OVERFLOW_CHECK == 1
422 memp_overflow_check_element_overflow(memp
, desc
);
423 memp_overflow_check_element_underflow(memp
, desc
);
424 #endif /* MEMP_OVERFLOW_CHECK */
431 LWIP_UNUSED_ARG(desc
);
432 SYS_ARCH_UNPROTECT(old_level
);
434 #else /* MEMP_MEM_MALLOC */
435 memp
->next
= *desc
->tab
;
438 #if MEMP_SANITY_CHECK
439 LWIP_ASSERT("memp sanity", memp_sanity(desc
));
440 #endif /* MEMP_SANITY_CHECK */
442 SYS_ARCH_UNPROTECT(old_level
);
443 #endif /* !MEMP_MEM_MALLOC */
447 * Put a custom pool element back into its pool.
449 * @param desc the pool where to put mem
450 * @param mem the memp element to free
453 memp_free_pool(const struct memp_desc
* desc
, void *mem
)
455 LWIP_ASSERT("invalid pool desc", desc
!= NULL
);
456 if ((desc
== NULL
) || (mem
== NULL
)) {
460 do_memp_free_pool(desc
, mem
);
464 * Put an element back into its pool.
466 * @param type the pool where to put mem
467 * @param mem the memp element to free
470 memp_free(memp_t type
, void *mem
)
472 #ifdef LWIP_HOOK_MEMP_AVAILABLE
473 struct memp
*old_first
;
476 LWIP_ERROR("memp_free: type < MEMP_MAX", (type
< MEMP_MAX
), return;);
482 #if MEMP_OVERFLOW_CHECK >= 2
483 memp_overflow_check_all();
484 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
486 #ifdef LWIP_HOOK_MEMP_AVAILABLE
487 old_first
= *memp_pools
[type
]->tab
;
490 do_memp_free_pool(memp_pools
[type
], mem
);
492 #ifdef LWIP_HOOK_MEMP_AVAILABLE
493 if (old_first
== NULL
) {
494 LWIP_HOOK_MEMP_AVAILABLE(type
);