]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/hashmap.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / hashmap.c
index 49a04795923bc07c41adf3c8de77b95d51ca8302..cc4423b2af10f960a608daabd42126f85b0a7072 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
 
 #include "alloc-util.h"
 #include "hashmap.h"
+#include "fileio.h"
 #include "macro.h"
 #include "mempool.h"
 #include "process-util.h"
 #include "random-util.h"
 #include "set.h"
 #include "siphash24.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
 #include <pthread.h>
 #include "list.h"
 #endif
@@ -142,7 +145,7 @@ typedef uint8_t dib_raw_t;
 
 #define DIB_FREE UINT_MAX
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
 struct hashmap_debug_info {
         LIST_FIELDS(struct hashmap_debug_info, debug_list);
         unsigned max_entries;  /* high watermark of n_entries */
@@ -278,6 +281,28 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
         },
 };
 
+#ifdef VALGRIND
+__attribute__((destructor)) static void cleanup_pools(void) {
+        _cleanup_free_ char *t = NULL;
+        int r;
+
+        /* Be nice to valgrind */
+
+        /* The pool is only allocated by the main thread, but the memory can
+         * be passed to other threads. Let's clean up if we are the main thread
+         * and no other threads are live. */
+        if (!is_main_thread())
+                return;
+
+        r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t);
+        if (r < 0 || !streq(t, "1"))
+                return;
+
+        mempool_drop(&hashmap_pool);
+        mempool_drop(&ordered_hashmap_pool);
+}
+#endif
+
 static unsigned n_buckets(HashmapBase *h) {
         return h->has_indirect ? h->indirect.n_buckets
                                : hashmap_type_info[h->type].n_direct_buckets;
@@ -499,7 +524,7 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) {
         dibs = dib_raw_ptr(h);
         assert(dibs[idx] != DIB_RAW_FREE);
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         h->debug.rem_count++;
         h->debug.last_rem_idx = idx;
 #endif
@@ -508,7 +533,7 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) {
         /* Find the stop bucket ("right"). It is either free or has DIB == 0. */
         for (right = next_idx(h, left); ; right = next_idx(h, right)) {
                 raw_dib = dibs[right];
-                if (raw_dib == 0 || raw_dib == DIB_RAW_FREE)
+                if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
                         break;
 
                 /* The buckets are not supposed to be all occupied and with DIB > 0.
@@ -578,7 +603,7 @@ static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *
                 assert(e->p.b.key == i->next_key);
         }
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         i->prev_idx = idx;
 #endif
 
@@ -635,7 +660,7 @@ static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
         }
 
         idx = i->idx;
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         i->prev_idx = idx;
 #endif
 
@@ -658,7 +683,7 @@ static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
                 return IDX_NIL;
         }
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         if (i->idx == IDX_FIRST) {
                 i->put_count = h->debug.put_count;
                 i->rem_count = h->debug.rem_count;
@@ -750,7 +775,7 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
                 shared_hash_key_initialized= true;
         }
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         h->debug.func = func;
         h->debug.file = file;
         h->debug.line = line;
@@ -807,7 +832,7 @@ static void hashmap_free_no_clear(HashmapBase *h) {
         assert(!h->has_indirect);
         assert(!h->n_direct_entries);
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
         LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
         assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
@@ -919,7 +944,7 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
         dib_raw_t raw_dib, *dibs;
         unsigned dib, distance;
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         h->debug.put_count++;
 #endif
 
@@ -927,7 +952,7 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
 
         for (distance = 0; ; distance++) {
                 raw_dib = dibs[idx];
-                if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) {
+                if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
                         if (raw_dib == DIB_RAW_REHASH)
                                 bucket_move_entry(h, swap, idx, IDX_TMP);
 
@@ -1012,7 +1037,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
         assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
 
         n_entries_inc(h);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
 #endif
 
@@ -1240,7 +1265,7 @@ int hashmap_replace(Hashmap *h, const void *key, void *value) {
         idx = bucket_scan(h, hash, key);
         if (idx != IDX_NIL) {
                 e = plain_bucket_at(h, idx);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
                 /* Although the key is equal, the key pointer may have changed,
                  * and this would break our assumption for iterating. So count
                  * this operation as incompatible with iteration. */
@@ -1764,6 +1789,9 @@ void *ordered_hashmap_next(OrderedHashmap *h, const void *key) {
 int set_consume(Set *s, void *value) {
         int r;
 
+        assert(s);
+        assert(value);
+
         r = set_put(s, value);
         if (r <= 0)
                 free(value);
@@ -1791,6 +1819,8 @@ int set_put_strdupv(Set *s, char **l) {
         int n = 0, r;
         char **i;
 
+        assert(s);
+
         STRV_FOREACH(i, l) {
                 r = set_put_strdup(s, *i);
                 if (r < 0)
@@ -1801,3 +1831,23 @@ int set_put_strdupv(Set *s, char **l) {
 
         return n;
 }
+
+int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
+        const char *p = v;
+        int r;
+
+        assert(s);
+        assert(v);
+
+        for (;;) {
+                char *word;
+
+                r = extract_first_word(&p, &word, separators, flags);
+                if (r <= 0)
+                        return r;
+
+                r = set_consume(s, word);
+                if (r < 0)
+                        return r;
+        }
+}