common: compile libhashtable as C++
authorSimon Marchi <simon.marchi@efficios.com>
Wed, 22 Sep 2021 12:13:04 +0000 (08:13 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 17 Nov 2021 23:58:46 +0000 (18:58 -0500)
Change-Id: Ia91d3207ffffb0cd45ee987107058dc9e4690c94
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/common/hashtable/Makefile.am
src/common/hashtable/hashtable.c [deleted file]
src/common/hashtable/hashtable.cpp [new file with mode: 0644]
src/common/hashtable/hashtable.h
src/common/hashtable/utils.c [deleted file]
src/common/hashtable/utils.cpp [new file with mode: 0644]

index 5f6770a815b9e8fd50b7dd4a4f085abab218bc16..b14254b34f051a5cf5c1289a64c400b36691efee 100644 (file)
@@ -2,8 +2,11 @@
 
 noinst_LTLIBRARIES = libhashtable.la
 
-libhashtable_la_SOURCES = hashtable.c hashtable.h \
-                         utils.c utils.h \
-                         hashtable-symbols.h
+libhashtable_la_SOURCES = \
+       hashtable.cpp \
+       hashtable.h \
+       hashtable-symbols.h \
+        utils.cpp \
+       utils.h
 
 libhashtable_la_LIBADD = $(URCU_LIBS) $(URCU_CDS_LIBS)
diff --git a/src/common/hashtable/hashtable.c b/src/common/hashtable/hashtable.c
deleted file mode 100644 (file)
index ac76580..0000000
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <string.h>
-#include <urcu.h>
-#include <urcu/compiler.h>
-
-#include <common/common.h>
-#include <common/defaults.h>
-
-#include "hashtable.h"
-#include "utils.h"
-
-/* seed_lock protects both seed_init and lttng_ht_seed. */
-static pthread_mutex_t seed_lock = PTHREAD_MUTEX_INITIALIZER;
-static bool seed_init;
-unsigned long lttng_ht_seed;
-
-static unsigned long min_hash_alloc_size = 1;
-static unsigned long max_hash_buckets_size = 0;
-
-/*
- * Getter/lookup functions need to be called with RCU read-side lock
- * held. However, modification functions (add, add_unique, replace, del)
- * take the RCU lock internally, so it does not matter whether the
- * caller hold the RCU lock or not.
- */
-
-/*
- * Match function for string node.
- */
-static int match_str(struct cds_lfht_node *node, const void *key)
-{
-       struct lttng_ht_node_str *match_node =
-               caa_container_of(node, struct lttng_ht_node_str, node);
-
-       return hash_match_key_str(match_node->key, (void *) key);
-}
-
-/*
- * Match function for ulong node.
- */
-static int match_ulong(struct cds_lfht_node *node, const void *key)
-{
-       struct lttng_ht_node_ulong *match_node =
-               caa_container_of(node, struct lttng_ht_node_ulong, node);
-
-       return hash_match_key_ulong((void *) match_node->key, (void *) key);
-}
-
-/*
- * Match function for u64 node.
- */
-static int match_u64(struct cds_lfht_node *node, const void *key)
-{
-       struct lttng_ht_node_u64 *match_node =
-               caa_container_of(node, struct lttng_ht_node_u64, node);
-
-       return hash_match_key_u64(&match_node->key, (void *) key);
-}
-
-/*
- * Match function for two uint64_t node.
- */
-static int match_two_u64(struct cds_lfht_node *node, const void *key)
-{
-       struct lttng_ht_node_two_u64 *match_node =
-               caa_container_of(node, struct lttng_ht_node_two_u64, node);
-
-       return hash_match_key_two_u64((void *) &match_node->key, (void *) key);
-}
-
-static inline
-const char *lttng_ht_type_str(enum lttng_ht_type type)
-{
-       switch (type) {
-       case LTTNG_HT_TYPE_STRING:
-               return "STRING";
-       case LTTNG_HT_TYPE_ULONG:
-               return "ULONG";
-       case LTTNG_HT_TYPE_U64:
-               return "U64";
-       case LTTNG_HT_TYPE_TWO_U64:
-               return "TWO_U64";
-       default:
-               ERR("Unknown lttng hashtable type %d", type);
-               abort();
-       }
-}
-
-/*
- * Return an allocated lttng hashtable.
- */
-struct lttng_ht *lttng_ht_new(unsigned long size, int type)
-{
-       struct lttng_ht *ht;
-
-       /* Test size */
-       if (!size)
-               size = DEFAULT_HT_SIZE;
-
-       pthread_mutex_lock(&seed_lock);
-       if (!seed_init) {
-               lttng_ht_seed = (unsigned long) time(NULL);
-               seed_init = true;
-       }
-       pthread_mutex_unlock(&seed_lock);
-
-       ht = zmalloc(sizeof(*ht));
-       if (ht == NULL) {
-               PERROR("zmalloc lttng_ht");
-               goto error;
-       }
-
-       ht->ht = cds_lfht_new(size, min_hash_alloc_size, max_hash_buckets_size,
-                       CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
-       /*
-        * There is already an assert in the RCU hashtable code so if the ht is
-        * NULL here there is a *huge* problem.
-        */
-       LTTNG_ASSERT(ht->ht);
-
-       switch (type) {
-       case LTTNG_HT_TYPE_STRING:
-               ht->match_fct = match_str;
-               ht->hash_fct = hash_key_str;
-               break;
-       case LTTNG_HT_TYPE_ULONG:
-               ht->match_fct = match_ulong;
-               ht->hash_fct = hash_key_ulong;
-               break;
-       case LTTNG_HT_TYPE_U64:
-               ht->match_fct = match_u64;
-               ht->hash_fct = hash_key_u64;
-               break;
-       case LTTNG_HT_TYPE_TWO_U64:
-               ht->match_fct = match_two_u64;
-               ht->hash_fct = hash_key_two_u64;
-               break;
-       default:
-               ERR("Unknown lttng hashtable type %d", type);
-               lttng_ht_destroy(ht);
-               goto error;
-       }
-
-       DBG3("Created hashtable size %lu at %p of type %s", size, ht->ht,
-                       lttng_ht_type_str(type));
-
-       return ht;
-
-error:
-       return NULL;
-}
-
-/*
- * Free a lttng hashtable.
- */
-void lttng_ht_destroy(struct lttng_ht *ht)
-{
-       int ret;
-
-       ret = cds_lfht_destroy(ht->ht, NULL);
-       LTTNG_ASSERT(!ret);
-       free(ht);
-}
-
-/*
- * Init lttng ht node string.
- */
-void lttng_ht_node_init_str(struct lttng_ht_node_str *node, char *key)
-{
-       LTTNG_ASSERT(node);
-
-       node->key = key;
-       cds_lfht_node_init(&node->node);
-}
-
-/*
- * Init lttng ht node unsigned long.
- */
-void lttng_ht_node_init_ulong(struct lttng_ht_node_ulong *node,
-               unsigned long key)
-{
-       LTTNG_ASSERT(node);
-
-       node->key = key;
-       cds_lfht_node_init(&node->node);
-}
-
-/*
- * Init lttng ht node uint64_t.
- */
-void lttng_ht_node_init_u64(struct lttng_ht_node_u64 *node,
-               uint64_t key)
-{
-       LTTNG_ASSERT(node);
-
-       node->key = key;
-       cds_lfht_node_init(&node->node);
-}
-
-/*
- * Init lttng ht node with two uint64_t.
- */
-void lttng_ht_node_init_two_u64(struct lttng_ht_node_two_u64 *node,
-               uint64_t key1, uint64_t key2)
-{
-       LTTNG_ASSERT(node);
-
-       node->key.key1 = key1;
-       node->key.key2 = key2;
-       cds_lfht_node_init(&node->node);
-}
-
-/*
- * Free lttng ht node string.
- */
-void lttng_ht_node_free_str(struct lttng_ht_node_str *node)
-{
-       LTTNG_ASSERT(node);
-       free(node);
-}
-
-/*
- * Free lttng ht node unsigned long.
- */
-void lttng_ht_node_free_ulong(struct lttng_ht_node_ulong *node)
-{
-       LTTNG_ASSERT(node);
-       free(node);
-}
-
-/*
- * Free lttng ht node uint64_t.
- */
-void lttng_ht_node_free_u64(struct lttng_ht_node_u64 *node)
-{
-       LTTNG_ASSERT(node);
-       free(node);
-}
-
-/*
- * Free lttng ht node two uint64_t.
- */
-void lttng_ht_node_free_two_u64(struct lttng_ht_node_two_u64 *node)
-{
-       LTTNG_ASSERT(node);
-       free(node);
-}
-
-/*
- * Lookup function in hashtable.
- */
-void lttng_ht_lookup(struct lttng_ht *ht, const void *key,
-               struct lttng_ht_iter *iter)
-{
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-
-       cds_lfht_lookup(ht->ht, ht->hash_fct(key, lttng_ht_seed),
-                       ht->match_fct, key, &iter->iter);
-}
-
-/*
- * Add unique string node to hashtable.
- */
-void lttng_ht_add_unique_str(struct lttng_ht *ht,
-               struct lttng_ht_node_str *node)
-{
-       struct cds_lfht_node *node_ptr;
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(node);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       node_ptr = cds_lfht_add_unique(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
-                       ht->match_fct, node->key, &node->node);
-       rcu_read_unlock();
-       LTTNG_ASSERT(node_ptr == &node->node);
-}
-
-/*
- * Add string node to hashtable.
- */
-void lttng_ht_add_str(struct lttng_ht *ht,
-               struct lttng_ht_node_str *node)
-{
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(node);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       cds_lfht_add(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
-                       &node->node);
-       rcu_read_unlock();
-}
-
-/*
- * Add unsigned long node to hashtable.
- */
-void lttng_ht_add_ulong(struct lttng_ht *ht, struct lttng_ht_node_ulong *node)
-{
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(node);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       cds_lfht_add(ht->ht, ht->hash_fct((void *) node->key, lttng_ht_seed),
-                       &node->node);
-       rcu_read_unlock();
-}
-
-/*
- * Add uint64_t node to hashtable.
- */
-void lttng_ht_add_u64(struct lttng_ht *ht, struct lttng_ht_node_u64 *node)
-{
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(node);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       cds_lfht_add(ht->ht, ht->hash_fct(&node->key, lttng_ht_seed),
-                       &node->node);
-       rcu_read_unlock();
-}
-
-/*
- * Add unique unsigned long node to hashtable.
- */
-void lttng_ht_add_unique_ulong(struct lttng_ht *ht,
-               struct lttng_ht_node_ulong *node)
-{
-       struct cds_lfht_node *node_ptr;
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(node);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       node_ptr = cds_lfht_add_unique(ht->ht,
-                       ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
-                       (void *) node->key, &node->node);
-       rcu_read_unlock();
-       LTTNG_ASSERT(node_ptr == &node->node);
-}
-
-/*
- * Add unique uint64_t node to hashtable.
- */
-void lttng_ht_add_unique_u64(struct lttng_ht *ht,
-               struct lttng_ht_node_u64 *node)
-{
-       struct cds_lfht_node *node_ptr;
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(node);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       node_ptr = cds_lfht_add_unique(ht->ht,
-                       ht->hash_fct(&node->key, lttng_ht_seed), ht->match_fct,
-                       &node->key, &node->node);
-       rcu_read_unlock();
-       LTTNG_ASSERT(node_ptr == &node->node);
-}
-
-/*
- * Add unique two uint64_t node to hashtable.
- */
-void lttng_ht_add_unique_two_u64(struct lttng_ht *ht,
-               struct lttng_ht_node_two_u64 *node)
-{
-       struct cds_lfht_node *node_ptr;
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(node);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       node_ptr = cds_lfht_add_unique(ht->ht,
-                       ht->hash_fct((void *) &node->key, lttng_ht_seed), ht->match_fct,
-                       (void *) &node->key, &node->node);
-       rcu_read_unlock();
-       LTTNG_ASSERT(node_ptr == &node->node);
-}
-
-/*
- * Add replace unsigned long node to hashtable.
- */
-struct lttng_ht_node_ulong *lttng_ht_add_replace_ulong(struct lttng_ht *ht,
-               struct lttng_ht_node_ulong *node)
-{
-       struct cds_lfht_node *node_ptr;
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(node);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       node_ptr = cds_lfht_add_replace(ht->ht,
-                       ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
-                       (void *) node->key, &node->node);
-       rcu_read_unlock();
-       if (!node_ptr) {
-               return NULL;
-       } else {
-               return caa_container_of(node_ptr, struct lttng_ht_node_ulong, node);
-       }
-       LTTNG_ASSERT(node_ptr == &node->node);
-}
-
-/*
- * Add replace unsigned long node to hashtable.
- */
-struct lttng_ht_node_u64 *lttng_ht_add_replace_u64(struct lttng_ht *ht,
-               struct lttng_ht_node_u64 *node)
-{
-       struct cds_lfht_node *node_ptr;
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(node);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       node_ptr = cds_lfht_add_replace(ht->ht,
-                       ht->hash_fct(&node->key, lttng_ht_seed), ht->match_fct,
-                       &node->key, &node->node);
-       rcu_read_unlock();
-       if (!node_ptr) {
-               return NULL;
-       } else {
-               return caa_container_of(node_ptr, struct lttng_ht_node_u64, node);
-       }
-       LTTNG_ASSERT(node_ptr == &node->node);
-}
-
-/*
- * Delete node from hashtable.
- */
-int lttng_ht_del(struct lttng_ht *ht, struct lttng_ht_iter *iter)
-{
-       int ret;
-
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(iter);
-
-       /* RCU read lock protects from ABA. */
-       rcu_read_lock();
-       ret = cds_lfht_del(ht->ht, iter->iter.node);
-       rcu_read_unlock();
-       return ret;
-}
-
-/*
- * Get first node in the hashtable.
- */
-void lttng_ht_get_first(struct lttng_ht *ht, struct lttng_ht_iter *iter)
-{
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(iter);
-
-       cds_lfht_first(ht->ht, &iter->iter);
-}
-
-/*
- * Get next node in the hashtable.
- */
-void lttng_ht_get_next(struct lttng_ht *ht, struct lttng_ht_iter *iter)
-{
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-       LTTNG_ASSERT(iter);
-
-       cds_lfht_next(ht->ht, &iter->iter);
-}
-
-/*
- * Return the number of nodes in the hashtable.
- */
-unsigned long lttng_ht_get_count(struct lttng_ht *ht)
-{
-       long scb, sca;
-       unsigned long count;
-
-       LTTNG_ASSERT(ht);
-       LTTNG_ASSERT(ht->ht);
-
-       /* RCU read lock protects from ABA and allows RCU traversal. */
-       rcu_read_lock();
-       cds_lfht_count_nodes(ht->ht, &scb, &count, &sca);
-       rcu_read_unlock();
-
-       return count;
-}
-
-/*
- * Return lttng ht string node from iterator.
- */
-struct lttng_ht_node_str *lttng_ht_iter_get_node_str(
-               struct lttng_ht_iter *iter)
-{
-       struct cds_lfht_node *node;
-
-       LTTNG_ASSERT(iter);
-       node = cds_lfht_iter_get_node(&iter->iter);
-       if (!node) {
-               return NULL;
-       }
-       return caa_container_of(node, struct lttng_ht_node_str, node);
-}
-
-/*
- * Return lttng ht unsigned long node from iterator.
- */
-struct lttng_ht_node_ulong *lttng_ht_iter_get_node_ulong(
-               struct lttng_ht_iter *iter)
-{
-       struct cds_lfht_node *node;
-
-       LTTNG_ASSERT(iter);
-       node = cds_lfht_iter_get_node(&iter->iter);
-       if (!node) {
-               return NULL;
-       }
-       return caa_container_of(node, struct lttng_ht_node_ulong, node);
-}
-
-/*
- * Return lttng ht unsigned long node from iterator.
- */
-struct lttng_ht_node_u64 *lttng_ht_iter_get_node_u64(
-               struct lttng_ht_iter *iter)
-{
-       struct cds_lfht_node *node;
-
-       LTTNG_ASSERT(iter);
-       node = cds_lfht_iter_get_node(&iter->iter);
-       if (!node) {
-               return NULL;
-       }
-       return caa_container_of(node, struct lttng_ht_node_u64, node);
-}
-
-/*
- * Return lttng ht stream and index id node from iterator.
- */
-struct lttng_ht_node_two_u64 *lttng_ht_iter_get_node_two_u64(
-               struct lttng_ht_iter *iter)
-{
-       struct cds_lfht_node *node;
-
-       LTTNG_ASSERT(iter);
-       node = cds_lfht_iter_get_node(&iter->iter);
-       if (!node) {
-               return NULL;
-       }
-       return caa_container_of(node, struct lttng_ht_node_two_u64, node);
-}
diff --git a/src/common/hashtable/hashtable.cpp b/src/common/hashtable/hashtable.cpp
new file mode 100644 (file)
index 0000000..7112deb
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <string.h>
+#include <urcu.h>
+#include <urcu/compiler.h>
+
+#include <common/common.h>
+#include <common/defaults.h>
+
+#include "hashtable.h"
+#include "utils.h"
+
+/* seed_lock protects both seed_init and lttng_ht_seed. */
+static pthread_mutex_t seed_lock = PTHREAD_MUTEX_INITIALIZER;
+static bool seed_init;
+unsigned long lttng_ht_seed;
+
+static unsigned long min_hash_alloc_size = 1;
+static unsigned long max_hash_buckets_size = 0;
+
+/*
+ * Getter/lookup functions need to be called with RCU read-side lock
+ * held. However, modification functions (add, add_unique, replace, del)
+ * take the RCU lock internally, so it does not matter whether the
+ * caller hold the RCU lock or not.
+ */
+
+/*
+ * Match function for string node.
+ */
+static int match_str(struct cds_lfht_node *node, const void *key)
+{
+       struct lttng_ht_node_str *match_node =
+               caa_container_of(node, struct lttng_ht_node_str, node);
+
+       return hash_match_key_str(match_node->key, (void *) key);
+}
+
+/*
+ * Match function for ulong node.
+ */
+static int match_ulong(struct cds_lfht_node *node, const void *key)
+{
+       struct lttng_ht_node_ulong *match_node =
+               caa_container_of(node, struct lttng_ht_node_ulong, node);
+
+       return hash_match_key_ulong((void *) match_node->key, (void *) key);
+}
+
+/*
+ * Match function for u64 node.
+ */
+static int match_u64(struct cds_lfht_node *node, const void *key)
+{
+       struct lttng_ht_node_u64 *match_node =
+               caa_container_of(node, struct lttng_ht_node_u64, node);
+
+       return hash_match_key_u64(&match_node->key, (void *) key);
+}
+
+/*
+ * Match function for two uint64_t node.
+ */
+static int match_two_u64(struct cds_lfht_node *node, const void *key)
+{
+       struct lttng_ht_node_two_u64 *match_node =
+               caa_container_of(node, struct lttng_ht_node_two_u64, node);
+
+       return hash_match_key_two_u64((void *) &match_node->key, (void *) key);
+}
+
+static inline
+const char *lttng_ht_type_str(enum lttng_ht_type type)
+{
+       switch (type) {
+       case LTTNG_HT_TYPE_STRING:
+               return "STRING";
+       case LTTNG_HT_TYPE_ULONG:
+               return "ULONG";
+       case LTTNG_HT_TYPE_U64:
+               return "U64";
+       case LTTNG_HT_TYPE_TWO_U64:
+               return "TWO_U64";
+       default:
+               ERR("Unknown lttng hashtable type %d", type);
+               abort();
+       }
+}
+
+/*
+ * Return an allocated lttng hashtable.
+ */
+struct lttng_ht *lttng_ht_new(unsigned long size, lttng_ht_type type)
+{
+       struct lttng_ht *ht;
+
+       /* Test size */
+       if (!size)
+               size = DEFAULT_HT_SIZE;
+
+       pthread_mutex_lock(&seed_lock);
+       if (!seed_init) {
+               lttng_ht_seed = (unsigned long) time(NULL);
+               seed_init = true;
+       }
+       pthread_mutex_unlock(&seed_lock);
+
+       ht = (lttng_ht *) zmalloc(sizeof(*ht));
+       if (ht == NULL) {
+               PERROR("zmalloc lttng_ht");
+               goto error;
+       }
+
+       ht->ht = cds_lfht_new(size, min_hash_alloc_size, max_hash_buckets_size,
+                       CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
+       /*
+        * There is already an assert in the RCU hashtable code so if the ht is
+        * NULL here there is a *huge* problem.
+        */
+       LTTNG_ASSERT(ht->ht);
+
+       switch (type) {
+       case LTTNG_HT_TYPE_STRING:
+               ht->match_fct = match_str;
+               ht->hash_fct = hash_key_str;
+               break;
+       case LTTNG_HT_TYPE_ULONG:
+               ht->match_fct = match_ulong;
+               ht->hash_fct = hash_key_ulong;
+               break;
+       case LTTNG_HT_TYPE_U64:
+               ht->match_fct = match_u64;
+               ht->hash_fct = hash_key_u64;
+               break;
+       case LTTNG_HT_TYPE_TWO_U64:
+               ht->match_fct = match_two_u64;
+               ht->hash_fct = hash_key_two_u64;
+               break;
+       default:
+               ERR("Unknown lttng hashtable type %d", type);
+               lttng_ht_destroy(ht);
+               goto error;
+       }
+
+       DBG3("Created hashtable size %lu at %p of type %s", size, ht->ht,
+                       lttng_ht_type_str(type));
+
+       return ht;
+
+error:
+       return NULL;
+}
+
+/*
+ * Free a lttng hashtable.
+ */
+void lttng_ht_destroy(struct lttng_ht *ht)
+{
+       int ret;
+
+       ret = cds_lfht_destroy(ht->ht, NULL);
+       LTTNG_ASSERT(!ret);
+       free(ht);
+}
+
+/*
+ * Init lttng ht node string.
+ */
+void lttng_ht_node_init_str(struct lttng_ht_node_str *node, char *key)
+{
+       LTTNG_ASSERT(node);
+
+       node->key = key;
+       cds_lfht_node_init(&node->node);
+}
+
+/*
+ * Init lttng ht node unsigned long.
+ */
+void lttng_ht_node_init_ulong(struct lttng_ht_node_ulong *node,
+               unsigned long key)
+{
+       LTTNG_ASSERT(node);
+
+       node->key = key;
+       cds_lfht_node_init(&node->node);
+}
+
+/*
+ * Init lttng ht node uint64_t.
+ */
+void lttng_ht_node_init_u64(struct lttng_ht_node_u64 *node,
+               uint64_t key)
+{
+       LTTNG_ASSERT(node);
+
+       node->key = key;
+       cds_lfht_node_init(&node->node);
+}
+
+/*
+ * Init lttng ht node with two uint64_t.
+ */
+void lttng_ht_node_init_two_u64(struct lttng_ht_node_two_u64 *node,
+               uint64_t key1, uint64_t key2)
+{
+       LTTNG_ASSERT(node);
+
+       node->key.key1 = key1;
+       node->key.key2 = key2;
+       cds_lfht_node_init(&node->node);
+}
+
+/*
+ * Free lttng ht node string.
+ */
+void lttng_ht_node_free_str(struct lttng_ht_node_str *node)
+{
+       LTTNG_ASSERT(node);
+       free(node);
+}
+
+/*
+ * Free lttng ht node unsigned long.
+ */
+void lttng_ht_node_free_ulong(struct lttng_ht_node_ulong *node)
+{
+       LTTNG_ASSERT(node);
+       free(node);
+}
+
+/*
+ * Free lttng ht node uint64_t.
+ */
+void lttng_ht_node_free_u64(struct lttng_ht_node_u64 *node)
+{
+       LTTNG_ASSERT(node);
+       free(node);
+}
+
+/*
+ * Free lttng ht node two uint64_t.
+ */
+void lttng_ht_node_free_two_u64(struct lttng_ht_node_two_u64 *node)
+{
+       LTTNG_ASSERT(node);
+       free(node);
+}
+
+/*
+ * Lookup function in hashtable.
+ */
+void lttng_ht_lookup(struct lttng_ht *ht, const void *key,
+               struct lttng_ht_iter *iter)
+{
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+
+       cds_lfht_lookup(ht->ht, ht->hash_fct(key, lttng_ht_seed),
+                       ht->match_fct, key, &iter->iter);
+}
+
+/*
+ * Add unique string node to hashtable.
+ */
+void lttng_ht_add_unique_str(struct lttng_ht *ht,
+               struct lttng_ht_node_str *node)
+{
+       struct cds_lfht_node *node_ptr;
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(node);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       node_ptr = cds_lfht_add_unique(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
+                       ht->match_fct, node->key, &node->node);
+       rcu_read_unlock();
+       LTTNG_ASSERT(node_ptr == &node->node);
+}
+
+/*
+ * Add string node to hashtable.
+ */
+void lttng_ht_add_str(struct lttng_ht *ht,
+               struct lttng_ht_node_str *node)
+{
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(node);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       cds_lfht_add(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
+                       &node->node);
+       rcu_read_unlock();
+}
+
+/*
+ * Add unsigned long node to hashtable.
+ */
+void lttng_ht_add_ulong(struct lttng_ht *ht, struct lttng_ht_node_ulong *node)
+{
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(node);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       cds_lfht_add(ht->ht, ht->hash_fct((void *) node->key, lttng_ht_seed),
+                       &node->node);
+       rcu_read_unlock();
+}
+
+/*
+ * Add uint64_t node to hashtable.
+ */
+void lttng_ht_add_u64(struct lttng_ht *ht, struct lttng_ht_node_u64 *node)
+{
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(node);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       cds_lfht_add(ht->ht, ht->hash_fct(&node->key, lttng_ht_seed),
+                       &node->node);
+       rcu_read_unlock();
+}
+
+/*
+ * Add unique unsigned long node to hashtable.
+ */
+void lttng_ht_add_unique_ulong(struct lttng_ht *ht,
+               struct lttng_ht_node_ulong *node)
+{
+       struct cds_lfht_node *node_ptr;
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(node);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       node_ptr = cds_lfht_add_unique(ht->ht,
+                       ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
+                       (void *) node->key, &node->node);
+       rcu_read_unlock();
+       LTTNG_ASSERT(node_ptr == &node->node);
+}
+
+/*
+ * Add unique uint64_t node to hashtable.
+ */
+void lttng_ht_add_unique_u64(struct lttng_ht *ht,
+               struct lttng_ht_node_u64 *node)
+{
+       struct cds_lfht_node *node_ptr;
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(node);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       node_ptr = cds_lfht_add_unique(ht->ht,
+                       ht->hash_fct(&node->key, lttng_ht_seed), ht->match_fct,
+                       &node->key, &node->node);
+       rcu_read_unlock();
+       LTTNG_ASSERT(node_ptr == &node->node);
+}
+
+/*
+ * Add unique two uint64_t node to hashtable.
+ */
+void lttng_ht_add_unique_two_u64(struct lttng_ht *ht,
+               struct lttng_ht_node_two_u64 *node)
+{
+       struct cds_lfht_node *node_ptr;
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(node);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       node_ptr = cds_lfht_add_unique(ht->ht,
+                       ht->hash_fct((void *) &node->key, lttng_ht_seed), ht->match_fct,
+                       (void *) &node->key, &node->node);
+       rcu_read_unlock();
+       LTTNG_ASSERT(node_ptr == &node->node);
+}
+
+/*
+ * Add replace unsigned long node to hashtable.
+ */
+struct lttng_ht_node_ulong *lttng_ht_add_replace_ulong(struct lttng_ht *ht,
+               struct lttng_ht_node_ulong *node)
+{
+       struct cds_lfht_node *node_ptr;
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(node);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       node_ptr = cds_lfht_add_replace(ht->ht,
+                       ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
+                       (void *) node->key, &node->node);
+       rcu_read_unlock();
+       if (!node_ptr) {
+               return NULL;
+       } else {
+               return caa_container_of(node_ptr, struct lttng_ht_node_ulong, node);
+       }
+       LTTNG_ASSERT(node_ptr == &node->node);
+}
+
+/*
+ * Add replace unsigned long node to hashtable.
+ */
+struct lttng_ht_node_u64 *lttng_ht_add_replace_u64(struct lttng_ht *ht,
+               struct lttng_ht_node_u64 *node)
+{
+       struct cds_lfht_node *node_ptr;
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(node);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       node_ptr = cds_lfht_add_replace(ht->ht,
+                       ht->hash_fct(&node->key, lttng_ht_seed), ht->match_fct,
+                       &node->key, &node->node);
+       rcu_read_unlock();
+       if (!node_ptr) {
+               return NULL;
+       } else {
+               return caa_container_of(node_ptr, struct lttng_ht_node_u64, node);
+       }
+       LTTNG_ASSERT(node_ptr == &node->node);
+}
+
+/*
+ * Delete node from hashtable.
+ */
+int lttng_ht_del(struct lttng_ht *ht, struct lttng_ht_iter *iter)
+{
+       int ret;
+
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(iter);
+
+       /* RCU read lock protects from ABA. */
+       rcu_read_lock();
+       ret = cds_lfht_del(ht->ht, iter->iter.node);
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * Get first node in the hashtable.
+ */
+void lttng_ht_get_first(struct lttng_ht *ht, struct lttng_ht_iter *iter)
+{
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(iter);
+
+       cds_lfht_first(ht->ht, &iter->iter);
+}
+
+/*
+ * Get next node in the hashtable.
+ */
+void lttng_ht_get_next(struct lttng_ht *ht, struct lttng_ht_iter *iter)
+{
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+       LTTNG_ASSERT(iter);
+
+       cds_lfht_next(ht->ht, &iter->iter);
+}
+
+/*
+ * Return the number of nodes in the hashtable.
+ */
+unsigned long lttng_ht_get_count(struct lttng_ht *ht)
+{
+       long scb, sca;
+       unsigned long count;
+
+       LTTNG_ASSERT(ht);
+       LTTNG_ASSERT(ht->ht);
+
+       /* RCU read lock protects from ABA and allows RCU traversal. */
+       rcu_read_lock();
+       cds_lfht_count_nodes(ht->ht, &scb, &count, &sca);
+       rcu_read_unlock();
+
+       return count;
+}
+
+/*
+ * Return lttng ht string node from iterator.
+ */
+struct lttng_ht_node_str *lttng_ht_iter_get_node_str(
+               struct lttng_ht_iter *iter)
+{
+       struct cds_lfht_node *node;
+
+       LTTNG_ASSERT(iter);
+       node = cds_lfht_iter_get_node(&iter->iter);
+       if (!node) {
+               return NULL;
+       }
+       return caa_container_of(node, struct lttng_ht_node_str, node);
+}
+
+/*
+ * Return lttng ht unsigned long node from iterator.
+ */
+struct lttng_ht_node_ulong *lttng_ht_iter_get_node_ulong(
+               struct lttng_ht_iter *iter)
+{
+       struct cds_lfht_node *node;
+
+       LTTNG_ASSERT(iter);
+       node = cds_lfht_iter_get_node(&iter->iter);
+       if (!node) {
+               return NULL;
+       }
+       return caa_container_of(node, struct lttng_ht_node_ulong, node);
+}
+
+/*
+ * Return lttng ht unsigned long node from iterator.
+ */
+struct lttng_ht_node_u64 *lttng_ht_iter_get_node_u64(
+               struct lttng_ht_iter *iter)
+{
+       struct cds_lfht_node *node;
+
+       LTTNG_ASSERT(iter);
+       node = cds_lfht_iter_get_node(&iter->iter);
+       if (!node) {
+               return NULL;
+       }
+       return caa_container_of(node, struct lttng_ht_node_u64, node);
+}
+
+/*
+ * Return lttng ht stream and index id node from iterator.
+ */
+struct lttng_ht_node_two_u64 *lttng_ht_iter_get_node_two_u64(
+               struct lttng_ht_iter *iter)
+{
+       struct cds_lfht_node *node;
+
+       LTTNG_ASSERT(iter);
+       node = cds_lfht_iter_get_node(&iter->iter);
+       if (!node) {
+               return NULL;
+       }
+       return caa_container_of(node, struct lttng_ht_node_two_u64, node);
+}
index cefd43833b721604487d12e71a1a36280c7f3e30..e150190417b7a594db359fada7237c2871039390 100644 (file)
@@ -71,7 +71,7 @@ struct lttng_ht_node_two_u64 {
 };
 
 /* Hashtable new and destroy */
-struct lttng_ht *lttng_ht_new(unsigned long size, int type);
+struct lttng_ht *lttng_ht_new(unsigned long size, enum lttng_ht_type type);
 void lttng_ht_destroy(struct lttng_ht *ht);
 
 /* Specialized node init and free functions */
diff --git a/src/common/hashtable/utils.c b/src/common/hashtable/utils.c
deleted file mode 100644 (file)
index eb51554..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Copyright (C) 2006 Bob Jenkins
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-/*
- * These are functions for producing 32-bit hashes for hash table lookup.
- * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() are
- * externally useful functions.  Routines to test the hash are included if
- * SELF_TEST is defined.  You can use this free for any purpose.  It's in the
- * public domain.  It has no warranty.
- *
- * You probably want to use hashlittle().  hashlittle() and hashbig() hash byte
- * arrays.  hashlittle() is is faster than hashbig() on little-endian machines.
- * Intel and AMD are little-endian machines.  On second thought, you probably
- * want hashlittle2(), which is identical to hashlittle() except it returns two
- * 32-bit hashes for the price of one.  You could implement hashbig2() if you
- * wanted but I haven't bothered here.
- *
- * If you want to find a hash of, say, exactly 7 integers, do
- *   a = i1;  b = i2;  c = i3;
- *   mix(a,b,c);
- *   a += i4; b += i5; c += i6;
- *   mix(a,b,c);
- *   a += i7;
- *   final(a,b,c);
- * then use c as the hash value.  If you have a variable length array of
- * 4-byte integers to hash, use hashword().  If you have a byte array (like
- * a character string), use hashlittle().  If you have several byte arrays, or
- * a mix of things, see the comments above hashlittle().
- *
- * Why is this so big?  I read 12 bytes at a time into 3 4-byte integers, then
- * mix those integers.  This is fast (you can do a lot more thorough mixing
- * with 12*3 instructions on 3 integers than you can with 3 instructions on 1
- * byte), but shoehorning those bytes into integers efficiently is messy.
- */
-
-#define _LGPL_SOURCE
-#include <stdint.h>     /* defines uint32_t etc */
-#include <stdio.h>      /* defines printf for tests */
-#include <string.h>
-#include <sys/param.h>  /* attempt to define endianness */
-#include <time.h>       /* defines time_t for timings in the test */
-#include <urcu/compiler.h>
-
-#include "utils.h"
-#include <common/compat/endian.h>    /* attempt to define endianness */
-#include <common/common.h>
-#include <common/hashtable/hashtable.h>
-
-/*
- * My best guess at if you are big-endian or little-endian.  This may
- * need adjustment.
- */
-#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
-     __BYTE_ORDER == __LITTLE_ENDIAN) || \
-    (defined(i386) || defined(__i386__) || defined(__i486__) || \
-     defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
-# define HASH_LITTLE_ENDIAN 1
-# define HASH_BIG_ENDIAN 0
-#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
-       __BYTE_ORDER == __BIG_ENDIAN) || \
-      (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
-# define HASH_LITTLE_ENDIAN 0
-# define HASH_BIG_ENDIAN 1
-#else
-# define HASH_LITTLE_ENDIAN 0
-# define HASH_BIG_ENDIAN 0
-#endif
-
-#define hashsize(n) ((uint32_t)1<<(n))
-#define hashmask(n) (hashsize(n)-1)
-#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
-
-/*
- * mix -- mix 3 32-bit values reversibly.
- *
- * This is reversible, so any information in (a,b,c) before mix() is
- * still in (a,b,c) after mix().
- *
- * If four pairs of (a,b,c) inputs are run through mix(), or through
- * mix() in reverse, there are at least 32 bits of the output that
- * are sometimes the same for one pair and different for another pair.
- * This was tested for:
- * * pairs that differed by one bit, by two bits, in any combination
- *   of top bits of (a,b,c), or in any combination of bottom bits of
- *   (a,b,c).
- * * "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
- *   the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
- *   is commonly produced by subtraction) look like a single 1-bit
- *   difference.
- * * the base values were pseudorandom, all zero but one bit set, or
- *   all zero plus a counter that starts at zero.
- *
- * Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
- * satisfy this are
- *     4  6  8 16 19  4
- *     9 15  3 18 27 15
- *    14  9  3  7 17  3
- * Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
- * for "differ" defined as + with a one-bit base and a two-bit delta.  I
- * used http://burtleburtle.net/bob/hash/avalanche.html to choose
- * the operations, constants, and arrangements of the variables.
- *
- * This does not achieve avalanche.  There are input bits of (a,b,c)
- * that fail to affect some output bits of (a,b,c), especially of a.  The
- * most thoroughly mixed value is c, but it doesn't really even achieve
- * avalanche in c.
- *
- * This allows some parallelism.  Read-after-writes are good at doubling
- * the number of bits affected, so the goal of mixing pulls in the opposite
- * direction as the goal of parallelism.  I did what I could.  Rotates
- * seem to cost as much as shifts on every machine I could lay my hands
- * on, and rotates are much kinder to the top and bottom bits, so I used
- * rotates.
- */
-#define mix(a,b,c) \
-{ \
-  a -= c;  a ^= rot(c, 4);  c += b; \
-  b -= a;  b ^= rot(a, 6);  a += c; \
-  c -= b;  c ^= rot(b, 8);  b += a; \
-  a -= c;  a ^= rot(c,16);  c += b; \
-  b -= a;  b ^= rot(a,19);  a += c; \
-  c -= b;  c ^= rot(b, 4);  b += a; \
-}
-
-/*
- * final -- final mixing of 3 32-bit values (a,b,c) into c
- *
- * Pairs of (a,b,c) values differing in only a few bits will usually
- * produce values of c that look totally different.  This was tested for
- * * pairs that differed by one bit, by two bits, in any combination
- *   of top bits of (a,b,c), or in any combination of bottom bits of
- *   (a,b,c).
- * * "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
- *   the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
- *   is commonly produced by subtraction) look like a single 1-bit
- *   difference.
- * * the base values were pseudorandom, all zero but one bit set, or
- *   all zero plus a counter that starts at zero.
- *
- * These constants passed:
- *  14 11 25 16 4 14 24
- *  12 14 25 16 4 14 24
- * and these came close:
- *   4  8 15 26 3 22 24
- *  10  8 15 26 3 22 24
- *  11  8 15 26 3 22 24
- */
-#define final(a,b,c) \
-{ \
-  c ^= b; c -= rot(b,14); \
-  a ^= c; a -= rot(c,11); \
-  b ^= a; b -= rot(a,25); \
-  c ^= b; c -= rot(b,16); \
-  a ^= c; a -= rot(c,4);  \
-  b ^= a; b -= rot(a,14); \
-  c ^= b; c -= rot(b,24); \
-}
-
-/*
- * k - the key, an array of uint32_t values
- * length - the length of the key, in uint32_ts
- * initval - the previous hash, or an arbitrary value
- */
-static uint32_t __attribute__((unused)) hashword(const uint32_t *k,
-               size_t length, uint32_t initval)
-{
-       uint32_t a, b, c;
-
-       /* Set up the internal state */
-       a = b = c = 0xdeadbeef + (((uint32_t) length) << 2) + initval;
-
-       /*----------------------------------------- handle most of the key */
-       while (length > 3) {
-               a += k[0];
-               b += k[1];
-               c += k[2];
-               mix(a, b, c);
-               length -= 3;
-               k += 3;
-       }
-
-       /*----------------------------------- handle the last 3 uint32_t's */
-       switch (length) {       /* all the case statements fall through */
-       case 3: c += k[2];
-       case 2: b += k[1];
-       case 1: a += k[0];
-               final(a, b, c);
-       case 0:                 /* case 0: nothing left to add */
-               break;
-       }
-       /*---------------------------------------------- report the result */
-       return c;
-}
-
-
-/*
- * hashword2() -- same as hashword(), but take two seeds and return two 32-bit
- * values.  pc and pb must both be nonnull, and *pc and *pb must both be
- * initialized with seeds.  If you pass in (*pb)==0, the output (*pc) will be
- * the same as the return value from hashword().
- */
-static void __attribute__((unused)) hashword2(const uint32_t *k, size_t length,
-               uint32_t *pc, uint32_t *pb)
-{
-       uint32_t a, b, c;
-
-       /* Set up the internal state */
-       a = b = c = 0xdeadbeef + ((uint32_t) (length << 2)) + *pc;
-       c += *pb;
-
-       while (length > 3) {
-               a += k[0];
-               b += k[1];
-               c += k[2];
-               mix(a, b, c);
-               length -= 3;
-               k += 3;
-       }
-
-       switch (length) {
-       case 3 :
-               c += k[2];
-       case 2 :
-               b += k[1];
-       case 1 :
-               a += k[0];
-               final(a, b, c);
-       case 0:     /* case 0: nothing left to add */
-               break;
-       }
-
-       *pc = c;
-       *pb = b;
-}
-
-/*
- * hashlittle() -- hash a variable-length key into a 32-bit value
- *   k       : the key (the unaligned variable-length array of bytes)
- *   length  : the length of the key, counting by bytes
- *   initval : can be any 4-byte value
- * Returns a 32-bit value.  Every bit of the key affects every bit of
- * the return value.  Two keys differing by one or two bits will have
- * totally different hash values.
- *
- * The best hash table sizes are powers of 2.  There is no need to do
- * mod a prime (mod is sooo slow!).  If you need less than 32 bits,
- * use a bitmask.  For example, if you need only 10 bits, do
- *   h = (h & hashmask(10));
- * In which case, the hash table should have hashsize(10) elements.
- *
- * If you are hashing n strings (uint8_t **)k, do it like this:
- *   for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
- *
- * By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
- * code any way you wish, private, educational, or commercial.  It's free.
- *
- * Use for hash table lookup, or anything where one collision in 2^^32 is
- * acceptable.  Do NOT use for cryptographic purposes.
- */
-LTTNG_NO_SANITIZE_ADDRESS
-__attribute__((unused))
-static uint32_t hashlittle(const void *key,
-               size_t length, uint32_t initval)
-{
-       uint32_t a,b,c;
-       union {
-               const void *ptr;
-               size_t i;
-       } u;     /* needed for Mac Powerbook G4 */
-
-       /* Set up the internal state */
-       a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
-
-       u.ptr = key;
-       if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
-               const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
-
-               /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
-               while (length > 12) {
-                       a += k[0];
-                       b += k[1];
-                       c += k[2];
-                       mix(a,b,c);
-                       length -= 12;
-                       k += 3;
-               }
-
-               /*
-                * "k[2]&0xffffff" actually reads beyond the end of the string, but
-                * then masks off the part it's not allowed to read.  Because the
-                * string is aligned, the masked-off tail is in the same word as the
-                * rest of the string.  Every machine with memory protection I've seen
-                * does it on word boundaries, so is OK with this.  But VALGRIND will
-                * still catch it and complain.  The masking trick does make the hash
-                * noticably faster for short strings (like English words).
-                */
-#ifndef VALGRIND
-
-               switch (length) {
-               case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
-               case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
-               case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
-               case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
-               case 8 : b+=k[1]; a+=k[0]; break;
-               case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
-               case 6 : b+=k[1]&0xffff; a+=k[0]; break;
-               case 5 : b+=k[1]&0xff; a+=k[0]; break;
-               case 4 : a+=k[0]; break;
-               case 3 : a+=k[0]&0xffffff; break;
-               case 2 : a+=k[0]&0xffff; break;
-               case 1 : a+=k[0]&0xff; break;
-               case 0 : return c;              /* zero length strings require no mixing */
-               }
-#else /* make valgrind happy */
-               const uint8_t *k8;
-
-               k8 = (const uint8_t *)k;
-               switch (length) {
-               case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
-               case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */
-               case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */
-               case 9 : c+=k8[8];                   /* fall through */
-               case 8 : b+=k[1]; a+=k[0]; break;
-               case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */
-               case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */
-               case 5 : b+=k8[4];                   /* fall through */
-               case 4 : a+=k[0]; break;
-               case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */
-               case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */
-               case 1 : a+=k8[0]; break;
-               case 0 : return c;
-               }
-#endif /* !valgrind */
-       } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
-               const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
-               const uint8_t *k8;
-
-               /*--------------- all but last block: aligned reads and different mixing */
-               while (length > 12) {
-                       a += k[0] + (((uint32_t)k[1])<<16);
-                       b += k[2] + (((uint32_t)k[3])<<16);
-                       c += k[4] + (((uint32_t)k[5])<<16);
-                       mix(a,b,c);
-                       length -= 12;
-                       k += 6;
-               }
-
-               k8 = (const uint8_t *)k;
-               switch (length) {
-               case 12:
-                       c+=k[4]+(((uint32_t)k[5])<<16);
-                       b+=k[2]+(((uint32_t)k[3])<<16);
-                       a+=k[0]+(((uint32_t)k[1])<<16);
-                       break;
-               case 11:
-                       c+=((uint32_t)k8[10])<<16;     /* fall through */
-               case 10:
-                       c+=k[4];
-                       b+=k[2]+(((uint32_t)k[3])<<16);
-                       a+=k[0]+(((uint32_t)k[1])<<16);
-                       break;
-               case 9:
-                       c+=k8[8];                      /* fall through */
-               case 8:
-                       b+=k[2]+(((uint32_t)k[3])<<16);
-                       a+=k[0]+(((uint32_t)k[1])<<16);
-                       break;
-               case 7:
-                       b+=((uint32_t)k8[6])<<16;      /* fall through */
-               case 6:
-                       b+=k[2];
-                       a+=k[0]+(((uint32_t)k[1])<<16);
-                       break;
-               case 5:
-                       b+=k8[4];                      /* fall through */
-               case 4:
-                       a+=k[0]+(((uint32_t)k[1])<<16);
-                       break;
-               case 3:
-                       a+=((uint32_t)k8[2])<<16;      /* fall through */
-               case 2:
-                       a+=k[0];
-                       break;
-               case 1:
-                       a+=k8[0];
-                       break;
-               case 0:
-                       return c;   /* zero length requires no mixing */
-               }
-
-       } else {    /* need to read the key one byte at a time */
-               const uint8_t *k = (const uint8_t *)key;
-
-               while (length > 12) {
-                       a += k[0];
-                       a += ((uint32_t)k[1])<<8;
-                       a += ((uint32_t)k[2])<<16;
-                       a += ((uint32_t)k[3])<<24;
-                       b += k[4];
-                       b += ((uint32_t)k[5])<<8;
-                       b += ((uint32_t)k[6])<<16;
-                       b += ((uint32_t)k[7])<<24;
-                       c += k[8];
-                       c += ((uint32_t)k[9])<<8;
-                       c += ((uint32_t)k[10])<<16;
-                       c += ((uint32_t)k[11])<<24;
-                       mix(a,b,c);
-                       length -= 12;
-                       k += 12;
-               }
-
-               switch(length) {                  /* all the case statements fall through */
-               case 12: c+=((uint32_t)k[11])<<24;
-               case 11: c+=((uint32_t)k[10])<<16;
-               case 10: c+=((uint32_t)k[9])<<8;
-               case 9: c+=k[8];
-               case 8: b+=((uint32_t)k[7])<<24;
-               case 7: b+=((uint32_t)k[6])<<16;
-               case 6: b+=((uint32_t)k[5])<<8;
-               case 5: b+=k[4];
-               case 4: a+=((uint32_t)k[3])<<24;
-               case 3: a+=((uint32_t)k[2])<<16;
-               case 2: a+=((uint32_t)k[1])<<8;
-               case 1:
-                       a+=k[0];
-                       break;
-               case 0:
-                       return c;
-               }
-       }
-
-       final(a,b,c);
-       return c;
-}
-
-unsigned long hash_key_u64(const void *_key, unsigned long seed)
-{
-       union {
-               uint64_t v64;
-               uint32_t v32[2];
-       } v;
-       union {
-               uint64_t v64;
-               uint32_t v32[2];
-       } key;
-
-       v.v64 = (uint64_t) seed;
-       key.v64 = *(const uint64_t *) _key;
-       hashword2(key.v32, 2, &v.v32[0], &v.v32[1]);
-       return v.v64;
-}
-
-#if (CAA_BITS_PER_LONG == 64)
-/*
- * Hash function for number value.
- * Pass the value itself as the key, not its address.
- */
-unsigned long hash_key_ulong(const void *_key, unsigned long seed)
-{
-       uint64_t __key = (uint64_t) _key;
-       return (unsigned long) hash_key_u64(&__key, seed);
-}
-#else
-/*
- * Hash function for number value.
- * Pass the value itself as the key, not its address.
- */
-unsigned long hash_key_ulong(const void *_key, unsigned long seed)
-{
-       uint32_t key = (uint32_t) _key;
-
-       return hashword(&key, 1, seed);
-}
-#endif /* CAA_BITS_PER_LONG */
-
-/*
- * Hash function for string.
- */
-unsigned long hash_key_str(const void *key, unsigned long seed)
-{
-       return hashlittle(key, strlen((const char *) key), seed);
-}
-
-/*
- * Hash function for two uint64_t.
- */
-unsigned long hash_key_two_u64(const void *key, unsigned long seed)
-{
-       const struct lttng_ht_two_u64 *k =
-               (const struct lttng_ht_two_u64 *) key;
-
-       return hash_key_u64(&k->key1, seed) ^ hash_key_u64(&k->key2, seed);
-}
-
-/*
- * Hash function compare for number value.
- */
-int hash_match_key_ulong(const void *key1, const void *key2)
-{
-       if (key1 == key2) {
-               return 1;
-       }
-
-       return 0;
-}
-
-/*
- * Hash function compare for number value.
- */
-int hash_match_key_u64(const void *key1, const void *key2)
-{
-       if (*(const uint64_t *) key1 == *(const uint64_t *) key2) {
-               return 1;
-       }
-
-       return 0;
-}
-
-/*
- * Hash compare function for string.
- */
-int hash_match_key_str(const void *key1, const void *key2)
-{
-       if (strcmp(key1, key2) == 0) {
-               return 1;
-       }
-
-       return 0;
-}
-
-/*
- * Hash function compare two uint64_t.
- */
-int hash_match_key_two_u64(const void *key1, const void *key2)
-{
-       const struct lttng_ht_two_u64 *k1 =
-               (const struct lttng_ht_two_u64 *) key1;
-       const struct lttng_ht_two_u64 *k2 =
-               (const struct lttng_ht_two_u64 *) key2;
-
-       if (hash_match_key_u64(&k1->key1, &k2->key1) &&
-                       hash_match_key_u64(&k1->key2, &k2->key2)) {
-               return 1;
-       }
-
-       return 0;
-}
diff --git a/src/common/hashtable/utils.cpp b/src/common/hashtable/utils.cpp
new file mode 100644 (file)
index 0000000..3bc2b5e
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2006 Bob Jenkins
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+/*
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() are
+ * externally useful functions.  Routines to test the hash are included if
+ * SELF_TEST is defined.  You can use this free for any purpose.  It's in the
+ * public domain.  It has no warranty.
+ *
+ * You probably want to use hashlittle().  hashlittle() and hashbig() hash byte
+ * arrays.  hashlittle() is is faster than hashbig() on little-endian machines.
+ * Intel and AMD are little-endian machines.  On second thought, you probably
+ * want hashlittle2(), which is identical to hashlittle() except it returns two
+ * 32-bit hashes for the price of one.  You could implement hashbig2() if you
+ * wanted but I haven't bothered here.
+ *
+ * If you want to find a hash of, say, exactly 7 integers, do
+ *   a = i1;  b = i2;  c = i3;
+ *   mix(a,b,c);
+ *   a += i4; b += i5; c += i6;
+ *   mix(a,b,c);
+ *   a += i7;
+ *   final(a,b,c);
+ * then use c as the hash value.  If you have a variable length array of
+ * 4-byte integers to hash, use hashword().  If you have a byte array (like
+ * a character string), use hashlittle().  If you have several byte arrays, or
+ * a mix of things, see the comments above hashlittle().
+ *
+ * Why is this so big?  I read 12 bytes at a time into 3 4-byte integers, then
+ * mix those integers.  This is fast (you can do a lot more thorough mixing
+ * with 12*3 instructions on 3 integers than you can with 3 instructions on 1
+ * byte), but shoehorning those bytes into integers efficiently is messy.
+ */
+
+#define _LGPL_SOURCE
+#include <stdint.h>     /* defines uint32_t etc */
+#include <stdio.h>      /* defines printf for tests */
+#include <string.h>
+#include <sys/param.h>  /* attempt to define endianness */
+#include <time.h>       /* defines time_t for timings in the test */
+#include <urcu/compiler.h>
+
+#include "utils.h"
+#include <common/compat/endian.h>    /* attempt to define endianness */
+#include <common/common.h>
+#include <common/hashtable/hashtable.h>
+
+/*
+ * My best guess at if you are big-endian or little-endian.  This may
+ * need adjustment.
+ */
+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
+     __BYTE_ORDER == __LITTLE_ENDIAN) || \
+    (defined(i386) || defined(__i386__) || defined(__i486__) || \
+     defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
+       __BYTE_ORDER == __BIG_ENDIAN) || \
+      (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#else
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 0
+#endif
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+ * mix -- mix 3 32-bit values reversibly.
+ *
+ * This is reversible, so any information in (a,b,c) before mix() is
+ * still in (a,b,c) after mix().
+ *
+ * If four pairs of (a,b,c) inputs are run through mix(), or through
+ * mix() in reverse, there are at least 32 bits of the output that
+ * are sometimes the same for one pair and different for another pair.
+ * This was tested for:
+ * * pairs that differed by one bit, by two bits, in any combination
+ *   of top bits of (a,b,c), or in any combination of bottom bits of
+ *   (a,b,c).
+ * * "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+ *   the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ *   is commonly produced by subtraction) look like a single 1-bit
+ *   difference.
+ * * the base values were pseudorandom, all zero but one bit set, or
+ *   all zero plus a counter that starts at zero.
+ *
+ * Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+ * satisfy this are
+ *     4  6  8 16 19  4
+ *     9 15  3 18 27 15
+ *    14  9  3  7 17  3
+ * Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+ * for "differ" defined as + with a one-bit base and a two-bit delta.  I
+ * used http://burtleburtle.net/bob/hash/avalanche.html to choose
+ * the operations, constants, and arrangements of the variables.
+ *
+ * This does not achieve avalanche.  There are input bits of (a,b,c)
+ * that fail to affect some output bits of (a,b,c), especially of a.  The
+ * most thoroughly mixed value is c, but it doesn't really even achieve
+ * avalanche in c.
+ *
+ * This allows some parallelism.  Read-after-writes are good at doubling
+ * the number of bits affected, so the goal of mixing pulls in the opposite
+ * direction as the goal of parallelism.  I did what I could.  Rotates
+ * seem to cost as much as shifts on every machine I could lay my hands
+ * on, and rotates are much kinder to the top and bottom bits, so I used
+ * rotates.
+ */
+#define mix(a,b,c) \
+{ \
+  a -= c;  a ^= rot(c, 4);  c += b; \
+  b -= a;  b ^= rot(a, 6);  a += c; \
+  c -= b;  c ^= rot(b, 8);  b += a; \
+  a -= c;  a ^= rot(c,16);  c += b; \
+  b -= a;  b ^= rot(a,19);  a += c; \
+  c -= b;  c ^= rot(b, 4);  b += a; \
+}
+
+/*
+ * final -- final mixing of 3 32-bit values (a,b,c) into c
+ *
+ * Pairs of (a,b,c) values differing in only a few bits will usually
+ * produce values of c that look totally different.  This was tested for
+ * * pairs that differed by one bit, by two bits, in any combination
+ *   of top bits of (a,b,c), or in any combination of bottom bits of
+ *   (a,b,c).
+ * * "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+ *   the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ *   is commonly produced by subtraction) look like a single 1-bit
+ *   difference.
+ * * the base values were pseudorandom, all zero but one bit set, or
+ *   all zero plus a counter that starts at zero.
+ *
+ * These constants passed:
+ *  14 11 25 16 4 14 24
+ *  12 14 25 16 4 14 24
+ * and these came close:
+ *   4  8 15 26 3 22 24
+ *  10  8 15 26 3 22 24
+ *  11  8 15 26 3 22 24
+ */
+#define final(a,b,c) \
+{ \
+  c ^= b; c -= rot(b,14); \
+  a ^= c; a -= rot(c,11); \
+  b ^= a; b -= rot(a,25); \
+  c ^= b; c -= rot(b,16); \
+  a ^= c; a -= rot(c,4);  \
+  b ^= a; b -= rot(a,14); \
+  c ^= b; c -= rot(b,24); \
+}
+
+/*
+ * k - the key, an array of uint32_t values
+ * length - the length of the key, in uint32_ts
+ * initval - the previous hash, or an arbitrary value
+ */
+static uint32_t __attribute__((unused)) hashword(const uint32_t *k,
+               size_t length, uint32_t initval)
+{
+       uint32_t a, b, c;
+
+       /* Set up the internal state */
+       a = b = c = 0xdeadbeef + (((uint32_t) length) << 2) + initval;
+
+       /*----------------------------------------- handle most of the key */
+       while (length > 3) {
+               a += k[0];
+               b += k[1];
+               c += k[2];
+               mix(a, b, c);
+               length -= 3;
+               k += 3;
+       }
+
+       /*----------------------------------- handle the last 3 uint32_t's */
+       switch (length) {       /* all the case statements fall through */
+       case 3: c += k[2];
+       case 2: b += k[1];
+       case 1: a += k[0];
+               final(a, b, c);
+       case 0:                 /* case 0: nothing left to add */
+               break;
+       }
+       /*---------------------------------------------- report the result */
+       return c;
+}
+
+
+/*
+ * hashword2() -- same as hashword(), but take two seeds and return two 32-bit
+ * values.  pc and pb must both be nonnull, and *pc and *pb must both be
+ * initialized with seeds.  If you pass in (*pb)==0, the output (*pc) will be
+ * the same as the return value from hashword().
+ */
+static void __attribute__((unused)) hashword2(const uint32_t *k, size_t length,
+               uint32_t *pc, uint32_t *pb)
+{
+       uint32_t a, b, c;
+
+       /* Set up the internal state */
+       a = b = c = 0xdeadbeef + ((uint32_t) (length << 2)) + *pc;
+       c += *pb;
+
+       while (length > 3) {
+               a += k[0];
+               b += k[1];
+               c += k[2];
+               mix(a, b, c);
+               length -= 3;
+               k += 3;
+       }
+
+       switch (length) {
+       case 3 :
+               c += k[2];
+       case 2 :
+               b += k[1];
+       case 1 :
+               a += k[0];
+               final(a, b, c);
+       case 0:     /* case 0: nothing left to add */
+               break;
+       }
+
+       *pc = c;
+       *pb = b;
+}
+
+/*
+ * hashlittle() -- hash a variable-length key into a 32-bit value
+ *   k       : the key (the unaligned variable-length array of bytes)
+ *   length  : the length of the key, counting by bytes
+ *   initval : can be any 4-byte value
+ * Returns a 32-bit value.  Every bit of the key affects every bit of
+ * the return value.  Two keys differing by one or two bits will have
+ * totally different hash values.
+ *
+ * The best hash table sizes are powers of 2.  There is no need to do
+ * mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+ * use a bitmask.  For example, if you need only 10 bits, do
+ *   h = (h & hashmask(10));
+ * In which case, the hash table should have hashsize(10) elements.
+ *
+ * If you are hashing n strings (uint8_t **)k, do it like this:
+ *   for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+ *
+ * By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
+ * code any way you wish, private, educational, or commercial.  It's free.
+ *
+ * Use for hash table lookup, or anything where one collision in 2^^32 is
+ * acceptable.  Do NOT use for cryptographic purposes.
+ */
+LTTNG_NO_SANITIZE_ADDRESS
+__attribute__((unused))
+static uint32_t hashlittle(const void *key,
+               size_t length, uint32_t initval)
+{
+       uint32_t a,b,c;
+       union {
+               const void *ptr;
+               size_t i;
+       } u;     /* needed for Mac Powerbook G4 */
+
+       /* Set up the internal state */
+       a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+       u.ptr = key;
+       if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+               const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+
+               /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+               while (length > 12) {
+                       a += k[0];
+                       b += k[1];
+                       c += k[2];
+                       mix(a,b,c);
+                       length -= 12;
+                       k += 3;
+               }
+
+               /*
+                * "k[2]&0xffffff" actually reads beyond the end of the string, but
+                * then masks off the part it's not allowed to read.  Because the
+                * string is aligned, the masked-off tail is in the same word as the
+                * rest of the string.  Every machine with memory protection I've seen
+                * does it on word boundaries, so is OK with this.  But VALGRIND will
+                * still catch it and complain.  The masking trick does make the hash
+                * noticably faster for short strings (like English words).
+                */
+#ifndef VALGRIND
+
+               switch (length) {
+               case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+               case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+               case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+               case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+               case 8 : b+=k[1]; a+=k[0]; break;
+               case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+               case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+               case 5 : b+=k[1]&0xff; a+=k[0]; break;
+               case 4 : a+=k[0]; break;
+               case 3 : a+=k[0]&0xffffff; break;
+               case 2 : a+=k[0]&0xffff; break;
+               case 1 : a+=k[0]&0xff; break;
+               case 0 : return c;              /* zero length strings require no mixing */
+               }
+#else /* make valgrind happy */
+               const uint8_t *k8;
+
+               k8 = (const uint8_t *)k;
+               switch (length) {
+               case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+               case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */
+               case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */
+               case 9 : c+=k8[8];                   /* fall through */
+               case 8 : b+=k[1]; a+=k[0]; break;
+               case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */
+               case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */
+               case 5 : b+=k8[4];                   /* fall through */
+               case 4 : a+=k[0]; break;
+               case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */
+               case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */
+               case 1 : a+=k8[0]; break;
+               case 0 : return c;
+               }
+#endif /* !valgrind */
+       } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+               const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
+               const uint8_t *k8;
+
+               /*--------------- all but last block: aligned reads and different mixing */
+               while (length > 12) {
+                       a += k[0] + (((uint32_t)k[1])<<16);
+                       b += k[2] + (((uint32_t)k[3])<<16);
+                       c += k[4] + (((uint32_t)k[5])<<16);
+                       mix(a,b,c);
+                       length -= 12;
+                       k += 6;
+               }
+
+               k8 = (const uint8_t *)k;
+               switch (length) {
+               case 12:
+                       c+=k[4]+(((uint32_t)k[5])<<16);
+                       b+=k[2]+(((uint32_t)k[3])<<16);
+                       a+=k[0]+(((uint32_t)k[1])<<16);
+                       break;
+               case 11:
+                       c+=((uint32_t)k8[10])<<16;     /* fall through */
+               case 10:
+                       c+=k[4];
+                       b+=k[2]+(((uint32_t)k[3])<<16);
+                       a+=k[0]+(((uint32_t)k[1])<<16);
+                       break;
+               case 9:
+                       c+=k8[8];                      /* fall through */
+               case 8:
+                       b+=k[2]+(((uint32_t)k[3])<<16);
+                       a+=k[0]+(((uint32_t)k[1])<<16);
+                       break;
+               case 7:
+                       b+=((uint32_t)k8[6])<<16;      /* fall through */
+               case 6:
+                       b+=k[2];
+                       a+=k[0]+(((uint32_t)k[1])<<16);
+                       break;
+               case 5:
+                       b+=k8[4];                      /* fall through */
+               case 4:
+                       a+=k[0]+(((uint32_t)k[1])<<16);
+                       break;
+               case 3:
+                       a+=((uint32_t)k8[2])<<16;      /* fall through */
+               case 2:
+                       a+=k[0];
+                       break;
+               case 1:
+                       a+=k8[0];
+                       break;
+               case 0:
+                       return c;   /* zero length requires no mixing */
+               }
+
+       } else {    /* need to read the key one byte at a time */
+               const uint8_t *k = (const uint8_t *)key;
+
+               while (length > 12) {
+                       a += k[0];
+                       a += ((uint32_t)k[1])<<8;
+                       a += ((uint32_t)k[2])<<16;
+                       a += ((uint32_t)k[3])<<24;
+                       b += k[4];
+                       b += ((uint32_t)k[5])<<8;
+                       b += ((uint32_t)k[6])<<16;
+                       b += ((uint32_t)k[7])<<24;
+                       c += k[8];
+                       c += ((uint32_t)k[9])<<8;
+                       c += ((uint32_t)k[10])<<16;
+                       c += ((uint32_t)k[11])<<24;
+                       mix(a,b,c);
+                       length -= 12;
+                       k += 12;
+               }
+
+               switch(length) {                  /* all the case statements fall through */
+               case 12: c+=((uint32_t)k[11])<<24;
+               case 11: c+=((uint32_t)k[10])<<16;
+               case 10: c+=((uint32_t)k[9])<<8;
+               case 9: c+=k[8];
+               case 8: b+=((uint32_t)k[7])<<24;
+               case 7: b+=((uint32_t)k[6])<<16;
+               case 6: b+=((uint32_t)k[5])<<8;
+               case 5: b+=k[4];
+               case 4: a+=((uint32_t)k[3])<<24;
+               case 3: a+=((uint32_t)k[2])<<16;
+               case 2: a+=((uint32_t)k[1])<<8;
+               case 1:
+                       a+=k[0];
+                       break;
+               case 0:
+                       return c;
+               }
+       }
+
+       final(a,b,c);
+       return c;
+}
+
+unsigned long hash_key_u64(const void *_key, unsigned long seed)
+{
+       union {
+               uint64_t v64;
+               uint32_t v32[2];
+       } v;
+       union {
+               uint64_t v64;
+               uint32_t v32[2];
+       } key;
+
+       v.v64 = (uint64_t) seed;
+       key.v64 = *(const uint64_t *) _key;
+       hashword2(key.v32, 2, &v.v32[0], &v.v32[1]);
+       return v.v64;
+}
+
+#if (CAA_BITS_PER_LONG == 64)
+/*
+ * Hash function for number value.
+ * Pass the value itself as the key, not its address.
+ */
+unsigned long hash_key_ulong(const void *_key, unsigned long seed)
+{
+       uint64_t __key = (uint64_t) _key;
+       return (unsigned long) hash_key_u64(&__key, seed);
+}
+#else
+/*
+ * Hash function for number value.
+ * Pass the value itself as the key, not its address.
+ */
+unsigned long hash_key_ulong(const void *_key, unsigned long seed)
+{
+       uint32_t key = (uint32_t) _key;
+
+       return hashword(&key, 1, seed);
+}
+#endif /* CAA_BITS_PER_LONG */
+
+/*
+ * Hash function for string.
+ */
+unsigned long hash_key_str(const void *key, unsigned long seed)
+{
+       return hashlittle(key, strlen((const char *) key), seed);
+}
+
+/*
+ * Hash function for two uint64_t.
+ */
+unsigned long hash_key_two_u64(const void *key, unsigned long seed)
+{
+       const struct lttng_ht_two_u64 *k =
+               (const struct lttng_ht_two_u64 *) key;
+
+       return hash_key_u64(&k->key1, seed) ^ hash_key_u64(&k->key2, seed);
+}
+
+/*
+ * Hash function compare for number value.
+ */
+int hash_match_key_ulong(const void *key1, const void *key2)
+{
+       if (key1 == key2) {
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Hash function compare for number value.
+ */
+int hash_match_key_u64(const void *key1, const void *key2)
+{
+       if (*(const uint64_t *) key1 == *(const uint64_t *) key2) {
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Hash compare function for string.
+ */
+int hash_match_key_str(const void *key1, const void *key2)
+{
+       if (strcmp((const char *) key1, (const char *) key2) == 0) {
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Hash function compare two uint64_t.
+ */
+int hash_match_key_two_u64(const void *key1, const void *key2)
+{
+       const struct lttng_ht_two_u64 *k1 =
+               (const struct lttng_ht_two_u64 *) key1;
+       const struct lttng_ht_two_u64 *k2 =
+               (const struct lttng_ht_two_u64 *) key2;
+
+       if (hash_match_key_u64(&k1->key1, &k2->key1) &&
+                       hash_match_key_u64(&k1->key2, &k2->key2)) {
+               return 1;
+       }
+
+       return 0;
+}
This page took 0.047318 seconds and 4 git commands to generate.