1 // SPDX-License-Identifier: MIT
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
10 static int nr_reader_threads
= 2;
11 static int nr_writer_threads
= 2;
12 static int duration_s
= 10;
14 static volatile int start_test
, stop_test
;
21 #include "../../src/rcu.h"
23 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
25 static struct side_rcu_gp_state test_rcu_gp
;
27 #define POISON_VALUE 55
33 static struct test_data
*rcu_p
;
36 void *test_reader_thread(void *arg
)
38 struct thread_ctx
*thread_ctx
= (struct thread_ctx
*) arg
;
41 while (!start_test
) { }
44 struct side_rcu_read_state rcu_read_state
;
48 side_rcu_read_begin(&test_rcu_gp
, &rcu_read_state
);
49 p
= side_rcu_dereference(rcu_p
);
52 if (v
!= 0 && v
!= 1) {
53 fprintf(stderr
, "Unexpected value: %d\n", v
);
57 side_rcu_read_end(&test_rcu_gp
, &rcu_read_state
);
60 thread_ctx
->count
= count
;
65 void *test_writer_thread(void *arg
)
67 struct thread_ctx
*thread_ctx
= (struct thread_ctx
*) arg
;
70 while (!start_test
) { }
73 struct test_data
*new_data
, *old_data
;
75 new_data
= calloc(1, sizeof(struct test_data
));
79 pthread_mutex_lock(&lock
);
82 new_data
->v
= old_data
->v
^ 1; /* 0 or 1 */
83 side_rcu_assign_pointer(rcu_p
, new_data
);
84 pthread_mutex_unlock(&lock
);
86 side_rcu_wait_grace_period(&test_rcu_gp
);
89 old_data
->v
= POISON_VALUE
;
94 thread_ctx
->count
= count
;
101 printf("Invoke with command line arguments:\n");
102 printf(" -d <seconds> (test duration in seconds)\n");
103 printf(" -r <nr_readers> (number of reader threads)\n");
104 printf(" -w <nr_writers> (number of writers threads)\n");
108 int parse_cmd_line(int argc
, const char **argv
)
110 const char *arg
= NULL
;
113 for (i
= 1; i
< argc
; i
++) {
123 goto error_extra_arg
;
124 duration_s
= atoi(argv
[i
+ 1]);
129 goto error_extra_arg
;
130 nr_reader_threads
= atoi(argv
[i
+ 1]);
135 goto error_extra_arg
;
136 nr_writer_threads
= atoi(argv
[i
+ 1]);
153 fprintf(stderr
, "Unknown command line option '%s'\n", arg
);
156 fprintf(stderr
, "Command line option '%s' requires an extra argument\n", arg
);
160 int main(int argc
, const char **argv
)
162 struct thread_ctx
*reader_ctx
;
163 struct thread_ctx
*writer_ctx
;
166 uint64_t read_tot
= 0, write_tot
= 0;
168 ret
= parse_cmd_line(argc
, argv
);
174 sleep_s
= duration_s
;
175 side_rcu_gp_init(&test_rcu_gp
);
176 reader_ctx
= calloc(nr_reader_threads
, sizeof(struct thread_ctx
));
179 writer_ctx
= calloc(nr_writer_threads
, sizeof(struct thread_ctx
));
184 for (i
= 0; i
< nr_reader_threads
; i
++) {
185 ret
= pthread_create(&reader_ctx
[i
].thread_id
, NULL
, test_reader_thread
, &reader_ctx
[i
]);
188 perror("pthread_create");
192 for (i
= 0; i
< nr_writer_threads
; i
++) {
193 ret
= pthread_create(&writer_ctx
[i
].thread_id
, NULL
, test_writer_thread
, &writer_ctx
[i
]);
196 perror("pthread_create");
203 while (sleep_s
> 0) {
204 sleep_s
= sleep(sleep_s
);
209 for (i
= 0; i
< nr_reader_threads
; i
++) {
212 ret
= pthread_join(reader_ctx
[i
].thread_id
, &res
);
215 perror("pthread_join");
218 read_tot
+= reader_ctx
[i
].count
;
220 for (i
= 0; i
< nr_writer_threads
; i
++) {
223 ret
= pthread_join(writer_ctx
[i
].thread_id
, &res
);
226 perror("pthread_join");
229 write_tot
+= writer_ctx
[i
].count
;
231 printf("Summary: duration: %d s, nr_reader_threads: %d, nr_writer_threads: %d, reads: %" PRIu64
", writes: %" PRIu64
"\n",
232 duration_s
, nr_reader_threads
, nr_writer_threads
, read_tot
, write_tot
);
235 side_rcu_gp_exit(&test_rcu_gp
);