]> git.proxmox.com Git - mirror_frr.git/blame - lib/memory.h
Merge pull request #5625 from qlyoung/fix-zapi-ipset-name-nullterm
[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
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
26extern "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
35struct 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
47struct 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
d62a17ae 104#define DECLARE_MTYPE(name) \
33de8d1d 105 extern struct memtype MTYPE_##name[1]; \
056830ba 106 /* end */
d62a17ae 107
108#define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \
33de8d1d
DL
109 attr struct memtype MTYPE_##mname[1] \
110 __attribute__((section(".data.mtypes"))) = { { \
d62a17ae 111 .name = desc, \
112 .next = NULL, \
113 .n_alloc = 0, \
114 .size = 0, \
115 .ref = NULL, \
33de8d1d 116 } }; \
d62a17ae 117 static void _mtinit_##mname(void) __attribute__((_CONSTRUCTOR(1001))); \
118 static void _mtinit_##mname(void) \
119 { \
120 if (_mg_##group.insert == NULL) \
121 _mg_##group.insert = &_mg_##group.types; \
33de8d1d
DL
122 MTYPE_##mname->ref = _mg_##group.insert; \
123 *_mg_##group.insert = MTYPE_##mname; \
124 _mg_##group.insert = &MTYPE_##mname->next; \
d62a17ae 125 } \
126 static void _mtfini_##mname(void) __attribute__((_DESTRUCTOR(1001))); \
127 static void _mtfini_##mname(void) \
128 { \
33de8d1d
DL
129 if (MTYPE_##mname->next) \
130 MTYPE_##mname->next->ref = MTYPE_##mname->ref; \
131 *MTYPE_##mname->ref = MTYPE_##mname->next; \
056830ba
DL
132 } \
133 /* end */
134
056830ba
DL
135#define DEFINE_MTYPE(group, name, desc) \
136 DEFINE_MTYPE_ATTR(group, name, , desc) \
056830ba 137 /* end */
4d8ebedd 138
d62a17ae 139#define DEFINE_MTYPE_STATIC(group, name, desc) \
140 DEFINE_MTYPE_ATTR(group, name, static, desc) \
056830ba 141 /* end */
3b4cd783 142
4a1ab8e4
DL
143DECLARE_MGROUP(LIB)
144DECLARE_MTYPE(TMP)
145
3b4cd783 146
fa7fe831 147extern void *qmalloc(struct memtype *mt, size_t size)
d62a17ae 148 __attribute__((malloc, _ALLOC_SIZE(2), nonnull(1) _RET_NONNULL));
fa7fe831 149extern void *qcalloc(struct memtype *mt, size_t size)
d62a17ae 150 __attribute__((malloc, _ALLOC_SIZE(2), nonnull(1) _RET_NONNULL));
fa7fe831 151extern void *qrealloc(struct memtype *mt, void *ptr, size_t size)
d62a17ae 152 __attribute__((_ALLOC_SIZE(3), nonnull(1) _RET_NONNULL));
153extern void *qstrdup(struct memtype *mt, const char *str)
154 __attribute__((malloc, nonnull(1) _RET_NONNULL));
155extern void qfree(struct memtype *mt, void *ptr) __attribute__((nonnull(1)));
3b4cd783 156
3b4cd783
DL
157#define XMALLOC(mtype, size) qmalloc(mtype, size)
158#define XCALLOC(mtype, size) qcalloc(mtype, size)
159#define XREALLOC(mtype, ptr, size) qrealloc(mtype, ptr, size)
160#define XSTRDUP(mtype, str) qstrdup(mtype, str)
d62a17ae 161#define XFREE(mtype, ptr) \
162 do { \
163 qfree(mtype, ptr); \
164 ptr = NULL; \
165 } while (0)
3b4cd783
DL
166
167static inline size_t mtype_stats_alloc(struct memtype *mt)
168{
169 return mt->n_alloc;
170}
3b4cd783
DL
171
172/* NB: calls are ordered by memgroup; and there is a call with mt == NULL for
173 * each memgroup (so that a header can be printed, and empty memgroups show)
174 *
175 * return value: 0: continue, !0: abort walk. qmem_walk will return the
176 * last value from qmem_walk_fn. */
fa7fe831
DL
177typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt);
178extern int qmem_walk(qmem_walk_fn *func, void *arg);
9eed278b
DL
179extern int log_memstats(FILE *fp, const char *);
180#define log_memstats_stderr(prefix) log_memstats(stderr, prefix)
3b4cd783 181
fa7fe831 182extern void memory_oom(size_t size, const char *name);
3b4cd783 183
5e244469
RW
184#ifdef __cplusplus
185}
186#endif
187
3b4cd783 188#endif /* _QUAGGA_MEMORY_H */