]> git.proxmox.com Git - mirror_frr.git/blob - lib/memory.h
lib: clean/restore memory debugging functions
[mirror_frr.git] / lib / memory.h
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 #ifndef _QUAGGA_MEMORY_H
24 #define _QUAGGA_MEMORY_H
25
26 #include <stdlib.h>
27
28 #define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
29
30 #define SIZE_VAR ~0UL
31 struct memtype
32 {
33 struct memtype *next;
34 const char *name;
35 size_t n_alloc;
36 size_t size;
37 };
38
39 struct memgroup
40 {
41 struct memgroup *next;
42 struct memtype *types, **insert;
43 const char *name;
44 };
45
46 #if defined(__clang__)
47 # if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5)
48 # define _RET_NONNULL , returns_nonnull
49 # endif
50 # define _CONSTRUCTOR(x) constructor(x)
51 #elif defined(__GNUC__)
52 # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
53 # define _RET_NONNULL , returns_nonnull
54 # endif
55 # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
56 # define _CONSTRUCTOR(x) constructor(x)
57 # define _ALLOC_SIZE(x) alloc_size(x)
58 # endif
59 #endif
60
61 #ifdef __sun
62 /* Solaris doesn't do constructor priorities due to linker restrictions */
63 # undef _CONSTRUCTOR
64 #endif
65
66 #ifndef _RET_NONNULL
67 # define _RET_NONNULL
68 #endif
69 #ifndef _CONSTRUCTOR
70 # define _CONSTRUCTOR(x) constructor
71 #endif
72 #ifndef _ALLOC_SIZE
73 # define _ALLOC_SIZE(x)
74 #endif
75
76 /* macro usage:
77 *
78 * mydaemon.h
79 * DECLARE_MGROUP(MYDAEMON)
80 * DECLARE_MTYPE(MYDAEMON_COMMON)
81 *
82 * mydaemon.c
83 * DEFINE_MGROUP(MYDAEMON, "my daemon memory")
84 * DEFINE_MTYPE(MYDAEMON, MYDAEMON_COMMON,
85 * "this mtype is used in multiple files in mydaemon")
86 * foo = qmalloc (MTYPE_MYDAEMON_COMMON, sizeof (*foo))
87 *
88 * mydaemon_io.c
89 * bar = qmalloc (MTYPE_MYDAEMON_COMMON, sizeof (*bar))
90 *
91 * DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO,
92 * "this mtype is used only in this file")
93 * baz = qmalloc (MTYPE_MYDAEMON_IO, sizeof (*baz))
94 *
95 * Note: Naming conventions (MGROUP_ and MTYPE_ prefixes are enforced
96 * by not having these as part of the macro arguments)
97 * Note: MTYPE_* are symbols to the compiler (of type struct memtype *),
98 * but MGROUP_* aren't.
99 */
100
101 #define DECLARE_MGROUP(name) \
102 extern struct memgroup _mg_##name;
103 #define DEFINE_MGROUP(mname, desc) \
104 struct memgroup _mg_##mname \
105 __attribute__ ((section (".data.mgroups"))) = { \
106 .name = desc, \
107 .types = NULL, .next = NULL, .insert = NULL, \
108 }; \
109 static void _mginit_##mname (void) \
110 __attribute__ ((_CONSTRUCTOR (1000))); \
111 static void _mginit_##mname (void) \
112 { extern struct memgroup **mg_insert; \
113 *mg_insert = &_mg_##mname; \
114 mg_insert = &_mg_##mname.next; }
115
116
117 #define DECLARE_MTYPE(name) \
118 extern struct memtype _mt_##name; \
119 static struct memtype * const MTYPE_ ## name = &_mt_##name;
120
121 #define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \
122 attr struct memtype _mt_##mname \
123 __attribute__ ((section (".data.mtypes"))) = { \
124 .name = desc, \
125 .next = NULL, .n_alloc = 0, .size = 0, \
126 }; \
127 static void _mtinit_##mname (void) \
128 __attribute__ ((_CONSTRUCTOR (1001))); \
129 static void _mtinit_##mname (void) \
130 { if (_mg_##group.insert == NULL) \
131 _mg_##group.insert = &_mg_##group.types; \
132 *_mg_##group.insert = &_mt_##mname; \
133 _mg_##group.insert = &_mt_##mname.next; }
134
135 #define DEFINE_MTYPE(group, name, desc) \
136 DEFINE_MTYPE_ATTR(group, name, , desc)
137 #define DEFINE_MTYPE_STATIC(group, name, desc) \
138 DEFINE_MTYPE_ATTR(group, name, static, desc) \
139 static struct memtype * const MTYPE_ ## name = &_mt_##name;
140
141 DECLARE_MGROUP(LIB)
142 DECLARE_MTYPE(TMP)
143
144
145 extern void *qmalloc (struct memtype *mt, size_t size)
146 __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL));
147 extern void *qcalloc (struct memtype *mt, size_t size)
148 __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL));
149 extern void *qrealloc (struct memtype *mt, void *ptr, size_t size)
150 __attribute__ ((_ALLOC_SIZE(3), nonnull (1) _RET_NONNULL));
151 extern void *qstrdup (struct memtype *mt, const char *str)
152 __attribute__ ((malloc, nonnull (1) _RET_NONNULL));
153 extern void qfree (struct memtype *mt, void *ptr)
154 __attribute__ ((nonnull (1)));
155
156 #define XMALLOC(mtype, size) qmalloc(mtype, size)
157 #define XCALLOC(mtype, size) qcalloc(mtype, size)
158 #define XREALLOC(mtype, ptr, size) qrealloc(mtype, ptr, size)
159 #define XSTRDUP(mtype, str) qstrdup(mtype, str)
160 #define XFREE(mtype, ptr) do { qfree(mtype, ptr); ptr = NULL; } \
161 while (0)
162
163 static inline size_t mtype_stats_alloc(struct memtype *mt)
164 {
165 return mt->n_alloc;
166 }
167
168 /* NB: calls are ordered by memgroup; and there is a call with mt == NULL for
169 * each memgroup (so that a header can be printed, and empty memgroups show)
170 *
171 * return value: 0: continue, !0: abort walk. qmem_walk will return the
172 * last value from qmem_walk_fn. */
173 typedef int qmem_walk_fn (void *arg, struct memgroup *mg, struct memtype *mt);
174 extern int qmem_walk (qmem_walk_fn *func, void *arg);
175 extern void log_memstats_stderr (const char *);
176
177 extern void memory_oom (size_t size, const char *name);
178
179 #endif /* _QUAGGA_MEMORY_H */