]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/hashmap.c
tree-wide: "<n>bit" → "<n>-bit"
[thirdparty/systemd.git] / src / basic / hashmap.c
index 62380b0e4a152546428f9b429286918a03a489fe..3093156748035ff22815b78d20c0596d1e7bbba5 100644 (file)
@@ -5,10 +5,14 @@
 #include <pthread.h>
 #include <stdint.h>
 #include <stdlib.h>
+#if HAVE_VALGRIND_VALGRIND_H
+#  include <valgrind/valgrind.h>
+#endif
 
 #include "alloc-util.h"
 #include "fileio.h"
 #include "hashmap.h"
+#include "logarithm.h"
 #include "macro.h"
 #include "memory-util.h"
 #include "mempool.h"
@@ -170,9 +174,9 @@ struct _packed_ indirect_storage {
 };
 
 struct direct_storage {
-        /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit.
-         * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit,
-         *              or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */
+        /* This gives us 39 bytes on 64-bit, or 35 bytes on 32-bit.
+         * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64-bit,
+         *              or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32-bit. */
         uint8_t storage[sizeof(struct indirect_storage)];
 };
 
@@ -273,29 +277,32 @@ static _used_ const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX
         },
 };
 
-#if VALGRIND
-_destructor_ static void cleanup_pools(void) {
-        _cleanup_free_ char *t = NULL;
+void hashmap_trim_pools(void) {
         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. */
 
-        /* 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. */
-        /* We build our own is_main_thread() here, which doesn't use C11
-         * TLS based caching of the result. That's because valgrind apparently
-         * doesn't like malloc() (which C11 TLS internally uses) to be called
-         * from a GCC destructors. */
+        /* We build our own is_main_thread() here, which doesn't use C11 TLS based caching of the
+         * result. That's because valgrind apparently doesn't like TLS to be used from a GCC destructor. */
         if (getpid() != gettid())
-                return;
+                return (void) log_debug("Not cleaning up memory pools, not in main thread.");
 
-        r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t);
-        if (r < 0 || !streq(t, "1"))
-                return;
+        r = get_process_threads(0);
+        if (r < 0)
+                return (void) log_debug_errno(r, "Failed to determine number of threads, not cleaning up memory pools: %m");
+        if (r != 1)
+                return (void) log_debug("Not cleaning up memory pools, running in multi-threaded process.");
 
-        mempool_drop(&hashmap_pool);
-        mempool_drop(&ordered_hashmap_pool);
+        mempool_trim(&hashmap_pool);
+        mempool_trim(&ordered_hashmap_pool);
+}
+
+#if HAVE_VALGRIND_VALGRIND_H
+_destructor_ static void cleanup_pools(void) {
+        /* Be nice to valgrind */
+        if (RUNNING_ON_VALGRIND)
+                hashmap_trim_pools();
 }
 #endif
 
@@ -372,8 +379,9 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
 }
 
 static struct hashmap_base_entry* bucket_at(HashmapBase *h, unsigned idx) {
-        return (struct hashmap_base_entry*)
-                ((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
+        return CAST_ALIGN_PTR(
+                        struct hashmap_base_entry,
+                        (uint8_t *) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
 }
 
 static struct plain_hashmap_entry* plain_bucket_at(Hashmap *h, unsigned idx) {
@@ -771,16 +779,15 @@ static void shared_hash_key_initialize(void) {
 static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type  HASHMAP_DEBUG_PARAMS) {
         HashmapBase *h;
         const struct hashmap_type_info *hi = &hashmap_type_info[type];
-        bool up;
 
-        up = mempool_enabled();
+        bool use_pool = mempool_enabled && mempool_enabled();  /* mempool_enabled is a weak symbol */
 
-        h = up ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
+        h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
         if (!h)
                 return NULL;
 
         h->type = type;
-        h->from_pool = up;
+        h->from_pool = use_pool;
         h->hash_ops = hash_ops ?: &trivial_hash_ops;
 
         if (type == HASHMAP_TYPE_ORDERED) {
@@ -1191,7 +1198,7 @@ static int resize_buckets(HashmapBase *h, unsigned entries_add) {
                 } while (rehash_next);
         }
 
-        assert(n_rehashed == n_entries(h));
+        assert_se(n_rehashed == n_entries(h));
 
         return 1;
 }
@@ -1752,7 +1759,7 @@ HashmapBase* _hashmap_copy(HashmapBase *h  HASHMAP_DEBUG_PARAMS) {
         }
 
         if (r < 0)
-                return _hashmap_free(copy, false, false);
+                return _hashmap_free(copy, NULL, NULL);
 
         return copy;
 }
@@ -1883,11 +1890,10 @@ int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l  HA
 }
 
 int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
-        const char *p = v;
+        const char *p = ASSERT_PTR(v);
         int r;
 
         assert(s);
-        assert(v);
 
         for (;;) {
                 char *word;
@@ -2080,6 +2086,8 @@ static bool set_fnmatch_one(Set *patterns, const char *needle) {
 
         assert(needle);
 
+        /* Any failure of fnmatch() is treated as equivalent to FNM_NOMATCH, i.e. as non-matching pattern */
+
         SET_FOREACH(p, patterns)
                 if (fnmatch(p, needle, 0) == 0)
                         return true;