diff --git a/qdf/inc/qdf_hashtable.h b/qdf/inc/qdf_hashtable.h new file mode 100644 index 000000000000..f01b5ec2f197 --- /dev/null +++ b/qdf/inc/qdf_hashtable.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: qdf_hashtable.h - Public APIs for a hashtable data structure + */ + +#ifndef __QDF_HASHTABLE_H +#define __QDF_HASHTABLE_H + +#include "i_qdf_hashtable.h" + +/** + * struct qdf_ht - opaque hashtable data type + */ +#define qdf_ht __qdf_ht + +/** + * struct qdf_ht_entry - opaque hashtable entry for membership in a qdf_ht + */ +#define qdf_ht_entry __qdf_ht_entry + +/** + * qdf_ht_declare() - declare a new qdf_ht + * @name: variable name of the hashtable to declare + * @bits: number of hash bits to use; buckets=2^bits + */ +#define qdf_ht_declare(name, bits) __qdf_ht_declare(name, bits) + +/** + * qdf_ht_init() - initialize a qdf_ht instance + * @table: a non-pointer qdf_ht instance to initialize + * + * Return: none + */ +#define qdf_ht_init(table) __qdf_ht_init(table) + +/** + * qdf_ht_deinit() - de-initialize a qdf_ht instance + * @table: a non-pointer qdf_ht instance to de-initialize + * + * Return: none + */ +#define qdf_ht_deinit(table) __qdf_ht_deinit(table) + +/** + * qdf_ht_empty() - check if a qdf_ht has any entries + * @table: a non-pointer qdf_ht instance to check + * + * Return: true if the hashtable is empty + */ +#define qdf_ht_empty(table) __qdf_ht_empty(table) + +/** + * qdf_ht_add() - add an entry to a qdf_ht instance + * @table: a non-pointer qdf_ht instance to add an entry to + * @entry: pinter to a qdf_ht_entry instance to add to @table + * @key: the key to use for entry insertion and lookup + * + * Return: none + */ +#define qdf_ht_add(table, entry, key) __qdf_ht_add(table, entry, key) + +/** + * qdf_ht_remove() - remove and entry from a qdf_ht instance + * @entry: pointer to a qdf_ht_entry instance to remove + * + * Return: none + */ +#define qdf_ht_remove(entry) __qdf_ht_remove(entry) + +/** + * qdf_ht_for_each() - iterate all entries in @table + * @table: a non-pointer qdf_ht instance to iterate + * @i: int type cursor populated with the bucket index + * @cursor: container struct pointer populated with each iteration + * @entry_field: name of the entry field in the entry container struct + */ +#define qdf_ht_for_each(table, i, cursor, entry_field) \ + __qdf_ht_for_each(table, i, cursor, entry_field) + +/** + * qdf_ht_for_each_in_bucket() - iterate entries in the bucket for @key + * @table: a non-pointer qdf_ht instance to iterate + * @cursor: container struct pointer populated with each iteration + * @entry_field: name of the entry field in the entry container struct + * @key: key used to lookup the hashtable bucket + */ +#define qdf_ht_for_each_in_bucket(table, cursor, entry_field, key) \ + __qdf_ht_for_each_in_bucket(table, cursor, entry_field, key) + +/** + * qdf_ht_for_each_match() - iterates through each entry matching @key + * @table: a non-pointer qdf_ht instance to iterate + * @cursor: container struct pointer populated with each iteration + * @entry_field: name of the entry field in the entry container struct + * @key: key used to lookup the entries + * @key_field: name of the key field in the entry container struct + */ +#define qdf_ht_for_each_match(table, cursor, entry_field, key, key_field) \ + __qdf_ht_for_each_match(table, cursor, entry_field, key, key_field) + +/** + * qdf_ht_get() - get the first entry with a key matching @key + * @table: a non-pointer qdf_ht instance to look in + * @cursor: container struct pointer populated with each iteration + * @entry_field: name of the entry field in the entry container struct + * @key: key used to lookup the entry + * @key_field: name of the key field in the entry container struct + */ +#define qdf_ht_get(table, cursor, entry_field, key, key_field) \ + __qdf_ht_get(table, cursor, entry_field, key, key_field) + +#endif /* __QDF_HASHTABLE_H */ diff --git a/qdf/linux/src/i_qdf_hashtable.h b/qdf/linux/src/i_qdf_hashtable.h new file mode 100644 index 000000000000..f1806cbf1d76 --- /dev/null +++ b/qdf/linux/src/i_qdf_hashtable.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __I_QDF_HASHTABLE_H +#define __I_QDF_HASHTABLE_H + +#include "linux/hashtable.h" + +#define __qdf_ht hlist_head +#define __qdf_ht_entry hlist_node +#define __qdf_ht_declare(name, bits) DECLARE_HASHTABLE(name, bits) +#define __qdf_ht_init(table) hash_init(table) +#define __qdf_ht_deinit(table) do { } while (false) +#define __qdf_ht_empty(table) hash_empty(table) +#define __qdf_ht_add(table, entry, key) hash_add(table, entry, key) +#define __qdf_ht_remove(entry) hash_del(entry) + +#define __qdf_ht_for_each(table, i, cursor, entry_field) \ + hash_for_each(table, i, cursor, entry_field) + +#define __qdf_ht_for_each_in_bucket(table, cursor, entry_field, key) \ + hash_for_each_possible(table, cursor, entry_field, key) + +#define __qdf_ht_for_each_match(table, cursor, entry_field, key, key_field) \ + hash_for_each_possible(table, (cursor), entry_field, (key)) \ + if ((cursor)->key_field == (key)) + +#define __qdf_ht_get(table, cursor, entry_field, key, key_field) \ +do { \ + cursor = NULL; \ + __qdf_ht_for_each_match(table, cursor, entry_field, key, key_field) \ + break; \ +} while (false) + +#endif /* __I_QDF_HASHTABLE_H */ diff --git a/qdf/test/qdf_hashtable_test.c b/qdf/test/qdf_hashtable_test.c new file mode 100644 index 000000000000..ce4a15989bd8 --- /dev/null +++ b/qdf/test/qdf_hashtable_test.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_hashtable.h" +#include "qdf_hashtable_test.h" +#include "qdf_trace.h" + +struct qdf_ht_test_item { + struct qdf_ht_entry entry; + uintptr_t key; +}; + +static uint32_t qdf_ht_test_single(void) +{ + const int bits = 4; /* 16 buckets */ + struct qdf_ht_test_item item = { .key = (uintptr_t)&bits }; + struct qdf_ht_test_item *cursor; + int i, count; + + qdf_ht_declare(ht, bits); + + qdf_ht_init(ht); + qdf_ht_add(ht, &item.entry, item.key); + + qdf_ht_get(ht, cursor, entry, item.key, key); + QDF_BUG(cursor); + QDF_BUG(cursor->key == item.key); + + count = 0; + qdf_ht_for_each(ht, i, cursor, entry) { + QDF_BUG(cursor->key == item.key); + count++; + } + QDF_BUG(count == 1); + + count = 0; + qdf_ht_for_each_in_bucket(ht, cursor, entry, item.key) { + QDF_BUG(cursor->key == item.key); + count++; + } + QDF_BUG(count == 1); + + count = 0; + qdf_ht_for_each_match(ht, cursor, entry, item.key, key) { + QDF_BUG(cursor->key == item.key); + count++; + } + QDF_BUG(count == 1); + + qdf_ht_remove(&item.entry); + + QDF_BUG(qdf_ht_empty(ht)); + + qdf_ht_deinit(ht); + + return 0; +} + +uint32_t qdf_ht_unit_test(void) +{ + uint32_t errors = 0; + + errors += qdf_ht_test_single(); + + return errors; +} + diff --git a/qdf/test/qdf_hashtable_test.h b/qdf/test/qdf_hashtable_test.h new file mode 100644 index 000000000000..90dfc9ea0c78 --- /dev/null +++ b/qdf/test/qdf_hashtable_test.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __QDF_HASHTABLE_TEST +#define __QDF_HASHTABLE_TEST + +#ifdef WLAN_HASHTABLE_TEST +/** + * qdf_ht_unit_test() - run the qdf hashtable unit test suite + * + * Return: number of failed test cases + */ +uint32_t qdf_ht_unit_test(void); +#else +static inline uint32_t qdf_ht_unit_test(void) +{ + return 0; +} +#endif /* WLAN_HASHTABLE_TEST */ + +#endif /* __QDF_HASHTABLE_TEST */ +