]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/memory.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[mirror_frr.git] / lib / memory.c
index 9de856a2e2f60a388659d0ff0127f8d5c19c1679..fee23a75ac67e1d11463c102b2e68a87444ba1b5 100644 (file)
 #include <zebra.h>
 
 #include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_MALLOC_NP_H
+#include <malloc_np.h>
+#endif
+#ifdef HAVE_MALLOC_MALLOC_H
+#include <malloc/malloc.h>
+#endif
 
 #include "memory.h"
 #include "log.h"
@@ -26,30 +35,69 @@ struct memgroup **mg_insert = &mg_first;
 
 DEFINE_MGROUP(LIB, "libfrr")
 DEFINE_MTYPE(LIB, TMP, "Temporary memory")
+DEFINE_MTYPE(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
 
-static inline void mt_count_alloc(struct memtype *mt, size_t size)
+static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
 {
-       mt->n_alloc++;
-
-       if (mt->size == 0)
-               mt->size = size;
-       else if (mt->size != size)
-               mt->size = SIZE_VAR;
+       size_t current;
+       size_t oldsize;
+
+       current = 1 + atomic_fetch_add_explicit(&mt->n_alloc, 1,
+                                               memory_order_relaxed);
+
+       oldsize = atomic_load_explicit(&mt->n_max, memory_order_relaxed);
+       if (current > oldsize)
+               /* note that this may fail, but approximation is sufficient */
+               atomic_compare_exchange_weak_explicit(&mt->n_max, &oldsize,
+                                                     current,
+                                                     memory_order_relaxed,
+                                                     memory_order_relaxed);
+
+       oldsize = atomic_load_explicit(&mt->size, memory_order_relaxed);
+       if (oldsize == 0)
+               oldsize = atomic_exchange_explicit(&mt->size, size,
+                                                  memory_order_relaxed);
+       if (oldsize != 0 && oldsize != size && oldsize != SIZE_VAR)
+               atomic_store_explicit(&mt->size, SIZE_VAR,
+                                     memory_order_relaxed);
+
+#ifdef HAVE_MALLOC_USABLE_SIZE
+       size_t mallocsz = malloc_usable_size(ptr);
+
+       current = mallocsz + atomic_fetch_add_explicit(&mt->total, mallocsz,
+                                                      memory_order_relaxed);
+       oldsize = atomic_load_explicit(&mt->max_size, memory_order_relaxed);
+       if (current > oldsize)
+               /* note that this may fail, but approximation is sufficient */
+               atomic_compare_exchange_weak_explicit(&mt->max_size, &oldsize,
+                                                     current,
+                                                     memory_order_relaxed,
+                                                     memory_order_relaxed);
+#endif
 }
 
-static inline void mt_count_free(struct memtype *mt)
+static inline void mt_count_free(struct memtype *mt, void *ptr)
 {
        assert(mt->n_alloc);
-       mt->n_alloc--;
+       atomic_fetch_sub_explicit(&mt->n_alloc, 1, memory_order_relaxed);
+
+#ifdef HAVE_MALLOC_USABLE_SIZE
+       size_t mallocsz = malloc_usable_size(ptr);
+
+       atomic_fetch_sub_explicit(&mt->total, mallocsz, memory_order_relaxed);
+#endif
 }
 
 static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
 {
        if (__builtin_expect(ptr == NULL, 0)) {
-               memory_oom(size, mt->name);
+               if (size) {
+                       /* malloc(0) is allowed to return NULL */
+                       memory_oom(size, mt->name);
+               }
                return NULL;
        }
-       mt_count_alloc(mt, size);
+       mt_count_alloc(mt, size, ptr);
        return ptr;
 }
 
@@ -66,19 +114,19 @@ void *qcalloc(struct memtype *mt, size_t size)
 void *qrealloc(struct memtype *mt, void *ptr, size_t size)
 {
        if (ptr)
-               mt_count_free(mt);
+               mt_count_free(mt, ptr);
        return mt_checkalloc(mt, ptr ? realloc(ptr, size) : malloc(size), size);
 }
 
 void *qstrdup(struct memtype *mt, const char *str)
 {
-       return mt_checkalloc(mt, strdup(str), strlen(str) + 1);
+       return str ? mt_checkalloc(mt, strdup(str), strlen(str) + 1) : NULL;
 }
 
 void qfree(struct memtype *mt, void *ptr)
 {
        if (ptr)
-               mt_count_free(mt);
+               mt_count_free(mt, ptr);
        free(ptr);
 }
 
@@ -99,6 +147,7 @@ int qmem_walk(qmem_walk_fn *func, void *arg)
 }
 
 struct exit_dump_args {
+       FILE *fp;
        const char *prefix;
        int error;
 };
@@ -108,22 +157,25 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
        struct exit_dump_args *eda = arg;
 
        if (!mt) {
-               fprintf(stderr,
-                       "%s: showing active allocations in memory group %s\n",
+               fprintf(eda->fp,
+                       "%s: showing active allocations in "
+                       "memory group %s\n",
                        eda->prefix, mg->name);
+
        } else if (mt->n_alloc) {
                char size[32];
                eda->error++;
                snprintf(size, sizeof(size), "%10zu", mt->size);
-               fprintf(stderr, "%s: memstats:  %-30s: %6zu * %s\n",
+               fprintf(eda->fp, "%s: memstats:  %-30s: %6zu * %s\n",
                        eda->prefix, mt->name, mt->n_alloc,
                        mt->size == SIZE_VAR ? "(variably sized)" : size);
        }
        return 0;
 }
 
-void log_memstats_stderr(const char *prefix)
+int log_memstats(FILE *fp, const char *prefix)
 {
-       struct exit_dump_args eda = {.prefix = prefix, .error = 0};
+       struct exit_dump_args eda = {.fp = fp, .prefix = prefix, .error = 0};
        qmem_walk(qmem_exit_walker, &eda);
+       return eda.error;
 }