• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file
3  * Dynamic pool memory manager
4  *
5  * lwIP has dedicated pools for many structures (netconn, protocol control blocks,
6  * packet buffers, ...). All these pools are managed here.
7  *
8  * @defgroup mempool Memory pools
9  * @ingroup infrastructure
10  * Custom memory pools
11 
12  */
13 
14 /*
15  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
16  * All rights reserved.
17  *
18  * Redistribution and use in source and binary forms, with or without modification,
19  * are permitted provided that the following conditions are met:
20  *
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.
28  *
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
38  * OF SUCH DAMAGE.
39  *
40  * This file is part of the lwIP TCP/IP stack.
41  *
42  * Author: Adam Dunkels <adam@sics.se>
43  *
44  */
45 
46 #include "lwip/opt.h"
47 
48 #include "lwip/memp.h"
49 #include "lwip/sys.h"
50 #include "lwip/stats.h"
51 
52 #include <string.h>
53 
54 /* Make sure we include everything we need for size calculation required by memp_std.h */
55 #include "lwip/pbuf.h"
56 #include "lwip/raw.h"
57 #include "lwip/udp.h"
58 #include "lwip/tcp.h"
59 #include "lwip/priv/tcp_priv.h"
60 #include "lwip/altcp.h"
61 #include "lwip/ip4_frag.h"
62 #include "lwip/netbuf.h"
63 #include "lwip/api.h"
64 #include "lwip/priv/tcpip_priv.h"
65 #include "lwip/priv/api_msg.h"
66 #include "lwip/priv/sockets_priv.h"
67 #include "lwip/etharp.h"
68 #include "lwip/igmp.h"
69 #include "lwip/timeouts.h"
70 /* needed by default MEMP_NUM_SYS_TIMEOUT */
71 #include "netif/ppp/ppp_opts.h"
72 #include "lwip/netdb.h"
73 #include "lwip/dns.h"
74 #include "lwip/priv/nd6_priv.h"
75 #include "lwip/ip6_frag.h"
76 #include "lwip/mld6.h"
77 
78 #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
79 #include "lwip/priv/memp_std.h"
80 
81 const struct memp_desc *const memp_pools[MEMP_MAX] = {
82 #define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name,
83 #include "lwip/priv/memp_std.h"
84 };
85 
86 #ifdef LWIP_HOOK_FILENAME
87 #include LWIP_HOOK_FILENAME
88 #endif
89 
90 #if MEMP_MEM_MALLOC && MEMP_OVERFLOW_CHECK >= 2
91 #undef MEMP_OVERFLOW_CHECK
92 /* MEMP_OVERFLOW_CHECK >= 2 does not work with MEMP_MEM_MALLOC, use 1 instead */
93 #define MEMP_OVERFLOW_CHECK 1
94 #endif
95 
96 #if MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC
97 /**
98  * Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm".
99  */
100 static int
memp_sanity(const struct memp_desc * desc)101 memp_sanity(const struct memp_desc *desc)
102 {
103   struct memp *t, *h;
104 
105   t = *desc->tab;
106   if (t != NULL) {
107     for (h = t->next; (t != NULL) && (h != NULL); t = t->next,
108          h = ((h->next != NULL) ? h->next->next : NULL)) {
109       if (t == h) {
110         return 0;
111       }
112     }
113   }
114 
115   return 1;
116 }
117 #endif /* MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC */
118 
119 #if MEMP_OVERFLOW_CHECK
120 /**
121  * Check if a memp element was victim of an overflow or underflow
122  * (e.g. the restricted area after/before it has been altered)
123  *
124  * @param p the memp element to check
125  * @param desc the pool p comes from
126  */
127 static void
memp_overflow_check_element(struct memp * p,const struct memp_desc * desc)128 memp_overflow_check_element(struct memp *p, const struct memp_desc *desc)
129 {
130   mem_overflow_check_raw((u8_t *)p + MEMP_SIZE, desc->size, "pool ", desc->desc);
131 }
132 
133 /**
134  * Initialize the restricted area of on memp element.
135  */
136 static void
memp_overflow_init_element(struct memp * p,const struct memp_desc * desc)137 memp_overflow_init_element(struct memp *p, const struct memp_desc *desc)
138 {
139   mem_overflow_init_raw((u8_t *)p + MEMP_SIZE, desc->size);
140 }
141 
142 #if MEMP_OVERFLOW_CHECK >= 2
143 /**
144  * Do an overflow check for all elements in every pool.
145  *
146  * @see memp_overflow_check_element for a description of the check
147  */
148 static void
memp_overflow_check_all(void)149 memp_overflow_check_all(void)
150 {
151   u16_t i, j;
152   struct memp *p;
153   SYS_ARCH_DECL_PROTECT(old_level);
154   SYS_ARCH_PROTECT(old_level);
155 
156   for (i = 0; i < MEMP_MAX; ++i) {
157     p = (struct memp *)LWIP_MEM_ALIGN(memp_pools[i]->base);
158     for (j = 0; j < memp_pools[i]->num; ++j) {
159       memp_overflow_check_element(p, memp_pools[i]);
160       p = LWIP_ALIGNMENT_CAST(struct memp *, ((u8_t *)p + MEMP_SIZE + memp_pools[i]->size + MEM_SANITY_REGION_AFTER_ALIGNED));
161     }
162   }
163   SYS_ARCH_UNPROTECT(old_level);
164 }
165 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
166 #endif /* MEMP_OVERFLOW_CHECK */
167 
168 /**
169  * Initialize custom memory pool.
170  * Related functions: memp_malloc_pool, memp_free_pool
171  *
172  * @param desc pool to initialize
173  */
174 void
memp_init_pool(const struct memp_desc * desc)175 memp_init_pool(const struct memp_desc *desc)
176 {
177 #if MEMP_MEM_MALLOC
178   LWIP_UNUSED_ARG(desc);
179 #else
180   int i;
181   struct memp *memp;
182 
183   *desc->tab = NULL;
184   memp = (struct memp *)LWIP_MEM_ALIGN(desc->base);
185 #if MEMP_MEM_INIT
186   /* force memset on pool memory */
187   memset(memp, 0, (size_t)desc->num * (MEMP_SIZE + desc->size
188 #if MEMP_OVERFLOW_CHECK
189                                        + MEM_SANITY_REGION_AFTER_ALIGNED
190 #endif
191                                       ));
192 #endif
193   /* create a linked list of memp elements */
194   for (i = 0; i < desc->num; ++i) {
195     memp->next = *desc->tab;
196     *desc->tab = memp;
197 #if MEMP_OVERFLOW_CHECK
198     memp_overflow_init_element(memp, desc);
199 #endif /* MEMP_OVERFLOW_CHECK */
200     /* cast through void* to get rid of alignment warnings */
201     memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size
202 #if MEMP_OVERFLOW_CHECK
203                                    + MEM_SANITY_REGION_AFTER_ALIGNED
204 #endif
205                                   );
206   }
207 #if MEMP_STATS
208   desc->stats->avail = desc->num;
209 #endif /* MEMP_STATS */
210 #endif /* !MEMP_MEM_MALLOC */
211 
212 #if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY)
213   desc->stats->name  = desc->desc;
214 #endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */
215 }
216 
217 /**
218  * Initializes lwIP built-in pools.
219  * Related functions: memp_malloc, memp_free
220  *
221  * Carves out memp_memory into linked lists for each pool-type.
222  */
223 void
memp_init(void)224 memp_init(void)
225 {
226   u16_t i;
227 
228   /* for every pool: */
229   for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) {
230     memp_init_pool(memp_pools[i]);
231 
232 #if LWIP_STATS && MEMP_STATS
233     lwip_stats.memp[i] = memp_pools[i]->stats;
234 #endif
235   }
236 
237 #if MEMP_OVERFLOW_CHECK >= 2
238   /* check everything a first time to see if it worked */
239   memp_overflow_check_all();
240 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
241 }
242 
243 static void *
244 #if !MEMP_OVERFLOW_CHECK
do_memp_malloc_pool(const struct memp_desc * desc)245 do_memp_malloc_pool(const struct memp_desc *desc)
246 #else
247 do_memp_malloc_pool_fn(const struct memp_desc *desc, const char *file, const int line)
248 #endif
249 {
250   struct memp *memp;
251   SYS_ARCH_DECL_PROTECT(old_level);
252 
253 #if MEMP_MEM_MALLOC
254   memp = (struct memp *)mem_malloc(MEMP_SIZE + MEMP_ALIGN_SIZE(desc->size));
255   SYS_ARCH_PROTECT(old_level);
256 #else /* MEMP_MEM_MALLOC */
257   SYS_ARCH_PROTECT(old_level);
258 
259   memp = *desc->tab;
260 #endif /* MEMP_MEM_MALLOC */
261 
262   if (memp != NULL) {
263 #if !MEMP_MEM_MALLOC
264 #if MEMP_OVERFLOW_CHECK == 1
265     memp_overflow_check_element(memp, desc);
266 #endif /* MEMP_OVERFLOW_CHECK */
267 
268     *desc->tab = memp->next;
269 #if MEMP_OVERFLOW_CHECK
270     memp->next = NULL;
271 #endif /* MEMP_OVERFLOW_CHECK */
272 #endif /* !MEMP_MEM_MALLOC */
273 #if MEMP_OVERFLOW_CHECK
274     memp->file = file;
275     memp->line = line;
276 #if MEMP_MEM_MALLOC
277     memp_overflow_init_element(memp, desc);
278 #endif /* MEMP_MEM_MALLOC */
279 #endif /* MEMP_OVERFLOW_CHECK */
280     LWIP_ASSERT("memp_malloc: memp properly aligned",
281                 ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
282 #if MEMP_STATS
283     desc->stats->used++;
284     if (desc->stats->used > desc->stats->max) {
285       desc->stats->max = desc->stats->used;
286     }
287 #endif
288     SYS_ARCH_UNPROTECT(old_level);
289     /* cast through u8_t* to get rid of alignment warnings */
290     return ((u8_t *)memp + MEMP_SIZE);
291   } else {
292 #if MEMP_STATS
293     desc->stats->err++;
294 #endif
295     SYS_ARCH_UNPROTECT(old_level);
296     LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", desc->desc));
297   }
298 
299   return NULL;
300 }
301 
302 /**
303  * Get an element from a custom pool.
304  *
305  * @param desc the pool to get an element from
306  *
307  * @return a pointer to the allocated memory or a NULL pointer on error
308  */
309 void *
310 #if !MEMP_OVERFLOW_CHECK
memp_malloc_pool(const struct memp_desc * desc)311 memp_malloc_pool(const struct memp_desc *desc)
312 #else
313 memp_malloc_pool_fn(const struct memp_desc *desc, const char *file, const int line)
314 #endif
315 {
316   LWIP_ASSERT("invalid pool desc", desc != NULL);
317   if (desc == NULL) {
318     return NULL;
319   }
320 
321 #if !MEMP_OVERFLOW_CHECK
322   return do_memp_malloc_pool(desc);
323 #else
324   return do_memp_malloc_pool_fn(desc, file, line);
325 #endif
326 }
327 
328 /**
329  * Get an element from a specific pool.
330  *
331  * @param type the pool to get an element from
332  *
333  * @return a pointer to the allocated memory or a NULL pointer on error
334  */
335 void *
336 #if !MEMP_OVERFLOW_CHECK
memp_malloc(memp_t type)337 memp_malloc(memp_t type)
338 #else
339 memp_malloc_fn(memp_t type, const char *file, const int line)
340 #endif
341 {
342   void *memp;
343   LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
344 
345 #if MEMP_OVERFLOW_CHECK >= 2
346   memp_overflow_check_all();
347 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
348 
349 #if !MEMP_OVERFLOW_CHECK
350   memp = do_memp_malloc_pool(memp_pools[type]);
351 #else
352   memp = do_memp_malloc_pool_fn(memp_pools[type], file, line);
353 #endif
354 
355   return memp;
356 }
357 
358 static void
do_memp_free_pool(const struct memp_desc * desc,void * mem)359 do_memp_free_pool(const struct memp_desc *desc, void *mem)
360 {
361   struct memp *memp;
362   SYS_ARCH_DECL_PROTECT(old_level);
363 
364   LWIP_ASSERT("memp_free: mem properly aligned",
365               ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
366 
367   /* cast through void* to get rid of alignment warnings */
368   memp = (struct memp *)(void *)((u8_t *)mem - MEMP_SIZE);
369 
370   SYS_ARCH_PROTECT(old_level);
371 
372 #if MEMP_OVERFLOW_CHECK == 1
373   memp_overflow_check_element(memp, desc);
374 #endif /* MEMP_OVERFLOW_CHECK */
375 
376 #if MEMP_STATS
377   desc->stats->used--;
378 #endif
379 
380 #if MEMP_MEM_MALLOC
381   LWIP_UNUSED_ARG(desc);
382   SYS_ARCH_UNPROTECT(old_level);
383   mem_free(memp);
384 #else /* MEMP_MEM_MALLOC */
385   memp->next = *desc->tab;
386   *desc->tab = memp;
387 
388 #if MEMP_SANITY_CHECK
389   LWIP_ASSERT("memp sanity", memp_sanity(desc));
390 #endif /* MEMP_SANITY_CHECK */
391 
392   SYS_ARCH_UNPROTECT(old_level);
393 #endif /* !MEMP_MEM_MALLOC */
394 }
395 
396 /**
397  * Put a custom pool element back into its pool.
398  *
399  * @param desc the pool where to put mem
400  * @param mem the memp element to free
401  */
402 void
memp_free_pool(const struct memp_desc * desc,void * mem)403 memp_free_pool(const struct memp_desc *desc, void *mem)
404 {
405   LWIP_ASSERT("invalid pool desc", desc != NULL);
406   if ((desc == NULL) || (mem == NULL)) {
407     return;
408   }
409 
410   do_memp_free_pool(desc, mem);
411 }
412 
413 /**
414  * Put an element back into its pool.
415  *
416  * @param type the pool where to put mem
417  * @param mem the memp element to free
418  */
419 void
memp_free(memp_t type,void * mem)420 memp_free(memp_t type, void *mem)
421 {
422 #ifdef LWIP_HOOK_MEMP_AVAILABLE
423   struct memp *old_first;
424 #endif
425 
426   LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;);
427 
428   if (mem == NULL) {
429     return;
430   }
431 
432 #if MEMP_OVERFLOW_CHECK >= 2
433   memp_overflow_check_all();
434 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
435 
436 #ifdef LWIP_HOOK_MEMP_AVAILABLE
437   old_first = *memp_pools[type]->tab;
438 #endif
439 
440   do_memp_free_pool(memp_pools[type], mem);
441 
442 #ifdef LWIP_HOOK_MEMP_AVAILABLE
443   if (old_first == NULL) {
444     LWIP_HOOK_MEMP_AVAILABLE(type);
445   }
446 #endif
447 }
448