| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #ifndef _QUAGGA_MEMORY_H |
| #define _QUAGGA_MEMORY_H |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <frratomic.h> |
| #include "compiler.h" |
| |
| #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) |
| |
| #if defined(HAVE_MALLOC_SIZE) && !defined(HAVE_MALLOC_USABLE_SIZE) |
| #define malloc_usable_size(x) malloc_size(x) |
| #define HAVE_MALLOC_USABLE_SIZE |
| #endif |
| |
| #define SIZE_VAR ~0UL |
| struct memtype { |
| struct memtype *next, **ref; |
| const char *name; |
| _Atomic size_t n_alloc; |
| _Atomic size_t n_max; |
| _Atomic size_t size; |
| #ifdef HAVE_MALLOC_USABLE_SIZE |
| _Atomic size_t total; |
| _Atomic size_t max_size; |
| #endif |
| }; |
| |
| struct memgroup { |
| struct memgroup *next, **ref; |
| struct memtype *types, **insert; |
| const char *name; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #define DECLARE_MGROUP(name) extern struct memgroup _mg_##name; |
| #define DEFINE_MGROUP(mname, desc) \ |
| struct memgroup _mg_##mname \ |
| __attribute__((section(".data.mgroups"))) = { \ |
| .name = desc, \ |
| .types = NULL, \ |
| .next = NULL, \ |
| .insert = NULL, \ |
| .ref = NULL, \ |
| }; \ |
| static void _mginit_##mname(void) __attribute__((_CONSTRUCTOR(1000))); \ |
| static void _mginit_##mname(void) \ |
| { \ |
| extern struct memgroup **mg_insert; \ |
| _mg_##mname.ref = mg_insert; \ |
| *mg_insert = &_mg_##mname; \ |
| mg_insert = &_mg_##mname.next; \ |
| } \ |
| static void _mgfini_##mname(void) __attribute__((_DESTRUCTOR(1000))); \ |
| static void _mgfini_##mname(void) \ |
| { \ |
| if (_mg_##mname.next) \ |
| _mg_##mname.next->ref = _mg_##mname.ref; \ |
| *_mg_##mname.ref = _mg_##mname.next; \ |
| } |
| |
| |
| #define DECLARE_MTYPE(name) \ |
| extern struct memtype _mt_##name; \ |
| static struct memtype *const MTYPE_##name = &_mt_##name; |
| |
| #define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \ |
| attr struct memtype _mt_##mname \ |
| __attribute__((section(".data.mtypes"))) = { \ |
| .name = desc, \ |
| .next = NULL, \ |
| .n_alloc = 0, \ |
| .size = 0, \ |
| .ref = NULL, \ |
| }; \ |
| static void _mtinit_##mname(void) __attribute__((_CONSTRUCTOR(1001))); \ |
| static void _mtinit_##mname(void) \ |
| { \ |
| if (_mg_##group.insert == NULL) \ |
| _mg_##group.insert = &_mg_##group.types; \ |
| _mt_##mname.ref = _mg_##group.insert; \ |
| *_mg_##group.insert = &_mt_##mname; \ |
| _mg_##group.insert = &_mt_##mname.next; \ |
| } \ |
| static void _mtfini_##mname(void) __attribute__((_DESTRUCTOR(1001))); \ |
| static void _mtfini_##mname(void) \ |
| { \ |
| if (_mt_##mname.next) \ |
| _mt_##mname.next->ref = _mt_##mname.ref; \ |
| *_mt_##mname.ref = _mt_##mname.next; \ |
| } |
| |
| #define DEFINE_MTYPE(group, name, desc) DEFINE_MTYPE_ATTR(group, name, , desc) |
| #define DEFINE_MTYPE_STATIC(group, name, desc) \ |
| DEFINE_MTYPE_ATTR(group, name, static, desc) \ |
| static struct memtype *const MTYPE_##name = &_mt_##name; |
| |
| DECLARE_MGROUP(LIB) |
| DECLARE_MTYPE(TMP) |
| DECLARE_MTYPE(PREFIX_FLOWSPEC) |
| |
| |
| extern void *qmalloc(struct memtype *mt, size_t size) |
| __attribute__((malloc, _ALLOC_SIZE(2), nonnull(1) _RET_NONNULL)); |
| extern void *qcalloc(struct memtype *mt, size_t size) |
| __attribute__((malloc, _ALLOC_SIZE(2), nonnull(1) _RET_NONNULL)); |
| extern void *qrealloc(struct memtype *mt, void *ptr, size_t size) |
| __attribute__((_ALLOC_SIZE(3), nonnull(1) _RET_NONNULL)); |
| extern void *qstrdup(struct memtype *mt, const char *str) |
| __attribute__((malloc, nonnull(1) _RET_NONNULL)); |
| extern void qfree(struct memtype *mt, void *ptr) __attribute__((nonnull(1))); |
| |
| #define XMALLOC(mtype, size) qmalloc(mtype, size) |
| #define XCALLOC(mtype, size) qcalloc(mtype, size) |
| #define XREALLOC(mtype, ptr, size) qrealloc(mtype, ptr, size) |
| #define XSTRDUP(mtype, str) qstrdup(mtype, str) |
| #define XFREE(mtype, ptr) \ |
| do { \ |
| qfree(mtype, ptr); \ |
| ptr = NULL; \ |
| } while (0) |
| |
| static inline size_t mtype_stats_alloc(struct memtype *mt) |
| { |
| return mt->n_alloc; |
| } |
| |
| |
| |
| |
| |
| |
| typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt); |
| extern int qmem_walk(qmem_walk_fn *func, void *arg); |
| extern int log_memstats(FILE *fp, const char *); |
| #define log_memstats_stderr(prefix) log_memstats(stderr, prefix) |
| |
| extern void memory_oom(size_t size, const char *name); |
| |
| #endif /* _QUAGGA_MEMORY_H */ |