From: Olivier Dion Date: Thu, 25 May 2023 18:35:57 +0000 (-0400) Subject: tests: Add tests for checking race conditions X-Git-Url: https://git.lttng.org/?p=userspace-rcu.git;a=commitdiff_plain;h=59fdcc3a77acbfd1c4552b64882752b96b2a4a5c tests: Add tests for checking race conditions These tests do nothing useful except of stress testing a single-consumer, multiple-producers program on various data structures. These tests are only meaningful when compiling liburcu with TSAN. Change-Id: If22b27ed0fb95bf890947fc4e75f923edb5ada8f Signed-off-by: Olivier Dion Signed-off-by: Mathieu Desnoyers --- diff --git a/tests/unit/test_lfstack.c b/tests/unit/test_lfstack.c new file mode 100644 index 0000000..a1f99f0 --- /dev/null +++ b/tests/unit/test_lfstack.c @@ -0,0 +1,90 @@ +/* + * test_lfstack.c + * + * Userspace RCU library - test wftack race conditions + * + * Copyright 2023 - Olivier Dion + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _LGPL_SOURCE + +#include + +#include + +#include + +#include "tap.h" + +#define NR_TESTS 1 +#define NR_PRODUCERS 4 +#define LOOP 100 + +static void async_run(struct cds_lfs_stack *queue) +{ + struct cds_lfs_node *node = malloc(sizeof(*node)); + + cds_lfs_node_init(node); + + cds_lfs_push(queue, node); +} + +static void *async_loop(void *queue) +{ + size_t k = 0; + + while (k < LOOP * NR_PRODUCERS) { + free(cds_lfs_pop_blocking(queue)); + ++k; + } + + return NULL; +} + +static void *spawn_jobs(void *queue) +{ + for (size_t k = 0; k < LOOP; ++k) { + async_run(queue); + } + + return 0; +} + +int main(void) +{ + pthread_t consumer; + pthread_t producers[NR_PRODUCERS]; + struct cds_lfs_stack queue; + + plan_tests(NR_TESTS); + + cds_lfs_init(&queue); + pthread_create(&consumer, NULL, async_loop, &queue); + + for (size_t k = 0; k < NR_PRODUCERS; ++k) { + pthread_create(&producers[k], NULL, spawn_jobs, &queue); + } + + pthread_join(consumer, NULL); + for (size_t k = 0; k < NR_PRODUCERS; ++k) { + pthread_join(producers[k], NULL); + } + + ok1("No race conditions"); + + return exit_status(); +} diff --git a/tests/unit/test_wfcqueue.c b/tests/unit/test_wfcqueue.c new file mode 100644 index 0000000..338aa07 --- /dev/null +++ b/tests/unit/test_wfcqueue.c @@ -0,0 +1,119 @@ +/* + * test_wfcqueue.c + * + * Userspace RCU library - test wfcqueue race conditions + * + * Copyright 2023 - Olivier Dion + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _LGPL_SOURCE + +#include + +#include + +#include + +#include "tap.h" + +#define NR_TESTS 1 +#define NR_PRODUCERS 4 +#define LOOP 100 + +struct queue { + struct cds_wfcq_head head; + struct cds_wfcq_tail tail; +}; + +static void async_run(struct queue *queue) +{ + struct cds_wfcq_node *node = malloc(sizeof(*node)); + + cds_wfcq_node_init(node); + + cds_wfcq_enqueue(&queue->head, &queue->tail, node); +} +static void do_async_loop(size_t *k, struct queue *queue) +{ + struct queue my_queue; + enum cds_wfcq_ret state; + struct cds_wfcq_node *node, *next; + + cds_wfcq_init(&my_queue.head, &my_queue.tail); + + state = cds_wfcq_splice_blocking(&my_queue.head, + &my_queue.tail, + &queue->head, + &queue->tail); + + if (state == CDS_WFCQ_RET_SRC_EMPTY) { + return; + } + + __cds_wfcq_for_each_blocking_safe(&my_queue.head, + &my_queue.tail, + node, next) { + free(node); + (*k)++; + } +} + +static void *async_loop(void *queue) +{ + size_t k = 0; + + while (k < LOOP * NR_PRODUCERS) { + (void) poll(NULL, 0, 10); + do_async_loop(&k, queue); + } + + return NULL; +} + +static void *spawn_jobs(void *queue) +{ + for (size_t k = 0; k < LOOP; ++k) { + async_run(queue); + } + + return 0; +} + +int main(void) +{ + pthread_t consumer; + pthread_t producers[NR_PRODUCERS]; + struct queue queue; + + plan_tests(NR_TESTS); + + cds_wfcq_init(&queue.head, &queue.tail); + pthread_create(&consumer, NULL, async_loop, &queue); + + for (size_t k = 0; k < NR_PRODUCERS; ++k) { + pthread_create(&producers[k], NULL, spawn_jobs, &queue); + } + + pthread_join(consumer, NULL); + for (size_t k = 0; k < NR_PRODUCERS; ++k) { + pthread_join(producers[k], NULL); + } + + ok1("No race conditions"); + + return exit_status(); +} diff --git a/tests/unit/test_wfqueue.c b/tests/unit/test_wfqueue.c new file mode 100644 index 0000000..57afaba --- /dev/null +++ b/tests/unit/test_wfqueue.c @@ -0,0 +1,91 @@ +/* + * test_wfqueue.c + * + * Userspace RCU library - test wfqueue race conditions + * + * Copyright 2023 - Olivier Dion + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _LGPL_SOURCE + +#include + +#include + +#define CDS_WFQ_DEPRECATED +#include + +#include "tap.h" + +#define NR_TESTS 1 +#define NR_PRODUCERS 4 +#define LOOP 100 + +static void async_run(struct cds_wfq_queue *queue) +{ + struct cds_wfq_node *node = malloc(sizeof(*node)); + + cds_wfq_node_init(node); + + cds_wfq_enqueue(queue, node); +} + +static void *async_loop(void *queue) +{ + size_t k = 0; + + while (k < LOOP * NR_PRODUCERS) { + free(cds_wfq_dequeue_blocking(queue)); + ++k; + } + + return NULL; +} + +static void *spawn_jobs(void *queue) +{ + for (size_t k = 0; k < LOOP; ++k) { + async_run(queue); + } + + return 0; +} + +int main(void) +{ + pthread_t consumer; + pthread_t producers[NR_PRODUCERS]; + struct cds_wfq_queue queue; + + plan_tests(NR_TESTS); + + cds_wfq_init(&queue); + pthread_create(&consumer, NULL, async_loop, &queue); + + for (size_t k = 0; k < NR_PRODUCERS; ++k) { + pthread_create(&producers[k], NULL, spawn_jobs, &queue); + } + + pthread_join(consumer, NULL); + for (size_t k = 0; k < NR_PRODUCERS; ++k) { + pthread_join(producers[k], NULL); + } + + ok1("No race conditions"); + + return exit_status(); +} diff --git a/tests/unit/test_wfstack.c b/tests/unit/test_wfstack.c new file mode 100644 index 0000000..578ae92 --- /dev/null +++ b/tests/unit/test_wfstack.c @@ -0,0 +1,90 @@ +/* + * test_wfstack.c + * + * Userspace RCU library - test wftack race conditions + * + * Copyright 2023 - Olivier Dion + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _LGPL_SOURCE + +#include + +#include + +#include + +#include "tap.h" + +#define NR_TESTS 1 +#define NR_PRODUCERS 4 +#define LOOP 100 + +static void async_run(struct cds_wfs_stack *queue) +{ + struct cds_wfs_node *node = malloc(sizeof(*node)); + + cds_wfs_node_init(node); + + cds_wfs_push(queue, node); +} + +static void *async_loop(void *queue) +{ + size_t k = 0; + + while (k < LOOP * NR_PRODUCERS) { + free(cds_wfs_pop_blocking(queue)); + ++k; + } + + return NULL; +} + +static void *spawn_jobs(void *queue) +{ + for (size_t k = 0; k < LOOP; ++k) { + async_run(queue); + } + + return 0; +} + +int main(void) +{ + pthread_t consumer; + pthread_t producers[NR_PRODUCERS]; + struct cds_wfs_stack queue; + + plan_tests(NR_TESTS); + + cds_wfs_init(&queue); + pthread_create(&consumer, NULL, async_loop, &queue); + + for (size_t k = 0; k < NR_PRODUCERS; ++k) { + pthread_create(&producers[k], NULL, spawn_jobs, &queue); + } + + pthread_join(consumer, NULL); + for (size_t k = 0; k < NR_PRODUCERS; ++k) { + pthread_join(producers[k], NULL); + } + + ok1("No race conditions"); + + return exit_status(); +}