diff --git a/Knot.files b/Knot.files index 71a588fae70685bdffae660699ae4c7c41040af2..102af3cf6f3d0be8e7d205050d1d38c433890355 100644 --- a/Knot.files +++ b/Knot.files @@ -81,8 +81,6 @@ src/common/print.c src/common/print.h src/common/latency.c src/common/latency.h -src/common/dynamic-array.c -src/common/dynamic-array.h src/common/skip-list.c src/common/skip-list.h src/common/tree.h @@ -181,8 +179,6 @@ src/zcompile/zcompile-error.c src/tests/unittests_main.c src/tests/common/acl_tests.c src/tests/common/acl_tests.h -src/tests/common/da_tests.c -src/tests/common/da_tests.h src/tests/common/events_tests.c src/tests/common/events_tests.h src/tests/common/skiplist_tests.c diff --git a/src/Makefile.am b/src/Makefile.am index 60c51c6517b3c3aeebe6e11782eedc9c359afb0c..fb4e6639b25bcc966d2f086d52bfa80ca74176cf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -58,8 +58,6 @@ knot_zcompile_SOURCES = \ unittests_SOURCES = \ tests/common/acl_tests.c \ tests/common/acl_tests.h \ - tests/common/da_tests.c \ - tests/common/da_tests.h \ tests/common/events_tests.c \ tests/common/events_tests.h \ tests/common/skiplist_tests.c \ @@ -229,13 +227,11 @@ libknots_la_SOURCES = \ common/base32.h \ common/print.c \ common/print.h \ - common/dynamic-array.c \ common/skip-list.c \ common/base32hex.c \ common/skip-list.h \ common/general-tree.h \ common/general-tree.c \ - common/dynamic-array.h \ common/tree.h \ common/base32hex.h \ common/evqueue.h \ diff --git a/src/common/dynamic-array.c b/src/common/dynamic-array.c deleted file mode 100644 index e948821925e57d0820b307abfd34e63a3acf7b79..0000000000000000000000000000000000000000 --- a/src/common/dynamic-array.c +++ /dev/null @@ -1,225 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <pthread.h> -#include <assert.h> -#include <stdio.h> - -#include <urcu.h> - -//#include "common.h" -#include "common/dynamic-array.h" - -#ifndef ERR_ALLOC_FAILED -#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d\n", \ - __FILE__, __LINE__) -#endif - -//#define DA_DEBUG - -#ifndef dbg_da -#ifdef DA_DEBUG -#define dbg_da(msg...) fprintf(stderr, msg) -#else -#define dbg_da(msg...) -#endif -#endif - -/*----------------------------------------------------------------------------*/ -/* Private functions */ -/*----------------------------------------------------------------------------*/ - -enum da_resize_type { - DA_LARGER, DA_SMALLER -}; - -typedef enum da_resize_type da_resize_type_t; - -/*----------------------------------------------------------------------------*/ -/*! - * \retval 1 On success. - * \retval -1 On failure. - */ -static int da_resize(da_array_t *array, da_resize_type_t type) -{ - dbg_da("da_resize(): array pointer: %p, items pointer: %p\n", array, - array->items); - - unsigned new_size = ((type == DA_LARGER) - ? (array->allocated *= 2) - : (array->allocated /= 2)); - - void *new_items = malloc(new_size * array->item_size); - if (new_items == NULL) { - ERR_ALLOC_FAILED; - return -1; - } - - dbg_da("Place for new items: %p\n", new_items); - - // copy the contents from the old array to the new - memcpy(new_items, array->items, array->count * array->item_size); - - // do RCU update - void *old_items = rcu_xchg_pointer(&array->items, new_items); - array->allocated = new_size; - - dbg_da("Old items pointer: %p\n", old_items); - - // wait for readers to finish - synchronize_rcu(); - // deallocate the old array - dbg_da("RCU synchronized, deallocating old items array at address %p." - "\n", old_items); - free(old_items); - - return 1; -} - -/*----------------------------------------------------------------------------*/ -/* Public functions */ -/*----------------------------------------------------------------------------*/ - -da_array_t *da_create(unsigned count, size_t item_size) -{ - da_array_t *a = (da_array_t *)malloc(sizeof(da_array_t)); - if (a == NULL) { - ERR_ALLOC_FAILED; - return NULL; - } - da_initialize(a, count, item_size); - return a; -} - -/*----------------------------------------------------------------------------*/ - -int da_initialize(da_array_t *array, unsigned count, size_t item_size) -{ - assert(array != NULL); - pthread_mutex_init(&array->mtx, NULL); - pthread_mutex_lock(&array->mtx); - - array->items = malloc(count * item_size); - if (array->items == NULL) { - array->allocated = 0; - array->count = 0; - ERR_ALLOC_FAILED; - pthread_mutex_unlock(&array->mtx); - return -1; - } - - array->allocated = count; - array->count = 0; - array->item_size = item_size; - memset(array->items, 0, count * item_size); - - pthread_mutex_unlock(&array->mtx); - return 0; -} - -/*----------------------------------------------------------------------------*/ - -int da_reserve(da_array_t *array, unsigned count) -{ - pthread_mutex_lock(&array->mtx); - unsigned res = 0; - - assert(array->allocated >= array->count); - if ((array->allocated - array->count) >= count) { - dbg_da("Enough place in the array, no resize needed.\n"); - res = 0; - } else { - dbg_da("Resizing array.\n"); - res = da_resize(array, DA_LARGER); - } - pthread_mutex_unlock(&array->mtx); - - return res; -} - -/*----------------------------------------------------------------------------*/ - -int da_occupy(da_array_t *array, unsigned count) -{ - pthread_mutex_lock(&array->mtx); - unsigned res = 0; - assert(array->allocated >= array->count); - - if ((array->allocated - array->count) < count) { - dbg_da("Not enough place to occupy.\n"); - res = -1; - } else { - array->count += count; - } - - pthread_mutex_unlock(&array->mtx); - return res; -} - -/*----------------------------------------------------------------------------*/ - -unsigned da_try_reserve(const da_array_t *array, unsigned count) -{ - assert(array->allocated >= array->count); - if ((array->allocated - array->count) >= count) { - return 0; - } - - return 1; -} - -/*----------------------------------------------------------------------------*/ - -void da_release(da_array_t *array, unsigned count) -{ - pthread_mutex_lock(&array->mtx); - - assert(array->allocated >= array->count); - assert(array->count >= count); - dbg_da("Decreasing count of items in array.\n"); - array->count -= count; - - pthread_mutex_unlock(&array->mtx); -} - -/*----------------------------------------------------------------------------*/ - -void da_destroy(da_array_t *array) -{ - pthread_mutex_lock(&array->mtx); - void *old_items = rcu_dereference(array->items); - rcu_set_pointer(&array->items, NULL); - pthread_mutex_unlock(&array->mtx); - - synchronize_rcu(); - free(old_items); - pthread_mutex_destroy(&array->mtx); -} - -/*----------------------------------------------------------------------------*/ - -void *da_get_items(const da_array_t *array) -{ - return array->items; -} - -/*----------------------------------------------------------------------------*/ - -unsigned da_get_count(const da_array_t *array) -{ - return array->count; -} diff --git a/src/common/dynamic-array.h b/src/common/dynamic-array.h deleted file mode 100644 index 77a5d131ec97e962fd87ece963bc073f68281ea1..0000000000000000000000000000000000000000 --- a/src/common/dynamic-array.h +++ /dev/null @@ -1,156 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -/*! - * \file dynamic-array.h - * - * \author Lubos Slovak <lubos.slovak@nic.cz> - * - * \brief Safe dynamic array implementation. - * - * \todo Somehow check if the array is initialized and do not use otherwise. - * Maybe some magic, or so. - * \todo This structure is too slow because of the mutex. - * - * \addtogroup common_lib - * @{ - */ - -#ifndef _KNOTD_COMMON_DYNAMIC_ARRAY_H_ -#define _KNOTD_COMMON_DYNAMIC_ARRAY_H_ - -#include <string.h> -#include <pthread.h> - -/*----------------------------------------------------------------------------*/ -/*! - * \brief Dynamic array structure. - * - * Before using the dynamic array, it must be initialized using da_initialize(). - * When getting individual items always use da_get_items() to obtain pointer to - * the actual array. - * - * Items in the array cannot be dereferenced (it uses void * for storing the - * the items). It is needed to type-cast the item array (obtained by calling - * da_get_items()) to a proper type before dereferencing. - * - * When adding items, first reserve enough space for them by callling - * da_reserve() and subsequently tell the array about the inserted items by - * calling da_occupy(). When removing, the array must be told about the fact - * by calling da_release(). - * - * For getting the actual number of items in array use da_get_count(). - * - * When the array is no more needed, the da_destroy() function must be called - * before deallocating the structure. - */ -struct da_array { - /*! \brief The actual array. The items can't be dereferenced directly.*/ - void *items; - - /*! - * \brief Size of the stored items in bytes (used in counting of space - * needed. - */ - size_t item_size; - - /*! - * \brief Size of allocated space in number of items that can be stored. - */ - unsigned allocated; - - /*! \brief Number of items actually stored in the array. */ - unsigned count; - - /*! \brief Mutex. */ - pthread_mutex_t mtx; -}; - -typedef struct da_array da_array_t; - -/*----------------------------------------------------------------------------*/ -/*! - * \brief Creates and initializes the dynamic array. - * - * Initialization comprises of allocating place for \a count items of size - * \a item_size and setting the items to zeros. - * - * \retval 0 if successful. - * \retval -1 if not successful. - */ -da_array_t *da_create(unsigned count, size_t item_size); - -/*! - * \brief Initializes the dynamic array. - * - * Initialization comprises of allocating place for \a count items of size - * \a item_size and setting the items to zeros. - * - * \retval 0 if successful. - * \retval -1 if not successful. - */ -int da_initialize(da_array_t *array, unsigned count, size_t item_size); - -/*! - * \brief Reserves space for \a count more items. - * - * \retval 0 if successful and resizing was not necessary. - * \retval 1 if successful and the array was enlarged. - * \retval -1 if not successful - resizing was needed but could not be done. - */ -int da_reserve(da_array_t *array, unsigned count); - -/*! - * \brief Increases the number of items in array by \a count. - * - * \retval 0 If successful. - * \retval -1 If not successful (not enough allocated space, i.e. must run - * da_reserve()). - */ -int da_occupy(da_array_t *array, unsigned count); - -/*! - * \brief Tries to reserve space for \a count more items. - * - * \retval 0 if successful and resizing is not necessary. - * \retval 1 if successful but the array will need to be resized. - */ -unsigned da_try_reserve(const da_array_t *array, unsigned count); - -/*! - * \brief Releases space taken by \a count items. - */ -void da_release(da_array_t *array, unsigned count); - -/*! - * \brief Poperly deallocates the array. - */ -void da_destroy(da_array_t *array); - -/*! - * \brief Returns the array of items as a void *. - */ -void *da_get_items(const da_array_t *array); - -/*! - * \brief Returns count of items in the array. - */ -unsigned da_get_count(const da_array_t *array); - -/*----------------------------------------------------------------------------*/ - -#endif /* _KNOTD_COMMON_DYNAMIC_ARRAY_H_ */ - -/*! @} */ diff --git a/src/tests/common/da_tests.c b/src/tests/common/da_tests.c deleted file mode 100644 index 627e8aa8016b0a95b1f51a87a8a4263115981118..0000000000000000000000000000000000000000 --- a/src/tests/common/da_tests.c +++ /dev/null @@ -1,330 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "tests/common/da_tests.h" -#include "common/dynamic-array.h" -#include <unistd.h> -#include <urcu.h> - -static int da_tests_count(int argc, char *argv[]); -static int da_tests_run(int argc, char *argv[]); - -/* - * Unit API. - */ -unit_api da_tests_api = { - "Dynamic array", - &da_tests_count, - &da_tests_run -}; - -/* - * Unit implementation. - */ - -static const int DA_TEST_COUNT = 5; -static const int RCU_THREADS = 3; -static const int DA_FRAGMENT = 10; -static const int DA_DEF_SIZE = 1000; -static const int DA_OPERATIONS = 1000; -enum Operations { - DA_RESERVE = 0, - DA_OCCUPY = 1, - DA_RELEASE = 2, - DA_OPCOUNT = 3 -}; - -static int da_tests_count(int argc, char *argv[]) -{ - return DA_TEST_COUNT; -} - -static void do_something(int loops) -{ - int i; - int res = 1; - - static const int LOOPS = 10000; - - for (int j = 1; j <= LOOPS; ++j) { - for (i = 1; i <= loops; ++i) { - res *= i; - } - } -} - -static void *test_rcu_routine(void *obj) -{ - rcu_register_thread(); - rcu_read_lock(); - - do_something(1000); - - rcu_read_unlock(); - rcu_unregister_thread(); - - return NULL; -} - -static int test_rcu_threads() -{ - // Create threads - pthread_t *threads = malloc(RCU_THREADS * sizeof(pthread_t)); - for (int i = 0; i < RCU_THREADS; ++i) { - if (pthread_create(&threads[i], NULL, test_rcu_routine, NULL)) { - diag("rcu: failed to create thread %d", i); - free(threads); - return 0; - } - } - - // Join threads - void *pret = NULL; - for (int i = 0; i < RCU_THREADS; ++i) { - if (pthread_join(threads[i], &pret)) { - diag("rcu: failed to join thread %d", i); - free(threads); - return 0; - } - } - - synchronize_rcu(); - free(threads); - - return 1; -} - -static int test_da_init(da_array_t *arr) -{ - return da_initialize(arr, DA_DEF_SIZE, sizeof(uint)) == 0; -} - -static int test_da_random_op(da_array_t *arr) -{ - unsigned seed = (unsigned)time(0); - uint allocated = DA_DEF_SIZE; - uint size = 0; - - for (int i = 0; i < DA_OPERATIONS; ++i) { - int r = rand_r(&seed) % DA_OPCOUNT; - int count = rand_r(&seed) % DA_FRAGMENT + 1; - - switch (r) { - - // Perform reserve operation - case DA_RESERVE: - if (da_reserve(arr, count) >= 0 && - size <= allocated) { - if ((allocated - size) < count) { - allocated *= 2; - } - } else { - diag("dynamic-array: da_reserve(%p, %d) failed" - " (size %d, alloc'd %d)", - arr, count, size, allocated); - return 0; - } - break; - - // Perform occupy operation - case DA_OCCUPY: - if (da_occupy(arr, count) == 0) { - uint *items = (uint *) da_get_items(arr); - for (int j = 0; j < da_get_count(arr); ++j) { - items[j] = rand_r(&seed); - } - if (size <= allocated && - (allocated - size) >= count) { - size += count; - } else { - return 0; - } - } else { - diag("dynamic-array: da_occupy(%p, %d) failed" - " (size %d, alloc'd %d)", - arr, count, size, allocated); - return 0; - } - break; - - // Perform release operation - case DA_RELEASE: - if (arr->count > 0) { - count = (rand_r(&seed) % DA_FRAGMENT) % arr->count; - da_release(arr, count); - - if (size <= allocated && size >= count) { - size -= count; - } else { - return 0; - } - } - break; - - default: - break; - } - - // Check allocated / size - if (allocated != arr->allocated || size != arr->count) { - diag("dynamic-array: allocated memory %d (expected %d)" - " size %d (expected %d) mismatch", - arr->allocated, allocated, arr->count, size); - return 0; - } - } - - return 1; -} - -void *test_da_read(void *obj) -{ - rcu_register_thread(); - rcu_read_lock(); - - unsigned seed = (unsigned)time(0); - da_array_t *arr = (da_array_t *) obj; - int index = rand_r(&seed) % da_get_count(arr); - - note(" dynamic-array: read thread"); - note(" read thread: saving pointer to %d. item", index); - uint *item = &((uint *) da_get_items(arr))[index]; - note(" read thread: before: pointer: %p item: %u", item, *item); - - do_something(100000); - - note(" read thread after: pointer: %p item: %u", item, *item); - rcu_read_unlock(); - note(" read thread unlocked: pointer: %p item: %u", item, *item); - - do_something(10000); - - note(" read thread: now the item should be deallocated"); - //note(" read thread: pointer: %p item: %u", item, *item); - - rcu_unregister_thread(); - - return NULL; -} - -static int test_da_resize_holding(da_array_t *arr) -{ - int ret = 1; - rcu_register_thread(); - pthread_t reader; - - // Create thread for reading - note("dynamic-array: creating read threads"); - if (pthread_create(&reader, NULL, test_da_read, (void *)arr)) { - diag("dynamic-array: failed to create reading thread", - __func__); - rcu_unregister_thread(); - return 0; - } - - // Wait some time, so the other thread gets the item for reading - do_something(5000); - - // Force resize - note(" dynamic-array: array resized"); - if (da_reserve(arr, arr->allocated - arr->count + 1) == -1) { - diag("dynamic-array: da_reserve(%p, %d) failed", arr, - arr->allocated - arr->count + 1); - ret = 0; - } - - //Wait for the thread to finish - void *pret = NULL; - if (pthread_join(reader, &pret)) { - diag("dynamic-array: failed to join reading thread", - __func__); - ret = 0; - } - - rcu_unregister_thread(); - return ret; -} - -static int test_da_resize(da_array_t *arr) -{ - unsigned seed = (unsigned)time(0); - int orig_count = da_get_count(arr); - note("dynamic-array: allocated: %d, items: %d", arr->allocated, - orig_count); - // store the items currently in the array - int *items = (int *)malloc(orig_count * sizeof(int)); - for (int i = 0; i < orig_count; ++i) { - items[i] = ((int *)da_get_items(arr))[i]; - } - - // force resize - int res = 0; - while ((res = da_reserve(arr, 10)) == 0) { - int i = da_get_count(arr); - da_occupy(arr, 10); - for (; i < da_get_count(arr); ++i) { - ((int *)da_get_items(arr))[i] = rand_r(&seed); - } - } - - if (res < 0) { - diag("dynamic-array: failed to reserve space"); - return 0; - } - - int errors = 0; - for (int i = 0; i < orig_count; ++i) { - if (items[i] != ((int *)da_get_items(arr))[i]) { - diag("dynamic-array: Wrong item on position %d." - "Should be: %d, " - "present value: %d", i, items[i], - ((int *)da_get_items(arr))[i]); - ++errors; - } - } - - free(items); - - return errors == 0; -} - -static int da_tests_run(int argc, char *argv[]) -{ - // Init - rcu_init(); - da_array_t array; - - // Test 1: test rcu - ok(test_rcu_threads(), "dynamic-array: rcu tests"); - - // Test 2: init - ok(test_da_init(&array), "dynamic-array: init"); - - // Test 3: reserve/occupy random operations - ok(test_da_random_op(&array), - "dynamic-array: randomized reserve/occupy/release"); - - // Test 4: resizing array while holding an item - ok(test_da_resize_holding(&array), - "dynamic-array: resize array while holding an item"); - - // Test 5: resize - ok(test_da_resize(&array), "dynamic-array: resize array"); - - // Cleanup - da_destroy(&array); - return 0; -} diff --git a/src/tests/common/da_tests.h b/src/tests/common/da_tests.h deleted file mode 100644 index d51b7bedf9f81d2aebaec3f6a6e4c027b2f418d3..0000000000000000000000000000000000000000 --- a/src/tests/common/da_tests.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _KNOTD_DA_TESTS_H_ -#define _KNOTD_DA_TESTS_H_ - -#include "common/libtap/tap_unit.h" - -/* Unit API. */ -unit_api da_tests_api; - -#endif /* _KNOTD_DA_TESTS_H_ */ diff --git a/src/tests/unittests_main.c b/src/tests/unittests_main.c index 1ec336a28493b90e946044f1c64d1952adf06ee2..21eae14bd5b381bc0378c827f6c520f4c5206763 100644 --- a/src/tests/unittests_main.c +++ b/src/tests/unittests_main.c @@ -22,7 +22,6 @@ #include "tests/common/slab_tests.h" #include "tests/common/skiplist_tests.h" #include "tests/common/events_tests.h" -#include "tests/common/da_tests.h" #include "tests/common/acl_tests.h" #include "tests/common/fdset_tests.h" #include "tests/knot/dthreads_tests.h" @@ -47,7 +46,6 @@ int main(int argc, char *argv[]) &skiplist_tests_api, //! Skip list unit &dthreads_tests_api, //! DThreads testing unit &events_tests_api, //! Events testing unit - &da_tests_api, //! Dynamic array unit &acl_tests_api, //! ACLs &fdset_tests_api, //! FDSET polling wrapper