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