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