1 1.1 christos // SPDX-FileCopyrightText: 2023 Olivier Dion <odion (at) efficios.com> 2 1.1 christos // 3 1.1 christos // SPDX-License-Identifier: GPL-2.0-or-later 4 1.1 christos 5 1.1 christos /* 6 1.1 christos * test_wfcqueue.c 7 1.1 christos * 8 1.1 christos * Userspace RCU library - test wfcqueue race conditions 9 1.1 christos */ 10 1.1 christos 11 1.1 christos #define _LGPL_SOURCE 12 1.1 christos 13 1.1 christos #include <stdlib.h> 14 1.1 christos 15 1.1 christos #include <pthread.h> 16 1.1 christos 17 1.1 christos #include <urcu/wfcqueue.h> 18 1.1 christos 19 1.1 christos #include "tap.h" 20 1.1 christos 21 1.1 christos #define NR_TESTS 1 22 1.1 christos #define NR_PRODUCERS 4 23 1.1 christos #define LOOP 100 24 1.1 christos 25 1.1 christos struct queue { 26 1.1 christos struct cds_wfcq_head head; 27 1.1 christos struct cds_wfcq_tail tail; 28 1.1 christos }; 29 1.1 christos 30 1.1 christos static void async_run(struct queue *queue) 31 1.1 christos { 32 1.1 christos struct cds_wfcq_node *node = malloc(sizeof(*node)); 33 1.1 christos 34 1.1 christos cds_wfcq_node_init(node); 35 1.1 christos 36 1.1 christos cds_wfcq_enqueue(&queue->head, &queue->tail, node); 37 1.1 christos } 38 1.1 christos static void do_async_loop(size_t *k, struct queue *queue) 39 1.1 christos { 40 1.1 christos struct queue my_queue; 41 1.1 christos enum cds_wfcq_ret state; 42 1.1 christos struct cds_wfcq_node *node, *next; 43 1.1 christos 44 1.1 christos cds_wfcq_init(&my_queue.head, &my_queue.tail); 45 1.1 christos 46 1.1 christos state = cds_wfcq_splice_blocking(&my_queue.head, 47 1.1 christos &my_queue.tail, 48 1.1 christos &queue->head, 49 1.1 christos &queue->tail); 50 1.1 christos 51 1.1 christos if (state == CDS_WFCQ_RET_SRC_EMPTY) { 52 1.1 christos return; 53 1.1 christos } 54 1.1 christos 55 1.1 christos __cds_wfcq_for_each_blocking_safe(&my_queue.head, 56 1.1 christos &my_queue.tail, 57 1.1 christos node, next) { 58 1.1 christos free(node); 59 1.1 christos (*k)++; 60 1.1 christos } 61 1.1 christos } 62 1.1 christos 63 1.1 christos static void *async_loop(void *queue) 64 1.1 christos { 65 1.1 christos size_t k = 0; 66 1.1 christos 67 1.1 christos while (k < LOOP * NR_PRODUCERS) { 68 1.1 christos (void) poll(NULL, 0, 10); 69 1.1 christos do_async_loop(&k, queue); 70 1.1 christos } 71 1.1 christos 72 1.1 christos return NULL; 73 1.1 christos } 74 1.1 christos 75 1.1 christos static void *spawn_jobs(void *queue) 76 1.1 christos { 77 1.1 christos for (size_t k = 0; k < LOOP; ++k) { 78 1.1 christos async_run(queue); 79 1.1 christos } 80 1.1 christos 81 1.1 christos return 0; 82 1.1 christos } 83 1.1 christos 84 1.1 christos int main(void) 85 1.1 christos { 86 1.1 christos pthread_t consumer; 87 1.1 christos pthread_t producers[NR_PRODUCERS]; 88 1.1 christos struct queue queue; 89 1.1 christos 90 1.1 christos plan_tests(NR_TESTS); 91 1.1 christos 92 1.1 christos cds_wfcq_init(&queue.head, &queue.tail); 93 1.1 christos pthread_create(&consumer, NULL, async_loop, &queue); 94 1.1 christos 95 1.1 christos for (size_t k = 0; k < NR_PRODUCERS; ++k) { 96 1.1 christos pthread_create(&producers[k], NULL, spawn_jobs, &queue); 97 1.1 christos } 98 1.1 christos 99 1.1 christos pthread_join(consumer, NULL); 100 1.1 christos for (size_t k = 0; k < NR_PRODUCERS; ++k) { 101 1.1 christos pthread_join(producers[k], NULL); 102 1.1 christos } 103 1.1 christos 104 1.1 christos ok1("No race conditions"); 105 1.1 christos 106 1.1 christos return exit_status(); 107 1.1 christos } 108