]>
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> | |
9eed278b | 21 | #include <stdio.h> |
a31446a8 | 22 | #include <frratomic.h> |
de1a880c | 23 | #include "compiler.h" |
3b4cd783 | 24 | |
5e244469 RW |
25 | #ifdef __cplusplus |
26 | extern "C" { | |
27 | #endif | |
28 | ||
602a6584 DL |
29 | #if defined(HAVE_MALLOC_SIZE) && !defined(HAVE_MALLOC_USABLE_SIZE) |
30 | #define malloc_usable_size(x) malloc_size(x) | |
31 | #define HAVE_MALLOC_USABLE_SIZE | |
32 | #endif | |
33 | ||
3b4cd783 | 34 | #define SIZE_VAR ~0UL |
fa7fe831 DL |
35 | struct memtype { |
36 | struct memtype *next, **ref; | |
37 | const char *name; | |
c8a65463 DL |
38 | atomic_size_t n_alloc; |
39 | atomic_size_t n_max; | |
40 | atomic_size_t size; | |
602a6584 | 41 | #ifdef HAVE_MALLOC_USABLE_SIZE |
c8a65463 DL |
42 | atomic_size_t total; |
43 | atomic_size_t max_size; | |
602a6584 | 44 | #endif |
3b4cd783 DL |
45 | }; |
46 | ||
fa7fe831 DL |
47 | struct memgroup { |
48 | struct memgroup *next, **ref; | |
49 | struct memtype *types, **insert; | |
50 | const char *name; | |
3b4cd783 DL |
51 | }; |
52 | ||
3b4cd783 DL |
53 | /* macro usage: |
54 | * | |
55 | * mydaemon.h | |
56 | * DECLARE_MGROUP(MYDAEMON) | |
57 | * DECLARE_MTYPE(MYDAEMON_COMMON) | |
58 | * | |
59 | * mydaemon.c | |
60 | * DEFINE_MGROUP(MYDAEMON, "my daemon memory") | |
61 | * DEFINE_MTYPE(MYDAEMON, MYDAEMON_COMMON, | |
62 | * "this mtype is used in multiple files in mydaemon") | |
fa7fe831 | 63 | * foo = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*foo)) |
3b4cd783 DL |
64 | * |
65 | * mydaemon_io.c | |
fa7fe831 | 66 | * bar = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*bar)) |
3b4cd783 DL |
67 | * |
68 | * DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO, | |
69 | * "this mtype is used only in this file") | |
fa7fe831 | 70 | * baz = qmalloc(MTYPE_MYDAEMON_IO, sizeof(*baz)) |
3b4cd783 DL |
71 | * |
72 | * Note: Naming conventions (MGROUP_ and MTYPE_ prefixes are enforced | |
73 | * by not having these as part of the macro arguments) | |
74 | * Note: MTYPE_* are symbols to the compiler (of type struct memtype *), | |
75 | * but MGROUP_* aren't. | |
76 | */ | |
77 | ||
d62a17ae | 78 | #define DECLARE_MGROUP(name) extern struct memgroup _mg_##name; |
79 | #define DEFINE_MGROUP(mname, desc) \ | |
80 | struct memgroup _mg_##mname \ | |
81 | __attribute__((section(".data.mgroups"))) = { \ | |
82 | .name = desc, \ | |
83 | .types = NULL, \ | |
84 | .next = NULL, \ | |
85 | .insert = NULL, \ | |
86 | .ref = NULL, \ | |
87 | }; \ | |
88 | static void _mginit_##mname(void) __attribute__((_CONSTRUCTOR(1000))); \ | |
89 | static void _mginit_##mname(void) \ | |
90 | { \ | |
91 | extern struct memgroup **mg_insert; \ | |
92 | _mg_##mname.ref = mg_insert; \ | |
93 | *mg_insert = &_mg_##mname; \ | |
94 | mg_insert = &_mg_##mname.next; \ | |
95 | } \ | |
96 | static void _mgfini_##mname(void) __attribute__((_DESTRUCTOR(1000))); \ | |
97 | static void _mgfini_##mname(void) \ | |
98 | { \ | |
99 | if (_mg_##mname.next) \ | |
100 | _mg_##mname.next->ref = _mg_##mname.ref; \ | |
101 | *_mg_##mname.ref = _mg_##mname.next; \ | |
102 | } | |
103 | ||
104 | ||
056830ba DL |
105 | /* the array is a trick to make the "MTYPE_FOO" name work as a pointer without |
106 | * putting a & in front of it, so we can do "XMALLOC(MTYPE_FOO, ...)" instead | |
107 | * of "XMALLOC(&MTYPE_FOO, ...)". | |
108 | */ | |
d62a17ae | 109 | #define DECLARE_MTYPE(name) \ |
110 | extern struct memtype _mt_##name; \ | |
056830ba DL |
111 | extern struct memtype MTYPE_##name[1]; \ |
112 | /* end */ | |
d62a17ae | 113 | |
114 | #define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \ | |
115 | attr struct memtype _mt_##mname \ | |
116 | __attribute__((section(".data.mtypes"))) = { \ | |
117 | .name = desc, \ | |
118 | .next = NULL, \ | |
119 | .n_alloc = 0, \ | |
120 | .size = 0, \ | |
121 | .ref = NULL, \ | |
122 | }; \ | |
123 | static void _mtinit_##mname(void) __attribute__((_CONSTRUCTOR(1001))); \ | |
124 | static void _mtinit_##mname(void) \ | |
125 | { \ | |
126 | if (_mg_##group.insert == NULL) \ | |
127 | _mg_##group.insert = &_mg_##group.types; \ | |
128 | _mt_##mname.ref = _mg_##group.insert; \ | |
129 | *_mg_##group.insert = &_mt_##mname; \ | |
130 | _mg_##group.insert = &_mt_##mname.next; \ | |
131 | } \ | |
132 | static void _mtfini_##mname(void) __attribute__((_DESTRUCTOR(1001))); \ | |
133 | static void _mtfini_##mname(void) \ | |
134 | { \ | |
135 | if (_mt_##mname.next) \ | |
136 | _mt_##mname.next->ref = _mt_##mname.ref; \ | |
137 | *_mt_##mname.ref = _mt_##mname.next; \ | |
056830ba DL |
138 | } \ |
139 | /* end */ | |
140 | ||
141 | /* can't quite get gcc to emit the alias correctly, so asm-alias it is :/ */ | |
142 | #define DEFINE_MTYPE(group, name, desc) \ | |
143 | DEFINE_MTYPE_ATTR(group, name, , desc) \ | |
144 | __asm__(".equiv MTYPE_" #name ", _mt_" #name "\n\t" \ | |
145 | ".global MTYPE_" #name "\n"); \ | |
146 | /* end */ | |
57d898f3 | 147 | /* and this one's borked on clang, it drops static on aliases :/, so... asm */ |
d62a17ae | 148 | #define DEFINE_MTYPE_STATIC(group, name, desc) \ |
149 | DEFINE_MTYPE_ATTR(group, name, static, desc) \ | |
57d898f3 DL |
150 | extern struct memtype MTYPE_##name[1]; \ |
151 | __asm__(".equiv MTYPE_" #name ", _mt_" #name "\n"); \ | |
056830ba | 152 | /* end */ |
3b4cd783 | 153 | |
4a1ab8e4 DL |
154 | DECLARE_MGROUP(LIB) |
155 | DECLARE_MTYPE(TMP) | |
156 | ||
3b4cd783 | 157 | |
fa7fe831 | 158 | extern void *qmalloc(struct memtype *mt, size_t size) |
d62a17ae | 159 | __attribute__((malloc, _ALLOC_SIZE(2), nonnull(1) _RET_NONNULL)); |
fa7fe831 | 160 | extern void *qcalloc(struct memtype *mt, size_t size) |
d62a17ae | 161 | __attribute__((malloc, _ALLOC_SIZE(2), nonnull(1) _RET_NONNULL)); |
fa7fe831 | 162 | extern void *qrealloc(struct memtype *mt, void *ptr, size_t size) |
d62a17ae | 163 | __attribute__((_ALLOC_SIZE(3), nonnull(1) _RET_NONNULL)); |
164 | extern void *qstrdup(struct memtype *mt, const char *str) | |
165 | __attribute__((malloc, nonnull(1) _RET_NONNULL)); | |
166 | extern void qfree(struct memtype *mt, void *ptr) __attribute__((nonnull(1))); | |
3b4cd783 | 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) | |
d62a17ae | 172 | #define XFREE(mtype, ptr) \ |
173 | do { \ | |
174 | qfree(mtype, ptr); \ | |
175 | ptr = NULL; \ | |
176 | } while (0) | |
3b4cd783 DL |
177 | |
178 | static inline size_t mtype_stats_alloc(struct memtype *mt) | |
179 | { | |
180 | return mt->n_alloc; | |
181 | } | |
3b4cd783 DL |
182 | |
183 | /* NB: calls are ordered by memgroup; and there is a call with mt == NULL for | |
184 | * each memgroup (so that a header can be printed, and empty memgroups show) | |
185 | * | |
186 | * return value: 0: continue, !0: abort walk. qmem_walk will return the | |
187 | * last value from qmem_walk_fn. */ | |
fa7fe831 DL |
188 | typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt); |
189 | extern int qmem_walk(qmem_walk_fn *func, void *arg); | |
9eed278b DL |
190 | extern int log_memstats(FILE *fp, const char *); |
191 | #define log_memstats_stderr(prefix) log_memstats(stderr, prefix) | |
3b4cd783 | 192 | |
fa7fe831 | 193 | extern void memory_oom(size_t size, const char *name); |
3b4cd783 | 194 | |
5e244469 RW |
195 | #ifdef __cplusplus |
196 | } | |
197 | #endif | |
198 | ||
3b4cd783 | 199 | #endif /* _QUAGGA_MEMORY_H */ |