Annotation of embedaddon/quagga/lib/memory.c, revision 1.1.1.2
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:
1.1.1.2 ! misho 469: DEFUN (show_memory_babel,
! 470: show_memory_babel_cmd,
! 471: "show memory babel",
! 472: SHOW_STR
! 473: "Memory statistics\n"
! 474: "Babel memory\n")
! 475: {
! 476: show_memory_vty (vty, memory_list_babel);
! 477: return CMD_SUCCESS;
! 478: }
! 479:
1.1 misho 480: DEFUN (show_memory_bgp,
481: show_memory_bgp_cmd,
482: "show memory bgp",
483: SHOW_STR
484: "Memory statistics\n"
485: "BGP memory\n")
486: {
487: show_memory_vty (vty, memory_list_bgp);
488: return CMD_SUCCESS;
489: }
490:
491: DEFUN (show_memory_ospf,
492: show_memory_ospf_cmd,
493: "show memory ospf",
494: SHOW_STR
495: "Memory statistics\n"
496: "OSPF memory\n")
497: {
498: show_memory_vty (vty, memory_list_ospf);
499: return CMD_SUCCESS;
500: }
501:
502: DEFUN (show_memory_ospf6,
503: show_memory_ospf6_cmd,
504: "show memory ospf6",
505: SHOW_STR
506: "Memory statistics\n"
507: "OSPF6 memory\n")
508: {
509: show_memory_vty (vty, memory_list_ospf6);
510: return CMD_SUCCESS;
511: }
512:
513: DEFUN (show_memory_isis,
514: show_memory_isis_cmd,
515: "show memory isis",
516: SHOW_STR
517: "Memory statistics\n"
518: "ISIS memory\n")
519: {
520: show_memory_vty (vty, memory_list_isis);
521: return CMD_SUCCESS;
522: }
523:
524: void
525: memory_init (void)
526: {
527: install_element (RESTRICTED_NODE, &show_memory_cmd);
528: install_element (RESTRICTED_NODE, &show_memory_all_cmd);
529: install_element (RESTRICTED_NODE, &show_memory_lib_cmd);
530: install_element (RESTRICTED_NODE, &show_memory_rip_cmd);
531: install_element (RESTRICTED_NODE, &show_memory_ripng_cmd);
1.1.1.2 ! misho 532: install_element (RESTRICTED_NODE, &show_memory_babel_cmd);
1.1 misho 533: install_element (RESTRICTED_NODE, &show_memory_bgp_cmd);
534: install_element (RESTRICTED_NODE, &show_memory_ospf_cmd);
535: install_element (RESTRICTED_NODE, &show_memory_ospf6_cmd);
536: install_element (RESTRICTED_NODE, &show_memory_isis_cmd);
537:
538: install_element (VIEW_NODE, &show_memory_cmd);
539: install_element (VIEW_NODE, &show_memory_all_cmd);
540: install_element (VIEW_NODE, &show_memory_lib_cmd);
541: install_element (VIEW_NODE, &show_memory_rip_cmd);
542: install_element (VIEW_NODE, &show_memory_ripng_cmd);
1.1.1.2 ! misho 543: install_element (VIEW_NODE, &show_memory_babel_cmd);
1.1 misho 544: install_element (VIEW_NODE, &show_memory_bgp_cmd);
545: install_element (VIEW_NODE, &show_memory_ospf_cmd);
546: install_element (VIEW_NODE, &show_memory_ospf6_cmd);
547: install_element (VIEW_NODE, &show_memory_isis_cmd);
548:
549: install_element (ENABLE_NODE, &show_memory_cmd);
550: install_element (ENABLE_NODE, &show_memory_all_cmd);
551: install_element (ENABLE_NODE, &show_memory_lib_cmd);
552: install_element (ENABLE_NODE, &show_memory_zebra_cmd);
553: install_element (ENABLE_NODE, &show_memory_rip_cmd);
554: install_element (ENABLE_NODE, &show_memory_ripng_cmd);
1.1.1.2 ! misho 555: install_element (ENABLE_NODE, &show_memory_babel_cmd);
1.1 misho 556: install_element (ENABLE_NODE, &show_memory_bgp_cmd);
557: install_element (ENABLE_NODE, &show_memory_ospf_cmd);
558: install_element (ENABLE_NODE, &show_memory_ospf6_cmd);
559: install_element (ENABLE_NODE, &show_memory_isis_cmd);
560: }
561:
562: /* Stats querying from users */
563: /* Return a pointer to a human friendly string describing
564: * the byte count passed in. E.g:
565: * "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc.
566: * Up to 4 significant figures will be given.
567: * The pointer returned may be NULL (indicating an error)
568: * or point to the given buffer, or point to static storage.
569: */
570: const char *
571: mtype_memstr (char *buf, size_t len, unsigned long bytes)
572: {
573: unsigned int t, g, m, k;
574:
575: /* easy cases */
576: if (!bytes)
577: return "0 bytes";
578: if (bytes == 1)
579: return "1 byte";
580:
581: if (sizeof (unsigned long) >= 8)
582: /* Hacked to make it not warn on ILP32 machines
583: * Shift will always be 40 at runtime. See below too */
584: t = bytes >> (sizeof (unsigned long) >= 8 ? 40 : 0);
585: else
586: t = 0;
587: g = bytes >> 30;
588: m = bytes >> 20;
589: k = bytes >> 10;
590:
591: if (t > 10)
592: {
593: /* The shift will always be 39 at runtime.
594: * Just hacked to make it not warn on 'smaller' machines.
595: * Static compiler analysis should mean no extra code
596: */
597: if (bytes & (1UL << (sizeof (unsigned long) >= 8 ? 39 : 0)))
598: t++;
599: snprintf (buf, len, "%4d TiB", t);
600: }
601: else if (g > 10)
602: {
603: if (bytes & (1 << 29))
604: g++;
605: snprintf (buf, len, "%d GiB", g);
606: }
607: else if (m > 10)
608: {
609: if (bytes & (1 << 19))
610: m++;
611: snprintf (buf, len, "%d MiB", m);
612: }
613: else if (k > 10)
614: {
615: if (bytes & (1 << 9))
616: k++;
617: snprintf (buf, len, "%d KiB", k);
618: }
619: else
620: snprintf (buf, len, "%ld bytes", bytes);
621:
622: return buf;
623: }
624:
625: unsigned long
626: mtype_stats_alloc (int type)
627: {
628: return mstat[type].alloc;
629: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>