On 12/7/22 09:08, Adrian Moreno wrote:
>
>
> On 12/6/22 17:02, Ilya Maximets wrote:
>> On 12/5/22 09:41, Adrian Moreno wrote:
>>> Low test coverage on this area caused some errors to remain unnoticed.
>>> Add basic functional test of rculist.
>>>
>>> Signed-off-by: Adrian Moreno <[email protected]>
>>> ---
>>> tests/automake.mk | 1 +
>>> tests/library.at | 5 ++
>>> tests/test-rculist.c | 205 +++++++++++++++++++++++++++++++++++++++++++
>>> 3 files changed, 211 insertions(+)
>>> create mode 100644 tests/test-rculist.c
>>>
>>> diff --git a/tests/automake.mk b/tests/automake.mk
>>> index d509cf935..88f97b8b7 100644
>>> --- a/tests/automake.mk
>>> +++ b/tests/automake.mk
>>> @@ -474,6 +474,7 @@ tests_ovstest_SOURCES = \
>>> tests/test-packets.c \
>>> tests/test-random.c \
>>> tests/test-rcu.c \
>>> + tests/test-rculist.c \
>>> tests/test-reconnect.c \
>>> tests/test-rstp.c \
>>> tests/test-sflow.c \
>>> diff --git a/tests/library.at b/tests/library.at
>>> index bafb28277..164ae789d 100644
>>> --- a/tests/library.at
>>> +++ b/tests/library.at
>>> @@ -27,6 +27,11 @@ AT_CHECK([ovstest test-hindex], [0],
>>> [.....................
>>> ])
>>> AT_CLEANUP
>>> +AT_SETUP([test rcu linked lists])
>>> +AT_CHECK([ovstest test-rculist], [0], [.....
>>> +])
>>> +AT_CLEANUP
>>> +
>>> AT_SETUP([cuckoo hash])
>>> AT_KEYWORDS([cmap])
>>> AT_CHECK([ovstest test-cmap check 1], [0], [...
>>> diff --git a/tests/test-rculist.c b/tests/test-rculist.c
>>> new file mode 100644
>>> index 000000000..49fe434ff
>>> --- /dev/null
>>> +++ b/tests/test-rculist.c
>>> @@ -0,0 +1,205 @@
>>> +#include <config.h>
>>> +#undef NDEBUG
>>> +#include <unistd.h>
>>> +
>>> +#include "ovstest.h"
>>> +#include "rculist.h"
>>> +#include "openvswitch/list.h"
>>> +#include "ovs-thread.h"
>>> +#include "random.h"
>>> +#include "util.h"
>>> +
>>> +enum { MAX_ELEMS = 10, MAX_CHECKS = 200 };
>>> +
>>> +/* Sample list element. */
>>> +struct element {
>>> + int value;
>>> + struct rculist node;
>>> +};
>>> +
>>> +/* Continuously check the integrity of the list until it's empty. */
>>> +static void *
>>> +checker_main(void *aux)
>>> +{
>>> + struct element *elem;
>>> + struct rculist *list = (struct rculist *) aux;
>>> + bool checked = false;
>>> +
>>> + for (int i = 0; i < MAX_CHECKS; i++) {
>>> + int value = -1;
>>> + RCULIST_FOR_EACH (elem, node, list) {
>>> + ovs_assert(value <= elem->value);
>>> + ovs_assert(elem->value < MAX_ELEMS);
>>> + value = elem->value;
>>> + if (!checked) {
>>> + checked = true;
>>> + }
>>> + usleep(10);
>>
>> Hi, Adrian.
>>
>> This change breaks the build on Windows:
>>
>> tests\test-rculist.c(37): error C4013: 'usleep' undefined; assuming extern
>> returning int
>> make[1]: *** [tests/test-rculist.obj] Error 2
>>
>> You should use xsleep or xnanosleep instead. The problem
>> might be that they are entering quiescent state for the time
>> of the sleep, so the test need to be careful with that.
>>
>
> We cannot enter quiescent state in the checker thread so I'll see if we can
> use Windows' "Sleep".
OK, the Sleep() should have a resolution you need.
I guess, you may define a function here in the test
that will do usleep() or Sleep() depending on the
platform, similarly to xsleep(), but without entering
a quiescent state.
> Thanks.
>
>>> + }
>>> +
>>> + ovsrcu_quiesce();
>>> +
>>> + if (checked && rculist_is_empty(list)) {
>>> + break;
>>> + }
>>> + }
>>> + return NULL;
>>> +}
>>> +
>>> +/* Run test while a thread checks the integrity of the list.
>>> + * Tests must end up emptying the list. */
>>> +static void
>>> +run_test_while_checking(void (*function)(struct rculist *list))
>>> +{
>>> + struct rculist list;
>>> + pthread_t checker;
>>> +
>>> + rculist_init(&list);
>>> +
>>> + checker = ovs_thread_create("checker", checker_main, &list);
>>> + function(&list);
>>> +
>>> + ovs_assert(rculist_is_empty(&list));
>>> + ovsrcu_quiesce();
>>> + xpthread_join(checker, NULL);
>>> + printf(".");
>>> +}
>>> +
>>> +static void
>>> +test_rculist_insert_delete__(struct rculist *list, bool long_version)
>>> +{
>>> + struct element *elem;
>>> + int value;
>>> +
>>> + for (int i = 1; i < MAX_ELEMS; i++) {
>>> + elem = xmalloc(sizeof *elem);
>>> + elem->value = i;
>>> + rculist_insert(list, &elem->node);
>>> + /* Leave some time for checkers to iterate through. */
>>> + usleep(random_range(1000));
>>> + }
>>> +
>>> + ovsrcu_quiesce();
>>> +
>>> + value = MAX_ELEMS;
>>> + RCULIST_FOR_EACH_REVERSE_PROTECTED (elem, node, list) {
>>> + ovs_assert (elem->value <= value);
>>> + value = elem->value;
>>> + }
>>> +
>>> + if (long_version) {
>>> + struct element *next;
>>> + RCULIST_FOR_EACH_SAFE_PROTECTED (elem, next, node, list) {
>>> + rculist_remove(&elem->node);
>>> + ovsrcu_postpone(free, elem);
>>> + /* Leave some time for checkers to iterate through. */
>>> + usleep(random_range(1000));
>>> + }
>>> + } else {
>>> + RCULIST_FOR_EACH_SAFE_PROTECTED (elem, node, list) {
>>> + rculist_remove(&elem->node);
>>> + ovsrcu_postpone(free, elem);
>>> + /* Leave some time for checkers to iterate through. */
>>> + usleep(random_range(1000));
>>> + }
>>> + }
>>> +}
>>> +
>>> +static void
>>> +test_rculist_insert_delete(struct rculist *list) {
>>
>> '{' should be on a new line.
>>
>>> + test_rculist_insert_delete__(list, false);
>>> +}
>>> +
>>> +static void
>>> +test_rculist_insert_delete_long(struct rculist *list) {
>>
>> Ditto.
>>
>>> + test_rculist_insert_delete__(list, true);
>>> +}
>>> +
>>> +static void
>>> +test_rculist_push_front_pop_back(struct rculist *list)
>>> +{
>>> + struct element *elem;
>>> +
>>> + for (int i = MAX_ELEMS - 1; i > 0; i--) {
>>> + elem = xmalloc(sizeof *elem);
>>> + elem->value = i;
>>> + rculist_push_front(list, &elem->node);
>>> + /* Leave some time for checkers to iterate through. */
>>> + usleep(random_range(1000));
>>> + }
>>> +
>>> + ovsrcu_quiesce();
>>> +
>>> + while (!rculist_is_empty(list)) {
>>> + elem = CONTAINER_OF(rculist_pop_back(list), struct element, node);
>>> + ovsrcu_postpone(free, elem);
>>> + /* Leave some time for checkers to iterate through. */
>>> + usleep(random_range(1000));
>>> + }
>>> +}
>>> +
>>> +static void
>>> +test_rculist_push_back_pop_front(struct rculist *list)
>>> +{
>>> + struct element *elem;
>>> +
>>> + for (int i = 0 ; i < MAX_ELEMS; i++) {
>>> + elem = xmalloc(sizeof *elem);
>>> + elem->value = i;
>>> + rculist_push_back(list, &elem->node);
>>> + /* Leave some time for checkers to iterate through. */
>>> + usleep(random_range(1000));
>>> + }
>>> +
>>> + ovsrcu_quiesce();
>>> +
>>> + while (!rculist_is_empty(list)) {
>>> + elem = CONTAINER_OF(rculist_pop_front(list), struct element, node);
>>> + ovsrcu_postpone(free, elem);
>>> + /* Leave some time for checkers to iterate through. */
>>> + usleep(random_range(1000));
>>> + }
>>> +}
>>> +
>>> +static void
>>> +test_rculist_splice(struct rculist *list)
>>> +{
>>> + struct element *elem;
>>> + struct rculist other;
>>> + rculist_init(&other);
>>> +
>>> + /* Insert elements in list by splicing an intermediate rculist */
>>> + for (int i = 0; i < MAX_ELEMS; i++) {
>>> + elem = xmalloc(sizeof *elem);
>>> + elem->value = i;
>>> + rculist_insert(&other, &elem->node);
>>> + rculist_splice_hidden(list, rculist_next_protected(&other),
>>> &other);
>>> + rculist_init(&other);
>>> + /* Leave some time for checkers to iterate through. */
>>> + usleep(random_range(1000));
>>> + }
>>> +
>>> + ovsrcu_quiesce();
>>> +
>>> + ovs_assert(rculist_size(list) == MAX_ELEMS);
>>> + ovs_assert(rculist_is_empty(&other));
>>> + while (!rculist_is_empty(list)) {
>>> + elem = CONTAINER_OF(rculist_pop_front(list), struct element, node);
>>> + ovsrcu_postpone(free, elem);
>>> + /* Leave some time for checkers to iterate through. */
>>> + usleep(random_range(1000));
>>> + }
>>> +}
>>> +
>>> +static void
>>> +test_rculist_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
>>> +{
>>> + run_test_while_checking(test_rculist_insert_delete);
>>> + run_test_while_checking(test_rculist_insert_delete_long);
>>> + run_test_while_checking(test_rculist_push_back_pop_front);
>>> + run_test_while_checking(test_rculist_push_front_pop_back);
>>> + run_test_while_checking(test_rculist_splice);
>>> + printf("\n");
>>> +}
>>> +
>>> +OVSTEST_REGISTER("test-rculist", test_rculist_main);
>>
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev