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