File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / memory.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:12 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_20_1, v0_99_20, HEAD
quagga

    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>