]> 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 90d7d420a925d7dff664bc872d68137710b5cc33..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,12 +35,23 @@ 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)
 {
+       size_t current;
        size_t oldsize;
 
-       atomic_fetch_add_explicit(&mt->n_alloc, 1, memory_order_relaxed);
+       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)
@@ -40,21 +60,44 @@ static inline void mt_count_alloc(struct memtype *mt, size_t size)
        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);
        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;
 }
 
@@ -71,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);
 }