]> git.proxmox.com Git - mirror_frr.git/blob - lib/memory.h
Merge branch 'stable/3.0' into tmp-3.0-master-merge
[mirror_frr.git] / lib / memory.h
1 /*
2 * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #ifndef _QUAGGA_MEMORY_H
18 #define _QUAGGA_MEMORY_H
19
20 #include <stdlib.h>
21 #include <frratomic.h>
22
23 #define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
24
25 #define SIZE_VAR ~0UL
26 struct memtype {
27 struct memtype *next, **ref;
28 const char *name;
29 _Atomic size_t n_alloc;
30 _Atomic size_t size;
31 };
32
33 struct memgroup {
34 struct memgroup *next, **ref;
35 struct memtype *types, **insert;
36 const char *name;
37 };
38
39 #if defined(__clang__)
40 #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5)
41 # define _RET_NONNULL , returns_nonnull
42 #endif
43 # define _CONSTRUCTOR(x) constructor(x)
44 #elif defined(__GNUC__)
45 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
46 # define _RET_NONNULL , returns_nonnull
47 #endif
48 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
49 # define _CONSTRUCTOR(x) constructor(x)
50 # define _DESTRUCTOR(x) destructor(x)
51 # define _ALLOC_SIZE(x) alloc_size(x)
52 #endif
53 #endif
54
55 #ifdef __sun
56 /* Solaris doesn't do constructor priorities due to linker restrictions */
57 #undef _CONSTRUCTOR
58 #undef _DESTRUCTOR
59 #endif
60
61 #ifndef _RET_NONNULL
62 # define _RET_NONNULL
63 #endif
64 #ifndef _CONSTRUCTOR
65 # define _CONSTRUCTOR(x) constructor
66 #endif
67 #ifndef _DESTRUCTOR
68 # define _DESTRUCTOR(x) destructor
69 #endif
70 #ifndef _ALLOC_SIZE
71 # define _ALLOC_SIZE(x)
72 #endif
73
74 /* macro usage:
75 *
76 * mydaemon.h
77 * DECLARE_MGROUP(MYDAEMON)
78 * DECLARE_MTYPE(MYDAEMON_COMMON)
79 *
80 * mydaemon.c
81 * DEFINE_MGROUP(MYDAEMON, "my daemon memory")
82 * DEFINE_MTYPE(MYDAEMON, MYDAEMON_COMMON,
83 * "this mtype is used in multiple files in mydaemon")
84 * foo = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*foo))
85 *
86 * mydaemon_io.c
87 * bar = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*bar))
88 *
89 * DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO,
90 * "this mtype is used only in this file")
91 * baz = qmalloc(MTYPE_MYDAEMON_IO, sizeof(*baz))
92 *
93 * Note: Naming conventions (MGROUP_ and MTYPE_ prefixes are enforced
94 * by not having these as part of the macro arguments)
95 * Note: MTYPE_* are symbols to the compiler (of type struct memtype *),
96 * but MGROUP_* aren't.
97 */
98
99 #define DECLARE_MGROUP(name) extern struct memgroup _mg_##name;
100 #define DEFINE_MGROUP(mname, desc) \
101 struct memgroup _mg_##mname \
102 __attribute__((section(".data.mgroups"))) = { \
103 .name = desc, \
104 .types = NULL, \
105 .next = NULL, \
106 .insert = NULL, \
107 .ref = NULL, \
108 }; \
109 static void _mginit_##mname(void) __attribute__((_CONSTRUCTOR(1000))); \
110 static void _mginit_##mname(void) \
111 { \
112 extern struct memgroup **mg_insert; \
113 _mg_##mname.ref = mg_insert; \
114 *mg_insert = &_mg_##mname; \
115 mg_insert = &_mg_##mname.next; \
116 } \
117 static void _mgfini_##mname(void) __attribute__((_DESTRUCTOR(1000))); \
118 static void _mgfini_##mname(void) \
119 { \
120 if (_mg_##mname.next) \
121 _mg_##mname.next->ref = _mg_##mname.ref; \
122 *_mg_##mname.ref = _mg_##mname.next; \
123 }
124
125
126 #define DECLARE_MTYPE(name) \
127 extern struct memtype _mt_##name; \
128 static struct memtype *const MTYPE_##name = &_mt_##name;
129
130 #define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \
131 attr struct memtype _mt_##mname \
132 __attribute__((section(".data.mtypes"))) = { \
133 .name = desc, \
134 .next = NULL, \
135 .n_alloc = 0, \
136 .size = 0, \
137 .ref = NULL, \
138 }; \
139 static void _mtinit_##mname(void) __attribute__((_CONSTRUCTOR(1001))); \
140 static void _mtinit_##mname(void) \
141 { \
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 } \
148 static void _mtfini_##mname(void) __attribute__((_DESTRUCTOR(1001))); \
149 static void _mtfini_##mname(void) \
150 { \
151 if (_mt_##mname.next) \
152 _mt_##mname.next->ref = _mt_##mname.ref; \
153 *_mt_##mname.ref = _mt_##mname.next; \
154 }
155
156 #define DEFINE_MTYPE(group, name, desc) DEFINE_MTYPE_ATTR(group, name, , desc)
157 #define DEFINE_MTYPE_STATIC(group, name, desc) \
158 DEFINE_MTYPE_ATTR(group, name, static, desc) \
159 static struct memtype *const MTYPE_##name = &_mt_##name;
160
161 DECLARE_MGROUP(LIB)
162 DECLARE_MTYPE(TMP)
163
164
165 extern void *qmalloc(struct memtype *mt, size_t size)
166 __attribute__((malloc, _ALLOC_SIZE(2), nonnull(1) _RET_NONNULL));
167 extern void *qcalloc(struct memtype *mt, size_t size)
168 __attribute__((malloc, _ALLOC_SIZE(2), nonnull(1) _RET_NONNULL));
169 extern void *qrealloc(struct memtype *mt, void *ptr, size_t size)
170 __attribute__((_ALLOC_SIZE(3), nonnull(1) _RET_NONNULL));
171 extern void *qstrdup(struct memtype *mt, const char *str)
172 __attribute__((malloc, nonnull(1) _RET_NONNULL));
173 extern void qfree(struct memtype *mt, void *ptr) __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) \
180 do { \
181 qfree(mtype, ptr); \
182 ptr = NULL; \
183 } while (0)
184
185 static inline size_t mtype_stats_alloc(struct memtype *mt)
186 {
187 return mt->n_alloc;
188 }
189
190 /* NB: calls are ordered by memgroup; and there is a call with mt == NULL for
191 * each memgroup (so that a header can be printed, and empty memgroups show)
192 *
193 * return value: 0: continue, !0: abort walk. qmem_walk will return the
194 * last value from qmem_walk_fn. */
195 typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt);
196 extern int qmem_walk(qmem_walk_fn *func, void *arg);
197 extern void log_memstats_stderr(const char *);
198
199 extern void memory_oom(size_t size, const char *name);
200
201 #endif /* _QUAGGA_MEMORY_H */