http: fix memory leak
[vpp.git] / src / vppinfra / bihash_template.c
index e408d15..38354a1 100644 (file)
 #define BIIHASH_MIN_ALLOC_LOG2_PAGES 10
 #endif
 
+#ifndef BIHASH_USE_HEAP
+#define BIHASH_USE_HEAP 1
+#endif
+
 static inline void *BV (alloc_aligned) (BVT (clib_bihash) * h, uword nbytes)
 {
   uword rv;
@@ -161,19 +165,23 @@ static void BV (clib_bihash_instantiate) (BVT (clib_bihash) * h)
 
   if (BIHASH_KVP_AT_BUCKET_LEVEL)
     {
-      int i;
+      int i, j;
       BVT (clib_bihash_bucket) * b;
 
       b = h->buckets;
 
       for (i = 0; i < h->nbuckets; i++)
        {
+         BVT (clib_bihash_kv) * v;
          b->offset = BV (clib_bihash_get_offset) (h, (void *) (b + 1));
          b->refcnt = 1;
          /* Mark all elements free */
-         clib_memset_u8 ((b + 1), 0xff, BIHASH_KVP_PER_PAGE *
-                         sizeof (BVT (clib_bihash_kv)));
-
+         v = (void *) (b + 1);
+         for (j = 0; j < BIHASH_KVP_PER_PAGE; j++)
+           {
+             BV (clib_bihash_mark_free) (v);
+             v++;
+           }
          /* Compute next bucket start address */
          b = (void *) (((uword) b) + sizeof (*b) +
                        (BIHASH_KVP_PER_PAGE *
@@ -197,7 +205,9 @@ void BV (clib_bihash_init2) (BVT (clib_bihash_init2_args) * a)
   h->log2_nbuckets = max_log2 (a->nbuckets);
   h->memory_size = BIHASH_USE_HEAP ? 0 : a->memory_size;
   h->instantiated = 0;
-  h->fmt_fn = a->fmt_fn;
+  h->dont_add_to_all_bihash_list = a->dont_add_to_all_bihash_list;
+  h->fmt_fn = BV (format_bihash);
+  h->kvp_fmt_fn = a->kvp_fmt_fn;
 
   alloc_arena (h) = 0;
 
@@ -271,7 +281,7 @@ void BV (clib_bihash_initiator_init_svm)
 
   ASSERT (memory_size < (1ULL << 32));
   /* Set up for memfd sharing */
-  if ((fd = memfd_create (name, MFD_ALLOW_SEALING)) == -1)
+  if ((fd = clib_mem_vm_create_fd (CLIB_MEM_PAGE_SZ_DEFAULT, name) == -1)
     {
       clib_unix_warning ("memfd_create");
       return;
@@ -327,7 +337,8 @@ void BV (clib_bihash_initiator_init_svm)
     (u64) BV (clib_bihash_get_offset) (h, freelist_vh->vector_data);
   h->freelists = (void *) (freelist_vh->vector_data);
 
-  h->fmt_fn = NULL;
+  h->fmt_fn = BV (format_bihash);
+  h->kvp_fmt_fn = NULL;
   h->instantiated = 1;
 }
 
@@ -377,14 +388,20 @@ void BV (clib_bihash_responder_init_svm)
 
   h->alloc_lock = BV (clib_bihash_get_value) (h, h->sh->alloc_lock_as_u64);
   h->freelists = BV (clib_bihash_get_value) (h, h->sh->freelists_as_u64);
-  h->fmt_fn = NULL;
+  h->fmt_fn = BV (format_bihash);
+  h->kvp_fmt_fn = NULL;
 }
 #endif /* BIHASH_32_64_SVM */
 
 void BV (clib_bihash_set_kvp_format_fn) (BVT (clib_bihash) * h,
-                                        format_function_t * fmt_fn)
+                                        format_function_t * kvp_fmt_fn)
+{
+  h->kvp_fmt_fn = kvp_fmt_fn;
+}
+
+int BV (clib_bihash_is_initialised) (const BVT (clib_bihash) * h)
 {
-  h->fmt_fn = fmt_fn;
+  return (h->instantiated != 0);
 }
 
 void BV (clib_bihash_free) (BVT (clib_bihash) * h)
@@ -413,6 +430,7 @@ void BV (clib_bihash_free) (BVT (clib_bihash) * h)
 
   vec_free (h->working_copies);
   vec_free (h->working_copy_lengths);
+  clib_mem_free ((void *) h->alloc_lock);
 #if BIHASH_32_64_SVM == 0
   vec_free (h->freelists);
 #else
@@ -423,6 +441,11 @@ void BV (clib_bihash_free) (BVT (clib_bihash) * h)
     clib_mem_vm_free ((void *) (uword) (alloc_arena (h)),
                      alloc_arena_size (h));
 never_initialized:
+  if (h->dont_add_to_all_bihash_list)
+    {
+      clib_memset_u8 (h, 0, sizeof (*h));
+      return;
+    }
   clib_memset_u8 (h, 0, sizeof (*h));
   for (i = 0; i < vec_len (clib_all_bihashes); i++)
     {
@@ -440,6 +463,7 @@ static
 BVT (clib_bihash_value) *
 BV (value_alloc) (BVT (clib_bihash) * h, u32 log2_pages)
 {
+  int i;
   BVT (clib_bihash_value) * rv = 0;
 
   ASSERT (h->alloc_lock[0]);
@@ -459,12 +483,15 @@ BV (value_alloc) (BVT (clib_bihash) * h, u32 log2_pages)
 
 initialize:
   ASSERT (rv);
-  /*
-   * Latest gcc complains that the length arg is zero
-   * if we replace (1<<log2_pages) with vec_len(rv).
-   * No clue.
-   */
-  clib_memset_u8 (rv, 0xff, sizeof (*rv) * (1 << log2_pages));
+
+  BVT (clib_bihash_kv) * v;
+  v = (BVT (clib_bihash_kv) *) rv;
+
+  for (i = 0; i < BIHASH_KVP_PER_PAGE * (1 << log2_pages); i++)
+    {
+      BV (clib_bihash_mark_free) (v);
+      v++;
+    }
   return rv;
 }
 
@@ -653,9 +680,10 @@ BV (split_and_rehash_linear)
   return new_values;
 }
 
-static_always_inline int BV (clib_bihash_add_del_inline_with_hash)
-  (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * add_v, u64 hash, int is_add,
-   int (*is_stale_cb) (BVT (clib_bihash_kv) *, void *), void *arg)
+static_always_inline int BV (clib_bihash_add_del_inline_with_hash) (
+  BVT (clib_bihash) * h, BVT (clib_bihash_kv) * add_v, u64 hash, int is_add,
+  int (*is_stale_cb) (BVT (clib_bihash_kv) *, void *), void *is_stale_arg,
+  void (*overwrite_cb) (BVT (clib_bihash_kv) *, void *), void *overwrite_arg)
 {
   BVT (clib_bihash_bucket) * b, tmp_b;
   BVT (clib_bihash_value) * v, *new_v, *save_new_v, *working_copy;
@@ -693,6 +721,12 @@ static_always_inline int BV (clib_bihash_add_del_inline_with_hash)
   ASSERT (h->instantiated != 0);
 #endif
 
+  /*
+   * Debug image: make sure that an item being added doesn't accidentally
+   * look like a free item.
+   */
+  ASSERT ((is_add && BV (clib_bihash_is_free) (add_v)) == 0);
+
   b = BV (clib_bihash_get_bucket) (h, hash);
 
   BV (clib_bihash_lock_bucket) (b);
@@ -749,6 +783,8 @@ static_always_inline int BV (clib_bihash_add_del_inline_with_hash)
        */
       for (i = 0; i < limit; i++)
        {
+         if (BV (clib_bihash_is_free) (&(v->kvp[i])))
+           continue;
          if (BV (clib_bihash_key_compare) (v->kvp[i].key, add_v->key))
            {
              /* Add but do not overwrite? */
@@ -757,7 +793,8 @@ static_always_inline int BV (clib_bihash_add_del_inline_with_hash)
                  BV (clib_bihash_unlock_bucket) (b);
                  return (-2);
                }
-
+             if (overwrite_cb)
+               overwrite_cb (&(v->kvp[i]), overwrite_arg);
              clib_memcpy_fast (&(v->kvp[i].value),
                                &add_v->value, sizeof (add_v->value));
              BV (clib_bihash_unlock_bucket) (b);
@@ -793,7 +830,7 @@ static_always_inline int BV (clib_bihash_add_del_inline_with_hash)
        {
          for (i = 0; i < limit; i++)
            {
-             if (is_stale_cb (&(v->kvp[i]), arg))
+             if (is_stale_cb (&(v->kvp[i]), is_stale_arg))
                {
                  clib_memcpy_fast (&(v->kvp[i]), add_v, sizeof (*add_v));
                  CLIB_MEMORY_STORE_BARRIER ();
@@ -809,10 +846,13 @@ static_always_inline int BV (clib_bihash_add_del_inline_with_hash)
     {
       for (i = 0; i < limit; i++)
        {
+         /* no sense even looking at this one */
+         if (BV (clib_bihash_is_free) (&(v->kvp[i])))
+           continue;
          /* Found the key? Kill it... */
          if (BV (clib_bihash_key_compare) (v->kvp[i].key, add_v->key))
            {
-             clib_memset_u8 (&(v->kvp[i]), 0xff, sizeof (*(add_v)));
+             BV (clib_bihash_mark_free) (&(v->kvp[i]));
              /* Is the bucket empty? */
              if (PREDICT_TRUE (b->refcnt > 1))
                {
@@ -827,8 +867,13 @@ static_always_inline int BV (clib_bihash_add_del_inline_with_hash)
                      b->linear_search = 0;
                      b->log2_pages = 0;
                      /* Clean up the bucket-level kvp array */
-                     clib_memset_u8 ((b + 1), 0xff, BIHASH_KVP_PER_PAGE *
-                                     sizeof (BVT (clib_bihash_kv)));
+                     BVT (clib_bihash_kv) *v = (void *) (b + 1);
+                     int j;
+                     for (j = 0; j < BIHASH_KVP_PER_PAGE; j++)
+                       {
+                         BV (clib_bihash_mark_free) (v);
+                         v++;
+                       }
                      CLIB_MEMORY_STORE_BARRIER ();
                      BV (clib_bihash_unlock_bucket) (b);
                      BV (clib_bihash_increment_stat) (h, BIHASH_STAT_del, 1);
@@ -975,7 +1020,15 @@ static_always_inline int BV (clib_bihash_add_del_inline)
 {
   u64 hash = BV (clib_bihash_hash) (add_v);
   return BV (clib_bihash_add_del_inline_with_hash) (h, add_v, hash, is_add,
-                                                   is_stale_cb, arg);
+                                                   is_stale_cb, arg, 0, 0);
+}
+
+int BV (clib_bihash_add_del_with_hash) (BVT (clib_bihash) * h,
+                                       BVT (clib_bihash_kv) * add_v, u64 hash,
+                                       int is_add)
+{
+  return BV (clib_bihash_add_del_inline_with_hash) (h, add_v, hash, is_add, 0,
+                                                   0, 0, 0);
 }
 
 int BV (clib_bihash_add_del)
@@ -991,6 +1044,15 @@ int BV (clib_bihash_add_or_overwrite_stale)
   return BV (clib_bihash_add_del_inline) (h, add_v, 1, stale_callback, arg);
 }
 
+int BV (clib_bihash_add_with_overwrite_cb) (
+  BVT (clib_bihash) * h, BVT (clib_bihash_kv) * add_v,
+  void (overwrite_cb) (BVT (clib_bihash_kv) *, void *), void *arg)
+{
+  u64 hash = BV (clib_bihash_hash) (add_v);
+  return BV (clib_bihash_add_del_inline_with_hash) (h, add_v, hash, 1, 0, 0,
+                                                   overwrite_cb, arg);
+}
+
 int BV (clib_bihash_search)
   (BVT (clib_bihash) * h,
    BVT (clib_bihash_kv) * search_key, BVT (clib_bihash_kv) * valuep)
@@ -1009,11 +1071,11 @@ u8 *BV (format_bihash) (u8 * s, va_list * args)
   u64 active_buckets = 0;
   u64 linear_buckets = 0;
 
-  s = format (s, "Hash table %s\n", h->name ? h->name : (u8 *) "(unnamed)");
+  s = format (s, "Hash table '%s'\n", h->name ? h->name : (u8 *) "(unnamed)");
 
 #if BIHASH_LAZY_INSTANTIATE
   if (PREDICT_FALSE (h->instantiated == 0))
-    return format (s, "[empty, uninitialized]");
+    return format (s, "    empty, uninitialized");
 #endif
 
   for (i = 0; i < h->nbuckets; i++)
@@ -1052,11 +1114,11 @@ u8 *BV (format_bihash) (u8 * s, va_list * args)
                }
              if (verbose)
                {
-                 if (h->fmt_fn)
+                 if (h->kvp_fmt_fn)
                    {
                      s = format (s, "    %d: %U\n",
                                  j * BIHASH_KVP_PER_PAGE + k,
-                                 h->fmt_fn, &(v->kvp[k]), verbose);
+                                 h->kvp_fmt_fn, &(v->kvp[k]), verbose);
                    }
                  else
                    {
@@ -1106,8 +1168,8 @@ u8 *BV (format_bihash) (u8 * s, va_list * args)
          c = c->next;
        }
       s = format (s,
-                 "    heap: %u chunks allocated\n"
-                 "          used %UB, scrap %UB\n", n_chunks,
+                 "    heap: %u chunk(s) allocated\n"
+                 "          bytes: used %U, scrap %U\n", n_chunks,
                  format_memory_size, total_size,
                  format_memory_size, bytes_left);
     }