On 05.11.15 13:20, huanggaoyang wrote:
Signed-off-by: huanggaoyang <huanggaoya...@huawei.com>
---
helper/hashtable.c | 346 ++++++++++++++++++++++++++++++++++++++++++++
helper/odph_hashtable.h | 42 ++++++
helper/odph_list_internal.h | 85 +++++++++++
3 files changed, 473 insertions(+)
create mode 100644 helper/hashtable.c
create mode 100644 helper/odph_hashtable.h
create mode 100644 helper/odph_list_internal.h
diff --git a/helper/hashtable.c b/helper/hashtable.c
new file mode 100644
index 0000000..0b29814
--- /dev/null
+++ b/helper/hashtable.c
@@ -0,0 +1,346 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "odph_hashtable.h"
+#include "odph_list_internal.h"
+#include "odph_debug.h"
+#include <odp.h>
+
+#define ODPH_SUCCESS 0
+#define ODPH_FAIL -1
+
+/** @magic word, write to the first byte of the memory block
+ * to indicate this block is used by a hash table structure
+ */
+#define ODPH_HASH_TABLE_MAGIC_WORD 0xABABBABA
+
+/** @support 64k buckets. Bucket is a list that composed of
+ * elements with the same HASH-value but different keys
+ */
+#define ODPH_MAX_BUCKET_NUM 0x10000
+
+/** @inner element structure of hash table
+ * To resolve the hash confict:
+ * we put the elements with different keys but a same HASH-value
+ * into a list
+ */
+typedef struct odph_hash_node {
+ /** list structure,for list opt */
+ odph_list_object list_node;
+ /** Flexible Array,memory will be alloced when table has been created
+ * Its length is key_size + value_size,
+ * suppose key_size = m; value_size = n;
+ * its structure is like:
+ * k_byte1 k_byte2...k_byten v_byte1...v_bytem
+ */
+ char content[0];
+} odph_hash_node;
+
+typedef struct {
+ uint32_t magicword; /**< for check */
+ uint32_t key_size; /**< input param when create,in Bytes */
+ uint32_t value_size; /**< input param when create,in Bytes */
+ uint32_t init_cap; /**< input param when create,in Bytes */
+ /** multi-process support,every list has one rw lock */
+ odp_rwlock_t *lock_pool;
+ /** table bucket pool,every hash value has one list head */
+ odph_list_head *list_head_pool;
+ /** number of the list head in list_head_pool */
+ uint32_t head_num;
+ /** table element pool */
+ odph_hash_node *hash_node_pool;
+ /** number of element in the hash_node_pool */
+ uint32_t hash_node_num;
+ char rsv[7]; /**< Reserved,for alignment */
+ char name[ODPH_TABLE_NAME_LEN]; /**< table name */
+} odph_hash_table_imp;
+
+odph_table_t odph_hash_table_create(const char *name, uint32_t capacity,
+ uint32_t key_size,
+ uint32_t value_size)
+{
+ int idx, i;
+ uint32_t node_num;
+ odph_hash_table_imp *tbl;
+ odp_shm_t shmem;
+ uint32_t node_mem;
+
+ if (strlen(name) >= ODPH_TABLE_NAME_LEN || capacity < 1 ||
+ capacity >= 0x1000 || key_size == 0 || value_size == 0) {
+ ODPH_DBG("create para input error!\n");
+ return NULL;
+ }
+ tbl = (odph_hash_table_imp *)odp_shm_addr(odp_shm_lookup(name));
+ if (tbl != NULL) {
+ ODPH_DBG("name already exist\n");
+ return NULL;
+ }
+ shmem = odp_shm_reserve(name, capacity << 20, 64, ODP_SHM_SW_ONLY);
+ if (shmem == ODP_SHM_INVALID) {
+ ODPH_DBG("shm reserve fail\n");
+ return NULL;
+ }
+ tbl = (odph_hash_table_imp *)odp_shm_addr(shmem);
+
+ /* clean this block of memory */
+ memset(tbl, 0, capacity << 20);
+
+ tbl->init_cap = capacity << 20;
+ strncpy(tbl->name, name, ODPH_TABLE_NAME_LEN);
+ tbl->key_size = key_size;
+ tbl->value_size = value_size;
+
+ /* header of this mem block is the table control struct,
+ * then the lock pool, then the list header pool
+ * the last part is the element node pool
+ */
+
+ tbl->lock_pool = (odp_rwlock_t *)((char *)tbl
+ + sizeof(odph_hash_table_imp));
+ tbl->list_head_pool = (odph_list_head *)((char *)tbl->lock_pool
+ + ODPH_MAX_BUCKET_NUM * sizeof(odp_rwlock_t));
+
+ node_mem = tbl->init_cap - sizeof(odph_hash_table_imp)
+ - ODPH_MAX_BUCKET_NUM * sizeof(odph_list_head)
+ - ODPH_MAX_BUCKET_NUM * sizeof(odp_rwlock_t);
+
+ node_num = node_mem / (sizeof(odph_hash_node) + key_size + value_size);
+ tbl->hash_node_num = node_num;
+ tbl->hash_node_pool = (odph_hash_node *)((char *)tbl->list_head_pool
+ + ODPH_MAX_BUCKET_NUM * sizeof(odph_list_head));
+
+ /* init every list head and rw lock */
+ for (i = 0; i < ODPH_MAX_BUCKET_NUM; i++) {
+ ODPH_INIT_LIST_HEAD(&tbl->list_head_pool[i]);
+ odp_rwlock_init((odp_rwlock_t *)&tbl->lock_pool[i]);
+ }
+
+ tbl->magicword = ODPH_HASH_TABLE_MAGIC_WORD;
+ return (odph_table_t)tbl;
+}
+
+int odph_hash_table_destroy(odph_table_t table)
+{
+ int ret;
+
+ if (table != NULL) {
+ odph_hash_table_imp *hash_tbl = (odph_hash_table_imp *)table;
+
+ if (hash_tbl->magicword != ODPH_HASH_TABLE_MAGIC_WORD)
+ return ODPH_FAIL;
+
+ ret = odp_shm_free(odp_shm_lookup(hash_tbl->name));
+ if (ret != 0) {
+ ODPH_DBG("free fail\n");
+ return ret;
+ }
+ /* clean head */
+ return ODPH_SUCCESS;
+ }
+ return ODPH_FAIL;
+}
+
+odph_table_t odph_hash_table_lookup(const char *name)
+{
+ int idx;
+ odph_hash_table_imp *hash_tbl;
+
+ if (name == NULL || strlen(name) >= ODPH_TABLE_NAME_LEN)
+ return NULL;
+
+ hash_tbl = (odph_hash_table_imp *)odp_shm_addr(odp_shm_lookup(name));
+ if (hash_tbl != NULL && strcmp(hash_tbl->name, name) == 0)
+ return (odph_table_t)hash_tbl;
+ return NULL;
+}
+
+/**
+ * Calculate has value by the input key and key_size
+ * This hash algorithm is the most simple one, so we choose it as an DEMO
+ * User can use any other algorithm, like CRC...
+ */
+uint16_t odp_key_hash(void *key, uint32_t key_size)
+{
+ register uint32_t hash = 0;
+ uint32_t idx = (key_size == 0 ? 1 : key_size);
+ uint32_t ch;
+
+ while (idx != 0) {
+ ch = (uint32_t)(*(char *)key);
+ hash = hash * 131 + ch;
+ idx--;
+ }
+ return (uint16_t)(hash & 0x0000FFFF);
+}
+
+/**
+ * Get an available node from pool
+ */
+odph_hash_node *odp_hashnode_take(odph_table_t table)
+{
+ odph_hash_table_imp *tbl = (odph_hash_table_imp *)table;
+ uint32_t idx;
+ odph_hash_node *node;
+
+ for (idx = 0; idx < tbl->hash_node_num; idx++) {
+ /** notice: memory of one hash_node is
+ * not only sizeof(odph_hash_node)
+ * should add the size of Flexible Array
+ */
+ node = (odph_hash_node *)((char *)tbl->hash_node_pool
+ + idx * (sizeof(odph_hash_node)
+ + tbl->key_size
+ + tbl->value_size));
+ if (node->list_node.next == NULL &&
+ node->list_node.prev == NULL) {
+ ODPH_INIT_LIST_HEAD(&node->list_node);
+ return node;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Release an node to the pool
+ */
+void odp_hashnode_give(odph_table_t table, odph_hash_node *node)
+{
+ odph_hash_table_imp *tbl = (odph_hash_table_imp *)table;
+
+ if (node == NULL)
+ return;
+
+ odph_list_del(&node->list_node);
+ memset(node, 0,
+ (sizeof(odph_hash_node) + tbl->key_size + tbl->value_size));
+}
+
+/* should make sure the input table exists and is available */
+int odph_hash_put_value(odph_table_t table, void *key, void *value)
+{
+ odph_hash_table_imp *tbl = (odph_hash_table_imp *)table;
+ uint16_t hash = 0;
+ odph_hash_node *node = NULL;
+ char *tmp = NULL;
+
+ if (table == NULL || key == NULL || value == NULL)
+ return ODPH_FAIL;
+
+ /* hash value is just the index of the list head in pool */
+ hash = odp_key_hash(key, tbl->key_size);
+
+ odp_rwlock_write_lock(&tbl->lock_pool[hash]);
+ /* First, check if the key already exist */
+ ODPH_LIST_FOR_EACH(node, &tbl->list_head_pool[hash], odph_hash_node,
+ list_node)
+ {
+ if (memcmp(node->content, key, tbl->key_size) == 0) {
+ /* copy value content to hash node*/
+ tmp = (void *)((char *)node->content + tbl->key_size);
+ memcpy(tmp, value, tbl->value_size);
+ odp_rwlock_write_unlock(&tbl->lock_pool[hash]);
+ return ODPH_SUCCESS;
+ }
+ }
+
+ /*if the key is a new one, get a new hash node form the pool */
+ node = odp_hashnode_take(table);
+ if (node == NULL) {
+ odp_rwlock_write_unlock(&tbl->lock_pool[hash]);
+ return ODPH_FAIL;
+ }
+
+ /* copy both key and value content to the hash node */
+ memcpy(node->content, key, tbl->key_size);
+ tmp = (void *)((char *)node->content + tbl->key_size);
+ memcpy(tmp, value, tbl->value_size);
+
+ /* add the node to list */
+ odph_list_add(&node->list_node, &tbl->list_head_pool[hash]);
+
+ odp_rwlock_write_unlock(&tbl->lock_pool[hash]);
+ return ODPH_SUCCESS;
+}
+
+/* should make sure the input table exists and is available */
+int odph_hash_get_value(odph_table_t table, void *key, void *buffer,
+ uint32_t buffer_size)
+{
+ odph_hash_table_imp *tbl = (odph_hash_table_imp *)table;
+ uint16_t hash = 0;
+ odph_hash_node *node;
+ char *tmp = NULL;
+
+ if (table == NULL || key == NULL || buffer == NULL ||
+ buffer_size < tbl->value_size)
+ return ODPH_FAIL;
+
+ /* hash value is just the index of the list head in pool */
+ hash = odp_key_hash(key, tbl->key_size);
+
+ odp_rwlock_read_lock(&tbl->lock_pool[hash]);
+
+ ODPH_LIST_FOR_EACH(node, &tbl->list_head_pool[hash],
+ odph_hash_node, list_node)
+ {
+ /* in case of hash conflict, compare the whole key */
+ if (memcmp(node->content, key, tbl->key_size) == 0) {
+ /* find the target */
+ tmp = (void *)((char *)node->content + tbl->key_size);
+ memcpy(buffer, tmp, tbl->value_size);
+
+ odp_rwlock_read_unlock(&tbl->lock_pool[hash]);
+
+ return ODPH_SUCCESS;
+ }
+ }
+
+ odp_rwlock_read_unlock(&tbl->lock_pool[hash]);
+
+ return ODPH_FAIL;
+}
+
+/* should make sure the input table exists and is available */
+int odph_hash_remove_value(odph_table_t table, void *key)
+{
+ odph_hash_table_imp *tbl = (odph_hash_table_imp *)table;
+ uint16_t hash = 0;
+ odph_hash_node *node;
+
+ if (table == NULL || key == NULL)
+ return ODPH_FAIL;
+
+ /* hash value is just the index of the list head in pool */
+ hash = odp_key_hash(key, tbl->key_size);
+
+ odp_rwlock_write_lock(&tbl->lock_pool[hash]);
+
+ ODPH_LIST_FOR_EACH(node, &tbl->list_head_pool[hash], odph_hash_node,
+ list_node)
+ {
+ if (memcmp(node->content, key, tbl->key_size) == 0) {
+ odp_hashnode_give(table, node);
+ odp_rwlock_write_unlock(&tbl->lock_pool[hash]);
+ return ODPH_SUCCESS;
+ }
+ }
+
+ odp_rwlock_write_unlock(&tbl->lock_pool[hash]);
+
+ return ODPH_SUCCESS;
+}
+
+odph_table_ops_t odph_hash_table_ops = {
+ odph_hash_table_create,
+ odph_hash_table_lookup,
+ odph_hash_table_destroy,
+ odph_hash_put_value,
+ odph_hash_get_value,
+ odph_hash_remove_value};
+
diff --git a/helper/odph_hashtable.h b/helper/odph_hashtable.h
new file mode 100644
index 0000000..7c20370
--- /dev/null
+++ b/helper/odph_hashtable.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP Hash Table
+ */
+
+#ifndef ODPH_HASH_TABLE_H_
+#define ODPH_HASH_TABLE_H_
+
+#include <stdint.h>
+#include <odp/plat/strong_types.h>
platform dependent inclusion
+#include <odp/helper/table.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+odph_table_t odph_hash_table_create(const char *name,
+ uint32_t capacity,
+ uint32_t key_size,
+ uint32_t value_size);
+odph_table_t odph_hash_table_lookup(const char *name);
+int odph_hash_table_destroy(odph_table_t table);
+int odph_hash_put_value(odph_table_t table, void *key, void *value);
+int odph_hash_get_value(odph_table_t table, void *key, void *buffer,
+ uint32_t buffer_size);
+int odph_hash_remove_value(odph_table_t table, void *key);
+
+extern odph_table_ops_t odph_hash_table_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/helper/odph_list_internal.h b/helper/odph_list_internal.h
new file mode 100644
index 0000000..9e532b0
--- /dev/null
+++ b/helper/odph_list_internal.h
@@ -0,0 +1,85 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP list
+ * a simple implementation of Doubly linked list
+ */
+
+#ifndef ODPH_LIST_INTER_H_
+#define ODPH_LIST_INTER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct odph_list_object {
+ struct odph_list_object *next, *prev;
+} odph_list_object;
+
+typedef odph_list_object odph_list_head;
+
+static inline void ODPH_INIT_LIST_HEAD(odph_list_object *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+static inline void __odph_list_add(odph_list_object *new,
+ odph_list_object *prev,
+ odph_list_object *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+static inline void odph_list_add(odph_list_object *new, odph_list_object *head)
+{
+ __odph_list_add(new, head, head->next);
+}
+
+static inline void odph_list_add_tail(struct odph_list_object *new,
+ odph_list_object *head)
+{
+ __odph_list_add(new, head->prev, head);
+}
+
+static inline void __odph_list_del(struct odph_list_object *prev,
+ odph_list_object *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static inline void odph_list_del(struct odph_list_object *entry)
+{
+ __odph_list_del(entry->prev, entry->next);
+ ODPH_INIT_LIST_HEAD(entry);
+}
+
+static inline int odph_list_empty(const struct odph_list_object *head)
+{
+ return head->next == head;
+}
+
+#define container_of(ptr, type, list_node) \
+ ((type *)(void *)((char *)ptr - offsetof(type, list_node)))
+
+#define ODPH_LIST_FOR_EACH(pos, list_head, type, list_node) \
+ for (pos = container_of((list_head)->next, type, list_node); \
+ &pos->list_node != (list_head); \
+ pos = container_of(pos->list_node.next, type, list_node))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--
Regards,
Ivan Khoronzhuk
_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp