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