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