#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"
};
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)];
};
},
};
-#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
}
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) {
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) {
} while (rehash_next);
}
- assert(n_rehashed == n_entries(h));
+ assert_se(n_rehashed == n_entries(h));
return 1;
}
}
if (r < 0)
- return _hashmap_free(copy, false, false);
+ return _hashmap_free(copy, NULL, NULL);
return copy;
}
}
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;
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;