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
9/*
10 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without modification,
14 * are permitted provided that the following conditions are met:
15 *
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.
23 *
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
33 * OF SUCH DAMAGE.
34 *
35 * This file is part of the lwIP TCP/IP stack.
36 *
37 * Author: Adam Dunkels <adam@sics.se>
38 *
39 */
40
41#include "lwip/opt.h"
42#include "lwip/def.h"
43#include "lwip/memp.h"
44#include "lwip/pbuf.h"
45#include "lwip/udp.h"
46#include "lwip/raw.h"
47#include "lwip/tcp.h"
48#include "lwip/igmp.h"
49#include "lwip/api.h"
50#include "lwip/api_msg.h"
51#include "lwip/tcpip.h"
52#include "lwip/sys.h"
53#include "lwip/stats.h"
54#include "netif/etharp.h"
55#include "lwip/ip_frag.h"
56
57#include <string.h>
58#include <inttypes.h>
59
60#if !MEMP_MEM_MALLOC            /* don't build if not configured for use in lwipopts.h */
61
62struct memp {
63    struct memp *next;
64#if MEMP_OVERFLOW_CHECK
65    const char *file;
66    int line;
67#endif                          /* MEMP_OVERFLOW_CHECK */
68};
69
70#if MEMP_OVERFLOW_CHECK
71/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
72 * and at the end of each element, initialize them as 0xcd and check
73 * them later. */
74/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
75 * every single element in each pool is checked!
76 * This is VERY SLOW but also very helpful. */
77/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
78 * lwipopts.h to change the amount reserved for checking. */
79#ifndef MEMP_SANITY_REGION_BEFORE
80#define MEMP_SANITY_REGION_BEFORE  16
81#endif                          /* MEMP_SANITY_REGION_BEFORE */
82#if MEMP_SANITY_REGION_BEFORE > 0
83#define MEMP_SANITY_REGION_BEFORE_ALIGNED    LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
84#else
85#define MEMP_SANITY_REGION_BEFORE_ALIGNED    0
86#endif                          /* MEMP_SANITY_REGION_BEFORE */
87#ifndef MEMP_SANITY_REGION_AFTER
88#define MEMP_SANITY_REGION_AFTER   16
89#endif                          /* MEMP_SANITY_REGION_AFTER */
90#if MEMP_SANITY_REGION_AFTER > 0
91#define MEMP_SANITY_REGION_AFTER_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
92#else
93#define MEMP_SANITY_REGION_AFTER_ALIGNED     0
94#endif                          /* MEMP_SANITY_REGION_AFTER */
95
96/* MEMP_SIZE: save space for struct memp and for sanity check */
97#define MEMP_SIZE          (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
98#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
99
100#else                           /* MEMP_OVERFLOW_CHECK */
101
102/* No sanity checks
103 * We don't need to preserve the struct memp while not allocated, so we
104 * can save a little space and set MEMP_SIZE to 0.
105 */
106#define MEMP_SIZE           0
107#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
108
109#endif                          /* MEMP_OVERFLOW_CHECK */
110
111/** This array holds the first free element of each pool.
112 *  Elements form a linked list. */
113static struct memp *memp_tab[MEMP_MAX];
114
115#else                           /* MEMP_MEM_MALLOC */
116
117#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
118
119#endif                          /* MEMP_MEM_MALLOC */
120
121/** This array holds the element sizes of each pool. */
122#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
123static
124#endif
125const u16_t memp_sizes[MEMP_MAX] = {
126#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_ALIGN_SIZE(size),
127#include "lwip/memp_std.h"
128};
129
130/**
131 * Array of indexes of pools, ordered by their element size in descending
132 * order.
133 */
134static size_t memp_sorted[MEMP_MAX];
135
136#if !MEMP_MEM_MALLOC            /* don't build if not configured for use in lwipopts.h */
137
138/** This array holds the number of elements in each pool. */
139static const u16_t memp_num[MEMP_MAX] = {
140#define LWIP_MEMPOOL(name,num,size,desc)  (num),
141#include "lwip/memp_std.h"
142};
143
144
145/** This array holds a textual description of each pool. */
146#ifdef LWIP_DEBUG
147static const char *memp_desc[MEMP_MAX] = {
148#define LWIP_MEMPOOL(name,num,size,desc)  (desc),
149#include "lwip/memp_std.h"
150};
151#endif                          /* LWIP_DEBUG */
152
153#if 0
154static u8_t memp_memory_orig[MEM_ALIGNMENT - 1
155#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
156#include "lwip/memp_std.h"
157  ];
158#endif
159
160/* This is the size of memory required by all the pools. */
161/*static const size_t memp_memory_size = (MEM_ALIGNMENT - 1
162#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
163#include "lwip/memp_std.h"
164  );*/
165
166static u8_t *memp_memory = 0;
167u8_t *mem_barrelfish_alloc(uint8_t buf_index, uint32_t size);
168u8_t *mem_barrelfish_register_buf(uint8_t binding_index, uint32_t size);
169
170#if MEMP_SANITY_CHECK
171/**
172 * Check that memp-lists don't form a circle
173 */
174static int memp_sanity(void)
175{
176    s16_t i, c;
177    struct memp *m, *n;
178
179    for (i = 0; i < MEMP_MAX; i++) {
180        for (m = memp_tab[i]; m != NULL; m = m->next) {
181            c = 1;
182            for (n = memp_tab[i]; n != NULL; n = n->next) {
183                if (n == m && --c < 0) {
184                    return 0;
185                }
186            }
187        }
188    }
189    return 1;
190}
191#endif                          /* MEMP_SANITY_CHECK */
192#if MEMP_OVERFLOW_CHECK
193/**
194 * Check if a memp element was victim of an overflow
195 * (e.g. the restricted area after it has been altered)
196 *
197 * @param p the memp element to check
198 * @param memp_size the element size of the pool p comes from
199 */
200static void memp_overflow_check_element(struct memp *p, u16_t memp_size)
201{
202    u16_t k;
203    u8_t *m;
204
205#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
206    m = (u8_t *) p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
207    for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
208        if (m[k] != 0xcd) {
209            LWIP_ASSERT("detected memp underflow!", 0);
210        }
211    }
212#endif
213#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
214    m = (u8_t *) p + MEMP_SIZE + memp_size;
215    for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
216        if (m[k] != 0xcd) {
217            LWIP_ASSERT("detected memp overflow!", 0);
218        }
219    }
220#endif
221}
222
223/**
224 * Do an overflow check for all elements in every pool.
225 *
226 * @see memp_overflow_check_element for a description of the check
227 */
228static void memp_overflow_check_all(void)
229{
230    u16_t i, j;
231    struct memp *p;
232
233    p = LWIP_MEM_ALIGN(memp_memory);
234    for (i = 0; i < MEMP_MAX; ++i) {
235        p = p;
236        for (j = 0; j < memp_num[i]; ++j) {
237            memp_overflow_check_element(p, memp_sizes[i]);
238            p =
239              (struct memp *) ((u8_t *) p + MEMP_SIZE + memp_sizes[i] +
240                               MEMP_SANITY_REGION_AFTER_ALIGNED);
241        }
242    }
243}
244
245/**
246 * Initialize the restricted areas of all memp elements in every pool.
247 */
248static void memp_overflow_init(void)
249{
250    u16_t i, j;
251    struct memp *p;
252    u8_t *m;
253
254    p = LWIP_MEM_ALIGN(memp_memory);
255    for (i = 0; i < MEMP_MAX; ++i) {
256        p = p;
257        for (j = 0; j < memp_num[i]; ++j) {
258#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
259            m = (u8_t *) p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
260            memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
261#endif
262#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
263            m = (u8_t *) p + MEMP_SIZE + memp_sizes[i];
264            memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
265#endif
266            p =
267              (struct memp *) ((u8_t *) p + MEMP_SIZE + memp_sizes[i] +
268                               MEMP_SANITY_REGION_AFTER_ALIGNED);
269        }
270    }
271}
272#endif                          /* MEMP_OVERFLOW_CHECK */
273
274static u16_t pbuf_pool_counter = 0;
275
276
277#if MEMP_OVERFLOW_CHECK
278#error   "Overflow checking is not supported at the moment, as it screws up "\
279         "our alignment assumptions"
280#endif
281
282/**
283 * Comparator function for ordering pools in descending order of their element
284 * sizes.
285 */
286static int memp_size_comp(const void *a, const void *b)
287{
288    const size_t *as = a, *bs = b;
289    if (memp_sizes[*bs] < memp_sizes[*as]) {
290        return -1;
291    } else if (memp_sizes[*bs] == memp_sizes[*as]) {
292        return 0;
293    } else {
294        return 1;
295    }
296}
297
298/** Initialize memp_sorted */
299static void initialize_memp_sorted(void)
300{
301    size_t i;
302    for (i = 0; i < MEMP_MAX; i++) {
303        memp_sorted[i] = i;
304    }
305    qsort(memp_sorted, MEMP_MAX, sizeof(size_t), memp_size_comp);
306}
307
308/**
309 * Try and figure out how much memory is needed for the pool. This is not
310 * completly trivial as we try to align the pool elements to their size.
311 *
312 * @param max_el_size Pointer to location where maximal element size should be
313 *                    stored (first element size).
314 */
315static size_t memp_memory_needed(void)
316{
317    size_t memp_memory_size = 0;
318    size_t cursz, curtotal, i, idx;
319    size_t maxsz = 1;
320
321    for (i = 0; i < MEMP_MAX; ++i) {
322        idx = memp_sorted[i];
323        cursz = memp_sizes[idx];
324        curtotal = memp_num[idx];
325        if (memp_memory_size % cursz != 0) {
326            curtotal += cursz - (memp_memory_size % cursz);
327        }
328        memp_memory_size += curtotal;
329
330        if (cursz > maxsz) {
331            maxsz = cursz;
332        }
333    }
334
335    // Add a little more so we can align the buffer
336    memp_memory_size += maxsz;
337
338    return memp_memory_size;
339}
340
341/**
342 * Initialize this module.
343 *
344 * Carves out memp_memory into linked lists for each pool-type.
345 */
346void memp_init(void)
347{
348    size_t memp_memory_size;
349//    printf("memp_init: allocating %zx memory for index %d\n", memp_memory_size,
350//           RX_BUFFER_ID);
351
352    initialize_memp_sorted();
353    memp_memory_size = memp_memory_needed();
354
355    memp_memory =
356      mem_barrelfish_alloc(RX_BUFFER_ID, memp_memory_size);
357    if (memp_memory == 0) {
358        fprintf(stderr, "could not allocate memory");
359        abort();
360    }
361
362//    printf("memp_init: allocated memory is at VA [%p]\n", memp_memory);
363
364    memp_initialize_pbuf_list();
365    mem_barrelfish_register_buf(RX_BUFFER_ID, memp_memory_size);
366}
367
368
369void memp_initialize_pbuf_list(void)
370{
371    assert(memp_memory != NULL);
372    struct memp *memp;
373    uintptr_t uimemp;
374    u16_t k, i, j;
375    for (i = 0; i < MEMP_MAX; ++i) {
376        MEMP_STATS_AVAIL(used, i, 0);
377        MEMP_STATS_AVAIL(max, i, 0);
378        MEMP_STATS_AVAIL(err, i, 0);
379        MEMP_STATS_AVAIL(avail, i, memp_num[i]);
380    }
381    memp = LWIP_MEM_ALIGN(memp_memory);
382/*    printf("memp_init: total types of pools %d\n", MEMP_MAX );
383    printf("memp_init: total types of pools %d, memp_mem %p\n",
384            MEMP_MAX, memp_memory);
385    printf("memp_init: total types of pools %d, memp %p\n", MEMP_MAX, memp);
386*/
387    memp->next = NULL;
388    /* for every pool: */
389    for (k = 0; k < MEMP_MAX; ++k) {
390        i = memp_sorted[k];
391        memp_tab[i] = NULL;
392
393
394        // Align memp to element size
395        uimemp = (uintptr_t) memp;
396        if (uimemp % memp_sizes[i] > 0) {
397            uimemp += memp_sizes[i] - (uimemp % memp_sizes[i]);
398        }
399        memp = (struct memp *) uimemp;
400
401        /* create a linked list of memp elements */
402        for (j = 0; j < memp_num[i]; ++j) {
403            memp->next = memp_tab[i];
404            memp_tab[i] = memp;
405            memp = (struct memp *) ((u8_t *) memp + memp_sizes[i]);
406        }
407    }
408    // Set how many free pbuf_pools are there
409//    printf("memp_num[PBUF_POOL] %" PRIu16 "\n", memp_num[MEMP_MAX - 1]);
410    pbuf_pool_counter = 0;
411#if MEMP_OVERFLOW_CHECK
412    memp_overflow_init();
413    /* check everything a first time to see if it worked */
414    memp_overflow_check_all();
415#endif                          /* MEMP_OVERFLOW_CHECK */
416
417//    mem_barrelfish_register_buf(RX_BUFFER_ID, memp_memory_size);
418}
419
420// Returns the count of free pbufs available
421u16_t memp_pbuf_peek(void)
422{
423    return (memp_num[MEMP_MAX - 1] - pbuf_pool_counter);
424}
425
426#define INSTRUMENT_PBUF_CALLS  1
427
428#if INSTRUMENT_PBUF_CALLS
429void show_pbuf_free_stats(void);
430void show_pbuf_alloc_stats(void);
431#endif // INSTRUMENT_PBUF_CALLS
432
433
434extern uint64_t chained_pbuf_count;
435extern uint64_t outgoing_packet_count;
436extern uint64_t incoming_packet_count;
437extern uint64_t pbuf_free_tx_done_counter;
438extern uint64_t pbuf_free_incoming_counter;
439extern uint64_t pbuf_realloc_called;
440extern uint64_t pbuf_free_called_all;
441
442
443extern uint64_t pbuf_alloc_all;
444extern uint64_t pbuf_alloc_pool;
445extern uint64_t pbuf_alloc_ram;
446extern uint64_t pbuf_free_all;
447extern uint64_t pbuf_free_pool;
448extern uint64_t pbuf_free_ram;
449extern uint64_t pbuf_free_all_called;
450extern uint64_t pbuf_free_pool_called;
451extern uint64_t pbuf_free_ram_called;
452
453
454extern uint64_t pbuf_free_RX_packets;
455extern uint64_t pbuf_free_TX_packets;
456extern uint64_t pbuf_alloc_RX_packets;
457extern uint64_t pbuf_alloc_RX_packets_2;
458extern uint64_t pbuf_alloc_TX_packets;
459
460static int64_t pbuf_pool_inuse_13 = 0;
461static uint64_t memp_called_counter_13 = 0;
462static uint64_t free_counter_13 = 0;
463static uint64_t free_counter = 0;
464static uint64_t memp_called_counter = 0;
465
466
467static __attribute__((unused)) void print_stats(void)
468{
469    int64_t memp_diff = memp_called_counter_13 - free_counter_13;
470        // This should be same as pbuf_pool_inuse_13,
471
472    int64_t pbuf_pool_diff = pbuf_alloc_pool - pbuf_free_pool;
473    int64_t pbuf_ram_diff = pbuf_alloc_ram - pbuf_free_ram;
474    int64_t pbuf_diff_all = pbuf_alloc_all - pbuf_free_all;
475
476
477    printf("%-15s [%-8"PRId64"] = %-15s [%-8"PRIu64"] - %-15s [%-8"PRIu64"]\n",
478        "memp_diff", memp_diff,
479        "memp_alloc", memp_called_counter_13,
480        "memp_free", free_counter_13);
481
482    printf("%-15s [%-8"PRId64"] = %-15s [%-8"PRIu64"] - %-15s [%-8"PRIu64"]\n",
483        "pbuf_pool_diff", pbuf_pool_diff,
484        "pbuf_alloc_pool", pbuf_alloc_pool,
485        "pbuf_free_pool", pbuf_free_pool);
486
487    printf("%-15s [%-8"PRId64"] = %-15s [%-8"PRIu64"] - %-15s [%-8"PRIu64"]\n",
488        "RX_pkt_diff", (pbuf_alloc_RX_packets - pbuf_free_RX_packets),
489        "pbuf_alloc_RX_packets", pbuf_alloc_RX_packets,
490        "pbuf_free_RX_packets", pbuf_free_RX_packets);
491
492    printf("%-15s [%-8"PRId64"] = %-15s [%-8"PRIu64"] - %-15s [%-8"PRIu64"]\n",
493        "RX_pkt_diff", (pbuf_alloc_RX_packets_2 - pbuf_free_RX_packets),
494        "pbuf_alloc_RX_packets_2", pbuf_alloc_RX_packets_2,
495        "pbuf_free_RX_packets", pbuf_free_RX_packets);
496
497    printf("%-15s [%-8"PRId64"] = %-15s [%-8"PRIu64"] - %-15s [%-8"PRIu64"]\n",
498        "pbuf_ram_diff", pbuf_ram_diff,
499        "pbuf_alloc_ram", pbuf_alloc_ram,
500        "pbuf_free_ram", pbuf_free_ram);
501
502    printf("%-15s [%-8"PRId64"] = %-15s [%-8"PRIu64"] - %-15s [%-8"PRIu64"]\n",
503        "TX_pkt_diff", (pbuf_alloc_TX_packets - pbuf_free_TX_packets),
504        "pbuf_alloc_TX_packets", pbuf_alloc_TX_packets,
505        "pbuf_free_TX_packets", pbuf_free_TX_packets);
506
507
508    printf("%-15s [%-8"PRId64"] = %-15s [%-8"PRIu64"] - %-15s [%-8"PRIu64"]\n",
509        "pbuf_diff_all", pbuf_diff_all,
510        "pbuf_alloc_all", pbuf_alloc_all,
511        "pbuf_free_all", pbuf_free_all);
512
513    printf("assert memp_diff  [%"PRId64"] ==  pbuf_diff_all [%"PRId64"] =="
514            " [%"PRId64"] (pbuf_pool_diff [%"PRId64"]  + pbuf_ram_diff  [%"PRId64"] )\n",
515            memp_diff, pbuf_diff_all,  (pbuf_pool_diff  + pbuf_ram_diff),
516            pbuf_pool_diff, pbuf_ram_diff);
517
518    printf("%-15s [%-8"PRId64"] = %-15s [%-8"PRIu64"] + %-15s [%-8"PRIu64"] ==  [%-8"PRIu64"]\n",
519        "pbuf_free_all_called", pbuf_free_all_called,
520        "pbuf_free_pool_called", pbuf_free_pool_called,
521        "pbuf_free_ram_called", pbuf_free_ram_called,
522        pbuf_free_pool_called + pbuf_free_ram_called);
523
524    printf("packet_accounting: allocations (incoming packets [%"PRIu64 "] + "
525            "outgoing packets [%"PRIu64"] = [%"PRIu64"]) - "
526            "free_counter_13 [%"PRIu64"] = unaccounted[%"PRId64"] \n",
527            incoming_packet_count, outgoing_packet_count,
528            (incoming_packet_count + outgoing_packet_count),
529            free_counter_13,
530            (free_counter_13 -
531             (incoming_packet_count + outgoing_packet_count))
532          );
533
534    printf("packet_accounting: (outgoing pbufs[%"PRIu64 "], "
535            "chained pbufs[%"PRIu64"]\n", outgoing_packet_count,
536            chained_pbuf_count);
537
538#if INSTRUMENT_PBUF_CALLS
539    show_pbuf_free_stats();
540    show_pbuf_alloc_stats();
541#endif // INSTRUMENT_PBUF_CALLS
542
543    // compare pbuf_diff_all with memp_diff
544    return;
545}
546
547#if 0
548static __attribute__((unused)) void print_stats_old(void)
549{
550
551    printf("memp_malloc: failed type: inUse_13: %"PRId64
552            ", allocations_13: %"PRIu64", free_counter_13: %"PRIu64"\n",
553            pbuf_pool_inuse_13, memp_called_counter_13,
554            free_counter_13);
555
556    printf("pbuf_free: pbuf_realloc [%"PRIu64"], "
557            "(pbuf_alloc [%"PRIu64 "] - "
558            "pbuf_free [%"PRIu64", (ALL: %"PRIu64")] = unaccounted [%"PRId64"]\n",
559            pbuf_realloc_called, pbuf_alloc_called,
560            pbuf_free_called, (pbuf_free_called_all) ,
561            (pbuf_free_called - (pbuf_alloc_called ))
562          );
563
564
565
566    printf("pbuf_free_all:  (pbuf_alloc [%"PRIu64 "] + pbuf_realloc [%"PRIu64"] = "
567            " [%"PRIu64"] ) -  pbuf_free_all [%"PRIu64", (called: %"PRIu64")] "
568            "= unaccounted [%"PRId64"]\n",
569            pbuf_alloc_called, pbuf_realloc_called,
570            (pbuf_alloc_called + pbuf_realloc_called),
571            (pbuf_free_called_all), pbuf_free_called,
572            (pbuf_free_called_all -
573             (pbuf_alloc_called + pbuf_realloc_called))
574          );
575
576    printf("memp_malloc: allocations (incoming packets [%"PRIu64 "] + "
577            "outgoing packets [%"PRIu64"] = [%"PRIu64"]) - "
578            "allcations_13 [%"PRIu64"] = unaccounted[%"PRId64"] \n",
579            incoming_packet_count, outgoing_packet_count,
580            (incoming_packet_count + outgoing_packet_count),
581            memp_called_counter_13,
582            (memp_called_counter_13 -
583             (incoming_packet_count + outgoing_packet_count))
584          );
585
586
587    printf("memp_malloc: frees ( TX_done_frees [%"PRIu64 "] + "
588            "incoming packets_frees [%"PRIu64"] = [%"PRIu64"]) - "
589            "free_calls [%"PRIu64"] = unaccounted[%"PRId64"] \n",
590            pbuf_free_tx_done_counter,
591            pbuf_free_incoming_counter,
592            (pbuf_free_tx_done_counter + pbuf_free_incoming_counter),
593            free_counter_13,
594            (free_counter_13 -
595             (pbuf_free_tx_done_counter + pbuf_free_incoming_counter))
596          );
597
598#if INSTRUMENT_PBUF_CALLS
599    show_pbuf_free_stats();
600#endif // INSTRUMENT_PBUF_CALLS
601
602
603}
604
605#endif // 0
606
607
608/**
609 * Get an element from a specific pool.
610 *
611 * @param type the pool to get an element from
612 *
613 * the debug version has two more parameters:
614 * @param file file name calling this function
615 * @param line number of line where this function is called
616 *
617 * @return a pointer to the allocated memory or a NULL pointer on error
618 */
619void *
620#if !MEMP_OVERFLOW_CHECK
621
622memp_malloc(memp_t type)
623#else
624memp_malloc_fn(memp_t type, const char *file, const int line)
625#endif
626{
627    struct memp *memp;
628    memp_called_counter++;
629    SYS_ARCH_DECL_PROTECT(old_level);
630
631    LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;
632      );
633
634    SYS_ARCH_PROTECT(old_level);
635#if MEMP_OVERFLOW_CHECK >= 2
636    memp_overflow_check_all();
637#endif                          /* MEMP_OVERFLOW_CHECK >= 2 */
638
639    memp = memp_tab[type];
640
641    if (memp != NULL) {
642        memp_tab[type] = memp->next;
643        ++pbuf_pool_counter;
644        if (type == 13) {
645            memp_called_counter_13++;
646            pbuf_pool_inuse_13++;
647        }
648
649//    printf("memp_malloc: %s %"PRIu16" %"PRIu16" \n",
650//            disp_name(), type, pbuf_pool_counter);
651#if MEMP_OVERFLOW_CHECK
652        memp->next = NULL;
653        memp->file = file;
654        memp->line = line;
655#endif                          /* MEMP_OVERFLOW_CHECK */
656        MEMP_STATS_INC_USED(used, type);
657        LWIP_ASSERT("memp_malloc: memp properly aligned",
658                    ((mem_ptr_t) memp % MEM_ALIGNMENT) == 0);
659        memp = (struct memp *) ((u8_t *) memp + MEMP_SIZE);
660    } else {
661        LWIP_DEBUGF(MEMP_DEBUG | 2,
662                    ("memp_malloc: out of memory in pool %s\n",
663                     memp_desc[type]));
664        MEMP_STATS_INC(err, type);
665    }
666
667    SYS_ARCH_UNPROTECT(old_level);
668
669    if (memp == NULL) {
670#if !MEMP_OVERFLOW_CHECK
671        // NOTE: no prints here because its OK to fail in allocation.
672        // Higher levels will deal with failure.
673        // Use prints here only for debugging.
674        if (type == 13) {
675            printf("memp_malloc: failed type: %" PRIu16 ", count: %"PRIu16
676                ", memp_called: %"PRIu64", free_counter: %"PRIu64", currently free: %"PRIu16" \n",
677                type, pbuf_pool_counter, memp_called_counter, free_counter, memp_pbuf_peek() );
678
679           // print_stats_old();
680            print_stats();
681            //abort();
682        }
683#else
684        printf("memp_malloc_fn failed :\n");
685#endif
686    }
687
688    return memp;
689}
690
691/**
692 * Put an element back into its pool.
693 *
694 * @param type the pool where to put mem
695 * @param mem the memp element to free
696 */
697void memp_free(memp_t type, void *mem)
698{
699    ++free_counter;
700/*    printf("memp_free %s called for type %"PRIu16" with counter "
701            "%"PRIu16", free counter %"PRIu64"\n",
702           disp_name(), type, pbuf_pool_counter, free_counter);
703*/
704    struct memp *memp;
705
706    SYS_ARCH_DECL_PROTECT(old_level);
707
708    if (mem == NULL) {
709        printf("memp_free: mem is NULL\n");
710        return;
711    }
712    LWIP_ASSERT("memp_free: mem properly aligned",
713                ((mem_ptr_t) mem % MEM_ALIGNMENT) == 0);
714
715    memp = (struct memp *) ((u8_t *) mem - MEMP_SIZE);
716
717    SYS_ARCH_PROTECT(old_level);
718#if MEMP_OVERFLOW_CHECK
719#if MEMP_OVERFLOW_CHECK >= 2
720    memp_overflow_check_all();
721#else
722    memp_overflow_check_element(memp, Nemp_sizes[type]);
723#endif                          /* MEMP_OVERFLOW_CHECK >= 2 */
724#endif                          /* MEMP_OVERFLOW_CHECK */
725
726    MEMP_STATS_DEC(used, type);
727
728    memp->next = memp_tab[type];
729    memp_tab[type] = memp;
730    assert(pbuf_pool_counter > 0);
731    --pbuf_pool_counter;
732
733    if (type == 13) {
734        --pbuf_pool_inuse_13;
735        ++free_counter_13;
736    }
737
738#if MEMP_SANITY_CHECK
739    LWIP_ASSERT("memp sanity", memp_sanity());
740#endif                          /* MEMP_SANITY_CHECK */
741
742    SYS_ARCH_UNPROTECT(old_level);
743}
744
745#endif                          /* MEMP_MEM_MALLOC */
746