]>
Commit | Line | Data |
---|---|---|
3b4cd783 DL |
1 | /* |
2 | * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. | |
3 | * | |
db2d8df6 DL |
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. | |
3b4cd783 | 7 | * |
db2d8df6 DL |
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. | |
3b4cd783 DL |
15 | */ |
16 | ||
17 | #ifndef _QUAGGA_MEMORY_H | |
18 | #define _QUAGGA_MEMORY_H | |
19 | ||
20 | #include <stdlib.h> | |
a31446a8 | 21 | #include <frratomic.h> |
3b4cd783 DL |
22 | |
23 | #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) | |
24 | ||
25 | #define SIZE_VAR ~0UL | |
fa7fe831 DL |
26 | struct memtype { |
27 | struct memtype *next, **ref; | |
28 | const char *name; | |
29 | _Atomic size_t n_alloc; | |
30 | _Atomic size_t size; | |
3b4cd783 DL |
31 | }; |
32 | ||
fa7fe831 DL |
33 | struct memgroup { |
34 | struct memgroup *next, **ref; | |
35 | struct memtype *types, **insert; | |
36 | const char *name; | |
3b4cd783 DL |
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) | |
af2d0efc | 50 | # define _DESTRUCTOR(x) destructor(x) |
3b4cd783 DL |
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 | |
af2d0efc | 58 | # undef _DESTRUCTOR |
3b4cd783 DL |
59 | #endif |
60 | ||
61 | #ifndef _RET_NONNULL | |
62 | # define _RET_NONNULL | |
63 | #endif | |
64 | #ifndef _CONSTRUCTOR | |
65 | # define _CONSTRUCTOR(x) constructor | |
66 | #endif | |
af2d0efc DL |
67 | #ifndef _DESTRUCTOR |
68 | # define _DESTRUCTOR(x) destructor | |
69 | #endif | |
3b4cd783 DL |
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") | |
fa7fe831 | 84 | * foo = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*foo)) |
3b4cd783 DL |
85 | * |
86 | * mydaemon_io.c | |
fa7fe831 | 87 | * bar = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*bar)) |
3b4cd783 DL |
88 | * |
89 | * DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO, | |
90 | * "this mtype is used only in this file") | |
fa7fe831 | 91 | * baz = qmalloc(MTYPE_MYDAEMON_IO, sizeof(*baz)) |
3b4cd783 DL |
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) \ | |
100 | extern struct memgroup _mg_##name; | |
101 | #define DEFINE_MGROUP(mname, desc) \ | |
102 | struct memgroup _mg_##mname \ | |
103 | __attribute__ ((section (".data.mgroups"))) = { \ | |
104 | .name = desc, \ | |
af2d0efc | 105 | .types = NULL, .next = NULL, .insert = NULL, .ref = NULL, \ |
3b4cd783 DL |
106 | }; \ |
107 | static void _mginit_##mname (void) \ | |
108 | __attribute__ ((_CONSTRUCTOR (1000))); \ | |
109 | static void _mginit_##mname (void) \ | |
110 | { extern struct memgroup **mg_insert; \ | |
af2d0efc | 111 | _mg_##mname.ref = mg_insert; \ |
3b4cd783 | 112 | *mg_insert = &_mg_##mname; \ |
af2d0efc DL |
113 | mg_insert = &_mg_##mname.next; } \ |
114 | static void _mgfini_##mname (void) \ | |
115 | __attribute__ ((_DESTRUCTOR (1000))); \ | |
116 | static void _mgfini_##mname (void) \ | |
117 | { if (_mg_##mname.next) \ | |
118 | _mg_##mname.next->ref = _mg_##mname.ref; \ | |
119 | *_mg_##mname.ref = _mg_##mname.next; } | |
3b4cd783 DL |
120 | |
121 | ||
122 | #define DECLARE_MTYPE(name) \ | |
123 | extern struct memtype _mt_##name; \ | |
124 | static struct memtype * const MTYPE_ ## name = &_mt_##name; | |
125 | ||
126 | #define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \ | |
127 | attr struct memtype _mt_##mname \ | |
128 | __attribute__ ((section (".data.mtypes"))) = { \ | |
129 | .name = desc, \ | |
af2d0efc | 130 | .next = NULL, .n_alloc = 0, .size = 0, .ref = NULL, \ |
3b4cd783 DL |
131 | }; \ |
132 | static void _mtinit_##mname (void) \ | |
133 | __attribute__ ((_CONSTRUCTOR (1001))); \ | |
134 | static void _mtinit_##mname (void) \ | |
135 | { if (_mg_##group.insert == NULL) \ | |
136 | _mg_##group.insert = &_mg_##group.types; \ | |
af2d0efc | 137 | _mt_##mname.ref = _mg_##group.insert; \ |
3b4cd783 | 138 | *_mg_##group.insert = &_mt_##mname; \ |
af2d0efc DL |
139 | _mg_##group.insert = &_mt_##mname.next; } \ |
140 | static void _mtfini_##mname (void) \ | |
141 | __attribute__ ((_DESTRUCTOR (1001))); \ | |
142 | static void _mtfini_##mname (void) \ | |
143 | { if (_mt_##mname.next) \ | |
144 | _mt_##mname.next->ref = _mt_##mname.ref; \ | |
145 | *_mt_##mname.ref = _mt_##mname.next; } | |
3b4cd783 DL |
146 | |
147 | #define DEFINE_MTYPE(group, name, desc) \ | |
148 | DEFINE_MTYPE_ATTR(group, name, , desc) | |
149 | #define DEFINE_MTYPE_STATIC(group, name, desc) \ | |
150 | DEFINE_MTYPE_ATTR(group, name, static, desc) \ | |
151 | static struct memtype * const MTYPE_ ## name = &_mt_##name; | |
152 | ||
4a1ab8e4 DL |
153 | DECLARE_MGROUP(LIB) |
154 | DECLARE_MTYPE(TMP) | |
155 | ||
3b4cd783 | 156 | |
fa7fe831 | 157 | extern void *qmalloc(struct memtype *mt, size_t size) |
3b4cd783 | 158 | __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL)); |
fa7fe831 | 159 | extern void *qcalloc(struct memtype *mt, size_t size) |
3b4cd783 | 160 | __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL)); |
fa7fe831 | 161 | extern void *qrealloc(struct memtype *mt, void *ptr, size_t size) |
3b4cd783 DL |
162 | __attribute__ ((_ALLOC_SIZE(3), nonnull (1) _RET_NONNULL)); |
163 | extern void *qstrdup (struct memtype *mt, const char *str) | |
164 | __attribute__ ((malloc, nonnull (1) _RET_NONNULL)); | |
fa7fe831 | 165 | extern void qfree(struct memtype *mt, void *ptr) |
3b4cd783 DL |
166 | __attribute__ ((nonnull (1))); |
167 | ||
3b4cd783 DL |
168 | #define XMALLOC(mtype, size) qmalloc(mtype, size) |
169 | #define XCALLOC(mtype, size) qcalloc(mtype, size) | |
170 | #define XREALLOC(mtype, ptr, size) qrealloc(mtype, ptr, size) | |
171 | #define XSTRDUP(mtype, str) qstrdup(mtype, str) | |
172 | #define XFREE(mtype, ptr) do { qfree(mtype, ptr); ptr = NULL; } \ | |
173 | while (0) | |
174 | ||
175 | static inline size_t mtype_stats_alloc(struct memtype *mt) | |
176 | { | |
177 | return mt->n_alloc; | |
178 | } | |
3b4cd783 DL |
179 | |
180 | /* NB: calls are ordered by memgroup; and there is a call with mt == NULL for | |
181 | * each memgroup (so that a header can be printed, and empty memgroups show) | |
182 | * | |
183 | * return value: 0: continue, !0: abort walk. qmem_walk will return the | |
184 | * last value from qmem_walk_fn. */ | |
fa7fe831 DL |
185 | typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt); |
186 | extern int qmem_walk(qmem_walk_fn *func, void *arg); | |
187 | extern void log_memstats_stderr(const char *); | |
3b4cd783 | 188 | |
fa7fe831 | 189 | extern void memory_oom(size_t size, const char *name); |
3b4cd783 DL |
190 | |
191 | #endif /* _QUAGGA_MEMORY_H */ |