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