Annotation of embedaddon/quagga/lib/memory.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Memory management routine
! 3: * Copyright (C) 1998 Kunihiro Ishiguro
! 4: *
! 5: * This file is part of GNU Zebra.
! 6: *
! 7: * GNU Zebra is free software; you can redistribute it and/or modify it
! 8: * under the terms of the GNU General Public License as published by the
! 9: * Free Software Foundation; either version 2, or (at your option) any
! 10: * later version.
! 11: *
! 12: * GNU Zebra is distributed in the hope that it will be useful, but
! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of
! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 15: * General Public License for more details.
! 16: *
! 17: * You should have received a copy of the GNU General Public License
! 18: * along with GNU Zebra; see the file COPYING. If not, write to the Free
! 19: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 20: * 02111-1307, USA.
! 21: */
! 22:
! 23: #include <zebra.h>
! 24: /* malloc.h is generally obsolete, however GNU Libc mallinfo wants it. */
! 25: #if !defined(HAVE_STDLIB_H) || (defined(GNU_LINUX) && defined(HAVE_MALLINFO))
! 26: #include <malloc.h>
! 27: #endif /* !HAVE_STDLIB_H || HAVE_MALLINFO */
! 28:
! 29: #include "log.h"
! 30: #include "memory.h"
! 31:
! 32: static void alloc_inc (int);
! 33: static void alloc_dec (int);
! 34: static void log_memstats(int log_priority);
! 35:
! 36: static const struct message mstr [] =
! 37: {
! 38: { MTYPE_THREAD, "thread" },
! 39: { MTYPE_THREAD_MASTER, "thread_master" },
! 40: { MTYPE_VECTOR, "vector" },
! 41: { MTYPE_VECTOR_INDEX, "vector_index" },
! 42: { MTYPE_IF, "interface" },
! 43: { 0, NULL },
! 44: };
! 45:
! 46: /* Fatal memory allocation error occured. */
! 47: static void __attribute__ ((noreturn))
! 48: zerror (const char *fname, int type, size_t size)
! 49: {
! 50: zlog_err ("%s : can't allocate memory for `%s' size %d: %s\n",
! 51: fname, lookup (mstr, type), (int) size, safe_strerror(errno));
! 52: log_memstats(LOG_WARNING);
! 53: /* N.B. It might be preferable to call zlog_backtrace_sigsafe here, since
! 54: that function should definitely be safe in an OOM condition. But
! 55: unfortunately zlog_backtrace_sigsafe does not support syslog logging at
! 56: this time... */
! 57: zlog_backtrace(LOG_WARNING);
! 58: abort();
! 59: }
! 60:
! 61: /*
! 62: * Allocate memory of a given size, to be tracked by a given type.
! 63: * Effects: Returns a pointer to usable memory. If memory cannot
! 64: * be allocated, aborts execution.
! 65: */
! 66: void *
! 67: zmalloc (int type, size_t size)
! 68: {
! 69: void *memory;
! 70:
! 71: memory = malloc (size);
! 72:
! 73: if (memory == NULL)
! 74: zerror ("malloc", type, size);
! 75:
! 76: alloc_inc (type);
! 77:
! 78: return memory;
! 79: }
! 80:
! 81: /*
! 82: * Allocate memory as in zmalloc, and also clear the memory.
! 83: */
! 84: void *
! 85: zcalloc (int type, size_t size)
! 86: {
! 87: void *memory;
! 88:
! 89: memory = calloc (1, size);
! 90:
! 91: if (memory == NULL)
! 92: zerror ("calloc", type, size);
! 93:
! 94: alloc_inc (type);
! 95:
! 96: return memory;
! 97: }
! 98:
! 99: /*
! 100: * Given a pointer returned by zmalloc or zcalloc, free it and
! 101: * return a pointer to a new size, basically acting like realloc().
! 102: * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the
! 103: * same type.
! 104: * Effects: Returns a pointer to the new memory, or aborts.
! 105: */
! 106: void *
! 107: zrealloc (int type, void *ptr, size_t size)
! 108: {
! 109: void *memory;
! 110:
! 111: memory = realloc (ptr, size);
! 112: if (memory == NULL)
! 113: zerror ("realloc", type, size);
! 114: if (ptr == NULL)
! 115: alloc_inc (type);
! 116:
! 117: return memory;
! 118: }
! 119:
! 120: /*
! 121: * Free memory allocated by z*alloc or zstrdup.
! 122: * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the
! 123: * same type.
! 124: * Effects: The memory is freed and may no longer be referenced.
! 125: */
! 126: void
! 127: zfree (int type, void *ptr)
! 128: {
! 129: if (ptr != NULL)
! 130: {
! 131: alloc_dec (type);
! 132: free (ptr);
! 133: }
! 134: }
! 135:
! 136: /*
! 137: * Duplicate a string, counting memory usage by type.
! 138: * Effects: The string is duplicated, and the return value must
! 139: * eventually be passed to zfree with the same type. The function will
! 140: * succeed or abort.
! 141: */
! 142: char *
! 143: zstrdup (int type, const char *str)
! 144: {
! 145: void *dup;
! 146:
! 147: dup = strdup (str);
! 148: if (dup == NULL)
! 149: zerror ("strdup", type, strlen (str));
! 150: alloc_inc (type);
! 151: return dup;
! 152: }
! 153:
! 154: #ifdef MEMORY_LOG
! 155: static struct
! 156: {
! 157: const char *name;
! 158: long alloc;
! 159: unsigned long t_malloc;
! 160: unsigned long c_malloc;
! 161: unsigned long t_calloc;
! 162: unsigned long c_calloc;
! 163: unsigned long t_realloc;
! 164: unsigned long t_free;
! 165: unsigned long c_strdup;
! 166: } mstat [MTYPE_MAX];
! 167:
! 168: static void
! 169: mtype_log (char *func, void *memory, const char *file, int line, int type)
! 170: {
! 171: zlog_debug ("%s: %s %p %s %d", func, lookup (mstr, type), memory, file, line);
! 172: }
! 173:
! 174: void *
! 175: mtype_zmalloc (const char *file, int line, int type, size_t size)
! 176: {
! 177: void *memory;
! 178:
! 179: mstat[type].c_malloc++;
! 180: mstat[type].t_malloc++;
! 181:
! 182: memory = zmalloc (type, size);
! 183: mtype_log ("zmalloc", memory, file, line, type);
! 184:
! 185: return memory;
! 186: }
! 187:
! 188: void *
! 189: mtype_zcalloc (const char *file, int line, int type, size_t size)
! 190: {
! 191: void *memory;
! 192:
! 193: mstat[type].c_calloc++;
! 194: mstat[type].t_calloc++;
! 195:
! 196: memory = zcalloc (type, size);
! 197: mtype_log ("xcalloc", memory, file, line, type);
! 198:
! 199: return memory;
! 200: }
! 201:
! 202: void *
! 203: mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size)
! 204: {
! 205: void *memory;
! 206:
! 207: /* Realloc need before allocated pointer. */
! 208: mstat[type].t_realloc++;
! 209:
! 210: memory = zrealloc (type, ptr, size);
! 211:
! 212: mtype_log ("xrealloc", memory, file, line, type);
! 213:
! 214: return memory;
! 215: }
! 216:
! 217: /* Important function. */
! 218: void
! 219: mtype_zfree (const char *file, int line, int type, void *ptr)
! 220: {
! 221: mstat[type].t_free++;
! 222:
! 223: mtype_log ("xfree", ptr, file, line, type);
! 224:
! 225: zfree (type, ptr);
! 226: }
! 227:
! 228: char *
! 229: mtype_zstrdup (const char *file, int line, int type, const char *str)
! 230: {
! 231: char *memory;
! 232:
! 233: mstat[type].c_strdup++;
! 234:
! 235: memory = zstrdup (type, str);
! 236:
! 237: mtype_log ("xstrdup", memory, file, line, type);
! 238:
! 239: return memory;
! 240: }
! 241: #else
! 242: static struct
! 243: {
! 244: char *name;
! 245: long alloc;
! 246: } mstat [MTYPE_MAX];
! 247: #endif /* MEMORY_LOG */
! 248:
! 249: /* Increment allocation counter. */
! 250: static void
! 251: alloc_inc (int type)
! 252: {
! 253: mstat[type].alloc++;
! 254: }
! 255:
! 256: /* Decrement allocation counter. */
! 257: static void
! 258: alloc_dec (int type)
! 259: {
! 260: mstat[type].alloc--;
! 261: }
! 262:
! 263: /* Looking up memory status from vty interface. */
! 264: #include "vector.h"
! 265: #include "vty.h"
! 266: #include "command.h"
! 267:
! 268: static void
! 269: log_memstats(int pri)
! 270: {
! 271: struct mlist *ml;
! 272:
! 273: for (ml = mlists; ml->list; ml++)
! 274: {
! 275: struct memory_list *m;
! 276:
! 277: zlog (NULL, pri, "Memory utilization in module %s:", ml->name);
! 278: for (m = ml->list; m->index >= 0; m++)
! 279: if (m->index && mstat[m->index].alloc)
! 280: zlog (NULL, pri, " %-30s: %10ld", m->format, mstat[m->index].alloc);
! 281: }
! 282: }
! 283:
! 284: void
! 285: log_memstats_stderr (const char *prefix)
! 286: {
! 287: struct mlist *ml;
! 288: struct memory_list *m;
! 289: int i;
! 290: int j = 0;
! 291:
! 292: for (ml = mlists; ml->list; ml++)
! 293: {
! 294: i = 0;
! 295:
! 296: for (m = ml->list; m->index >= 0; m++)
! 297: if (m->index && mstat[m->index].alloc)
! 298: {
! 299: if (!i)
! 300: fprintf (stderr,
! 301: "%s: memstats: Current memory utilization in module %s:\n",
! 302: prefix,
! 303: ml->name);
! 304: fprintf (stderr,
! 305: "%s: memstats: %-30s: %10ld%s\n",
! 306: prefix,
! 307: m->format,
! 308: mstat[m->index].alloc,
! 309: mstat[m->index].alloc < 0 ? " (REPORT THIS BUG!)" : "");
! 310: i = j = 1;
! 311: }
! 312: }
! 313:
! 314: if (j)
! 315: fprintf (stderr,
! 316: "%s: memstats: NOTE: If configuration exists, utilization may be "
! 317: "expected.\n",
! 318: prefix);
! 319: else
! 320: fprintf (stderr,
! 321: "%s: memstats: No remaining tracked memory utilization.\n",
! 322: prefix);
! 323: }
! 324:
! 325: static void
! 326: show_separator(struct vty *vty)
! 327: {
! 328: vty_out (vty, "-----------------------------\r\n");
! 329: }
! 330:
! 331: static int
! 332: show_memory_vty (struct vty *vty, struct memory_list *list)
! 333: {
! 334: struct memory_list *m;
! 335: int needsep = 0;
! 336:
! 337: for (m = list; m->index >= 0; m++)
! 338: if (m->index == 0)
! 339: {
! 340: if (needsep)
! 341: {
! 342: show_separator (vty);
! 343: needsep = 0;
! 344: }
! 345: }
! 346: else if (mstat[m->index].alloc)
! 347: {
! 348: vty_out (vty, "%-30s: %10ld\r\n", m->format, mstat[m->index].alloc);
! 349: needsep = 1;
! 350: }
! 351: return needsep;
! 352: }
! 353:
! 354: #ifdef HAVE_MALLINFO
! 355: static int
! 356: show_memory_mallinfo (struct vty *vty)
! 357: {
! 358: struct mallinfo minfo = mallinfo();
! 359: char buf[MTYPE_MEMSTR_LEN];
! 360:
! 361: vty_out (vty, "System allocator statistics:%s", VTY_NEWLINE);
! 362: vty_out (vty, " Total heap allocated: %s%s",
! 363: mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.arena),
! 364: VTY_NEWLINE);
! 365: vty_out (vty, " Holding block headers: %s%s",
! 366: mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.hblkhd),
! 367: VTY_NEWLINE);
! 368: vty_out (vty, " Used small blocks: %s%s",
! 369: mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.usmblks),
! 370: VTY_NEWLINE);
! 371: vty_out (vty, " Used ordinary blocks: %s%s",
! 372: mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.uordblks),
! 373: VTY_NEWLINE);
! 374: vty_out (vty, " Free small blocks: %s%s",
! 375: mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fsmblks),
! 376: VTY_NEWLINE);
! 377: vty_out (vty, " Free ordinary blocks: %s%s",
! 378: mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fordblks),
! 379: VTY_NEWLINE);
! 380: vty_out (vty, " Ordinary blocks: %ld%s",
! 381: (unsigned long)minfo.ordblks,
! 382: VTY_NEWLINE);
! 383: vty_out (vty, " Small blocks: %ld%s",
! 384: (unsigned long)minfo.smblks,
! 385: VTY_NEWLINE);
! 386: vty_out (vty, " Holding blocks: %ld%s",
! 387: (unsigned long)minfo.hblks,
! 388: VTY_NEWLINE);
! 389: vty_out (vty, "(see system documentation for 'mallinfo' for meaning)%s",
! 390: VTY_NEWLINE);
! 391: return 1;
! 392: }
! 393: #endif /* HAVE_MALLINFO */
! 394:
! 395: DEFUN (show_memory_all,
! 396: show_memory_all_cmd,
! 397: "show memory all",
! 398: "Show running system information\n"
! 399: "Memory statistics\n"
! 400: "All memory statistics\n")
! 401: {
! 402: struct mlist *ml;
! 403: int needsep = 0;
! 404:
! 405: #ifdef HAVE_MALLINFO
! 406: needsep = show_memory_mallinfo (vty);
! 407: #endif /* HAVE_MALLINFO */
! 408:
! 409: for (ml = mlists; ml->list; ml++)
! 410: {
! 411: if (needsep)
! 412: show_separator (vty);
! 413: needsep = show_memory_vty (vty, ml->list);
! 414: }
! 415:
! 416: return CMD_SUCCESS;
! 417: }
! 418:
! 419: ALIAS (show_memory_all,
! 420: show_memory_cmd,
! 421: "show memory",
! 422: "Show running system information\n"
! 423: "Memory statistics\n")
! 424:
! 425: DEFUN (show_memory_lib,
! 426: show_memory_lib_cmd,
! 427: "show memory lib",
! 428: SHOW_STR
! 429: "Memory statistics\n"
! 430: "Library memory\n")
! 431: {
! 432: show_memory_vty (vty, memory_list_lib);
! 433: return CMD_SUCCESS;
! 434: }
! 435:
! 436: DEFUN (show_memory_zebra,
! 437: show_memory_zebra_cmd,
! 438: "show memory zebra",
! 439: SHOW_STR
! 440: "Memory statistics\n"
! 441: "Zebra memory\n")
! 442: {
! 443: show_memory_vty (vty, memory_list_zebra);
! 444: return CMD_SUCCESS;
! 445: }
! 446:
! 447: DEFUN (show_memory_rip,
! 448: show_memory_rip_cmd,
! 449: "show memory rip",
! 450: SHOW_STR
! 451: "Memory statistics\n"
! 452: "RIP memory\n")
! 453: {
! 454: show_memory_vty (vty, memory_list_rip);
! 455: return CMD_SUCCESS;
! 456: }
! 457:
! 458: DEFUN (show_memory_ripng,
! 459: show_memory_ripng_cmd,
! 460: "show memory ripng",
! 461: SHOW_STR
! 462: "Memory statistics\n"
! 463: "RIPng memory\n")
! 464: {
! 465: show_memory_vty (vty, memory_list_ripng);
! 466: return CMD_SUCCESS;
! 467: }
! 468:
! 469: DEFUN (show_memory_bgp,
! 470: show_memory_bgp_cmd,
! 471: "show memory bgp",
! 472: SHOW_STR
! 473: "Memory statistics\n"
! 474: "BGP memory\n")
! 475: {
! 476: show_memory_vty (vty, memory_list_bgp);
! 477: return CMD_SUCCESS;
! 478: }
! 479:
! 480: DEFUN (show_memory_ospf,
! 481: show_memory_ospf_cmd,
! 482: "show memory ospf",
! 483: SHOW_STR
! 484: "Memory statistics\n"
! 485: "OSPF memory\n")
! 486: {
! 487: show_memory_vty (vty, memory_list_ospf);
! 488: return CMD_SUCCESS;
! 489: }
! 490:
! 491: DEFUN (show_memory_ospf6,
! 492: show_memory_ospf6_cmd,
! 493: "show memory ospf6",
! 494: SHOW_STR
! 495: "Memory statistics\n"
! 496: "OSPF6 memory\n")
! 497: {
! 498: show_memory_vty (vty, memory_list_ospf6);
! 499: return CMD_SUCCESS;
! 500: }
! 501:
! 502: DEFUN (show_memory_isis,
! 503: show_memory_isis_cmd,
! 504: "show memory isis",
! 505: SHOW_STR
! 506: "Memory statistics\n"
! 507: "ISIS memory\n")
! 508: {
! 509: show_memory_vty (vty, memory_list_isis);
! 510: return CMD_SUCCESS;
! 511: }
! 512:
! 513: void
! 514: memory_init (void)
! 515: {
! 516: install_element (RESTRICTED_NODE, &show_memory_cmd);
! 517: install_element (RESTRICTED_NODE, &show_memory_all_cmd);
! 518: install_element (RESTRICTED_NODE, &show_memory_lib_cmd);
! 519: install_element (RESTRICTED_NODE, &show_memory_rip_cmd);
! 520: install_element (RESTRICTED_NODE, &show_memory_ripng_cmd);
! 521: install_element (RESTRICTED_NODE, &show_memory_bgp_cmd);
! 522: install_element (RESTRICTED_NODE, &show_memory_ospf_cmd);
! 523: install_element (RESTRICTED_NODE, &show_memory_ospf6_cmd);
! 524: install_element (RESTRICTED_NODE, &show_memory_isis_cmd);
! 525:
! 526: install_element (VIEW_NODE, &show_memory_cmd);
! 527: install_element (VIEW_NODE, &show_memory_all_cmd);
! 528: install_element (VIEW_NODE, &show_memory_lib_cmd);
! 529: install_element (VIEW_NODE, &show_memory_rip_cmd);
! 530: install_element (VIEW_NODE, &show_memory_ripng_cmd);
! 531: install_element (VIEW_NODE, &show_memory_bgp_cmd);
! 532: install_element (VIEW_NODE, &show_memory_ospf_cmd);
! 533: install_element (VIEW_NODE, &show_memory_ospf6_cmd);
! 534: install_element (VIEW_NODE, &show_memory_isis_cmd);
! 535:
! 536: install_element (ENABLE_NODE, &show_memory_cmd);
! 537: install_element (ENABLE_NODE, &show_memory_all_cmd);
! 538: install_element (ENABLE_NODE, &show_memory_lib_cmd);
! 539: install_element (ENABLE_NODE, &show_memory_zebra_cmd);
! 540: install_element (ENABLE_NODE, &show_memory_rip_cmd);
! 541: install_element (ENABLE_NODE, &show_memory_ripng_cmd);
! 542: install_element (ENABLE_NODE, &show_memory_bgp_cmd);
! 543: install_element (ENABLE_NODE, &show_memory_ospf_cmd);
! 544: install_element (ENABLE_NODE, &show_memory_ospf6_cmd);
! 545: install_element (ENABLE_NODE, &show_memory_isis_cmd);
! 546: }
! 547:
! 548: /* Stats querying from users */
! 549: /* Return a pointer to a human friendly string describing
! 550: * the byte count passed in. E.g:
! 551: * "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc.
! 552: * Up to 4 significant figures will be given.
! 553: * The pointer returned may be NULL (indicating an error)
! 554: * or point to the given buffer, or point to static storage.
! 555: */
! 556: const char *
! 557: mtype_memstr (char *buf, size_t len, unsigned long bytes)
! 558: {
! 559: unsigned int t, g, m, k;
! 560:
! 561: /* easy cases */
! 562: if (!bytes)
! 563: return "0 bytes";
! 564: if (bytes == 1)
! 565: return "1 byte";
! 566:
! 567: if (sizeof (unsigned long) >= 8)
! 568: /* Hacked to make it not warn on ILP32 machines
! 569: * Shift will always be 40 at runtime. See below too */
! 570: t = bytes >> (sizeof (unsigned long) >= 8 ? 40 : 0);
! 571: else
! 572: t = 0;
! 573: g = bytes >> 30;
! 574: m = bytes >> 20;
! 575: k = bytes >> 10;
! 576:
! 577: if (t > 10)
! 578: {
! 579: /* The shift will always be 39 at runtime.
! 580: * Just hacked to make it not warn on 'smaller' machines.
! 581: * Static compiler analysis should mean no extra code
! 582: */
! 583: if (bytes & (1UL << (sizeof (unsigned long) >= 8 ? 39 : 0)))
! 584: t++;
! 585: snprintf (buf, len, "%4d TiB", t);
! 586: }
! 587: else if (g > 10)
! 588: {
! 589: if (bytes & (1 << 29))
! 590: g++;
! 591: snprintf (buf, len, "%d GiB", g);
! 592: }
! 593: else if (m > 10)
! 594: {
! 595: if (bytes & (1 << 19))
! 596: m++;
! 597: snprintf (buf, len, "%d MiB", m);
! 598: }
! 599: else if (k > 10)
! 600: {
! 601: if (bytes & (1 << 9))
! 602: k++;
! 603: snprintf (buf, len, "%d KiB", k);
! 604: }
! 605: else
! 606: snprintf (buf, len, "%ld bytes", bytes);
! 607:
! 608: return buf;
! 609: }
! 610:
! 611: unsigned long
! 612: mtype_stats_alloc (int type)
! 613: {
! 614: return mstat[type].alloc;
! 615: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>