]> git.proxmox.com Git - mirror_frr.git/blob - lib/memory.c
memory: restore 'memstats:' keyword when logging memstats - useful in log
[mirror_frr.git] / lib / memory.c
1 /*
2 * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23 #include <zebra.h>
24
25 #include <stdlib.h>
26
27 #include "memory.h"
28
29 static struct memgroup *mg_first = NULL;
30 struct memgroup **mg_insert = &mg_first;
31
32 DEFINE_MGROUP(LIB, "libzebra")
33 DEFINE_MTYPE(LIB, TMP, "Temporary memory")
34
35 static inline void
36 mt_count_alloc (struct memtype *mt, size_t size)
37 {
38 mt->n_alloc++;
39
40 if (mt->size == 0)
41 mt->size = size;
42 else if (mt->size != size)
43 mt->size = SIZE_VAR;
44 }
45
46 static inline void
47 mt_count_free (struct memtype *mt)
48 {
49 mt->n_alloc--;
50 }
51
52 static inline void *
53 mt_checkalloc (struct memtype *mt, void *ptr, size_t size)
54 {
55 if (__builtin_expect(ptr == NULL, 0))
56 {
57 memory_oom (size, mt->name);
58 return NULL;
59 }
60 mt_count_alloc (mt, size);
61 return ptr;
62 }
63
64 void *
65 qmalloc (struct memtype *mt, size_t size)
66 {
67 return mt_checkalloc (mt, malloc (size), size);
68 }
69
70 void *
71 qcalloc (struct memtype *mt, size_t size)
72 {
73 return mt_checkalloc (mt, calloc (size, 1), size);
74 }
75
76 void *
77 qrealloc (struct memtype *mt, void *ptr, size_t size)
78 {
79 if (ptr)
80 mt_count_free (mt);
81 return mt_checkalloc (mt, ptr ? realloc (ptr, size) : malloc (size), size);
82 }
83
84 void *
85 qstrdup (struct memtype *mt, const char *str)
86 {
87 return mt_checkalloc (mt, strdup (str), strlen (str) + 1);
88 }
89
90 void
91 qfree (struct memtype *mt, void *ptr)
92 {
93 if (ptr)
94 mt_count_free (mt);
95 free (ptr);
96 }
97
98 int
99 qmem_walk (qmem_walk_fn *func, void *arg)
100 {
101 struct memgroup *mg;
102 struct memtype *mt;
103 int rv;
104
105 for (mg = mg_first; mg; mg = mg->next)
106 {
107 if ((rv = func (arg, mg, NULL)))
108 return rv;
109 for (mt = mg->types; mt; mt = mt->next)
110 if ((rv = func (arg, mg, mt)))
111 return rv;
112 }
113 return 0;
114 }
115
116 struct exit_dump_args
117 {
118 const char *prefix;
119 int error;
120 };
121
122 static int
123 qmem_exit_walker (void *arg, struct memgroup *mg, struct memtype *mt)
124 {
125 struct exit_dump_args *eda = arg;
126
127 if (!mt)
128 {
129 fprintf (stderr, "%s: showing active allocations in memory group %s\n",
130 eda->prefix, mg->name);
131 }
132 else if (mt->n_alloc)
133 {
134 char size[32];
135 eda->error++;
136 snprintf (size, sizeof (size), "%10zu", mt->size);
137 fprintf (stderr, "%s: memstats: %-30s: %6zu * %s\n",
138 eda->prefix, mt->name, mt->n_alloc,
139 mt->size == SIZE_VAR ? "(variably sized)" : size);
140 }
141 return 0;
142 }
143
144 void
145 log_memstats_stderr (const char *prefix)
146 {
147 struct exit_dump_args eda = { .prefix = prefix, .error = 0 };
148 qmem_walk (qmem_exit_walker, &eda);
149 }