Fix force_mb_all_threads must be called within internal local
[urcu.git] / test_urcu.c
CommitLineData
b257a10b
MD
1/*
2 * test_urcu.c
3 *
4 * Userspace RCU library - test program
5 *
6 * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
7 *
8 * Distributed under GPLv2
9 */
10
ac260fd9 11#include <stdio.h>
f69f195a
MD
12#include <pthread.h>
13#include <stdlib.h>
41718ff9 14#include <string.h>
f69f195a
MD
15#include <sys/types.h>
16#include <sys/wait.h>
17#include <unistd.h>
18#include <stdio.h>
41718ff9 19#include <assert.h>
87bd15cd
BW
20#include <sys/syscall.h>
21
22#if defined(_syscall0)
23_syscall0(pid_t, gettid)
24#elif defined(__NR_gettid)
25static inline pid_t gettid(void)
26{
27 return syscall(__NR_gettid);
28}
29#else
30#warning "use pid as tid"
31static inline pid_t gettid(void)
32{
33 return getpid();
34}
35#endif
36
ac260fd9
MD
37#include "urcu.h"
38
41718ff9
MD
39struct test_array {
40 int a;
41718ff9
MD
41};
42
bb488185
MD
43static int no_writer_delay;
44
41718ff9
MD
45static struct test_array *test_rcu_pointer;
46
cf380c2f
MD
47static unsigned long duration;
48static time_t start_time;
49static unsigned long __thread duration_interval;
50#define DURATION_TEST_DELAY 100
51
52/*
53 * returns 0 if test should end.
54 */
55static int test_duration(void)
56{
57 if (duration_interval++ >= DURATION_TEST_DELAY) {
58 duration_interval = 0;
59 if (time(NULL) - start_time >= duration)
60 return 0;
61 }
62 return 1;
63}
64
b1b5ce8f 65#define NR_READ 10
8c8eed97 66#define NR_WRITE 9
f69f195a 67
c265818b
MD
68pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
69
70void rcu_copy_mutex_lock(void)
71{
72 int ret;
73 ret = pthread_mutex_lock(&rcu_copy_mutex);
74 if (ret) {
75 perror("Error in pthread mutex lock");
76 exit(-1);
77 }
78}
79
80void rcu_copy_mutex_unlock(void)
81{
82 int ret;
83
84 ret = pthread_mutex_unlock(&rcu_copy_mutex);
85 if (ret) {
86 perror("Error in pthread mutex unlock");
87 exit(-1);
88 }
89}
f69f195a 90
bb488185
MD
91/*
92 * malloc/free are reusing memory areas too quickly, which does not let us
93 * test races appropriately. Use a large circular array for allocations.
94 * ARRAY_SIZE is larger than NR_WRITE, which insures we never run over our tail.
95 */
96#define ARRAY_SIZE (1048576 * NR_WRITE)
97#define ARRAY_POISON 0xDEADBEEF
98static int array_index;
99static struct test_array test_array[ARRAY_SIZE];
100
101static struct test_array *test_array_alloc(void)
102{
103 struct test_array *ret;
104 int index;
105
106 rcu_copy_mutex_lock();
107 index = array_index % ARRAY_SIZE;
108 assert(test_array[index].a == ARRAY_POISON ||
109 test_array[index].a == 0);
110 ret = &test_array[index];
111 array_index++;
112 if (array_index == ARRAY_SIZE)
113 array_index = 0;
114 rcu_copy_mutex_unlock();
115 return ret;
116}
117
118static void test_array_free(struct test_array *ptr)
119{
120 if (!ptr)
121 return;
122 rcu_copy_mutex_lock();
123 ptr->a = ARRAY_POISON;
124 rcu_copy_mutex_unlock();
125}
126
f69f195a
MD
127void *thr_reader(void *arg)
128{
41718ff9
MD
129 struct test_array *local_ptr;
130
cf380c2f 131 printf("thread_begin %s, thread id : %lx, tid %lu\n",
87bd15cd 132 "reader", pthread_self(), (unsigned long)gettid());
f69f195a
MD
133
134 urcu_register_thread();
135
cf380c2f 136 for (;;) {
1430ee0b 137 rcu_read_lock();
cf380c2f 138 local_ptr = rcu_dereference(test_rcu_pointer);
bb488185 139 debug_yield_read();
cf380c2f
MD
140 if (local_ptr)
141 assert(local_ptr->a == 8);
1430ee0b 142 rcu_read_unlock();
cf380c2f
MD
143 if (!test_duration())
144 break;
41718ff9 145 }
f69f195a
MD
146
147 urcu_unregister_thread();
41718ff9 148
cf380c2f
MD
149 printf("thread_end %s, thread id : %lx, tid %lu\n",
150 "reader", pthread_self(), (unsigned long)gettid());
f69f195a
MD
151 return ((void*)1);
152
153}
154
155void *thr_writer(void *arg)
156{
41718ff9 157 struct test_array *new, *old;
f69f195a 158
cf380c2f 159 printf("thread_begin %s, thread id : %lx, tid %lu\n",
87bd15cd 160 "writer", pthread_self(), (unsigned long)gettid());
f69f195a 161
cf380c2f 162 for (;;) {
bb488185 163 new = test_array_alloc();
c265818b 164 rcu_copy_mutex_lock();
41718ff9 165 old = test_rcu_pointer;
cf380c2f 166 if (old)
41718ff9 167 assert(old->a == 8);
ad6ce6ae 168 new->a = 8;
f4a486ac 169 old = urcu_publish_content(&test_rcu_pointer, new);
c265818b 170 rcu_copy_mutex_unlock();
41718ff9 171 /* can be done after unlock */
cf380c2f 172 if (old)
8c8eed97 173 old->a = 0;
bb488185 174 test_array_free(old);
cf380c2f
MD
175 if (!test_duration())
176 break;
bb488185
MD
177 if (!no_writer_delay)
178 usleep(1);
f69f195a
MD
179 }
180
cf380c2f
MD
181 printf("thread_end %s, thread id : %lx, tid %lu\n",
182 "writer", pthread_self(), (unsigned long)gettid());
f69f195a
MD
183 return ((void*)2);
184}
ac260fd9 185
1430ee0b
MD
186void show_usage(int argc, char **argv)
187{
188 printf("Usage : %s duration (s)", argv[0]);
189#ifdef DEBUG_YIELD
190 printf(" [-r] [-w] (yield reader and/or writer)");
191#endif
bb488185 192 printf(" [-n] (disable writer delay)");
1430ee0b
MD
193 printf("\n");
194}
195
cf380c2f 196int main(int argc, char **argv)
ac260fd9 197{
f69f195a
MD
198 int err;
199 pthread_t tid_reader[NR_READ], tid_writer[NR_WRITE];
200 void *tret;
201 int i;
202
cf380c2f 203 if (argc < 2) {
1430ee0b 204 show_usage(argc, argv);
cf380c2f
MD
205 return -1;
206 }
207
208 err = sscanf(argv[1], "%lu", &duration);
209 if (err != 1) {
1430ee0b 210 show_usage(argc, argv);
cf380c2f
MD
211 return -1;
212 }
213
cf380c2f
MD
214 for (i = 2; i < argc; i++) {
215 if (argv[i][0] != '-')
216 continue;
217 switch (argv[i][1]) {
bb488185 218#ifdef DEBUG_YIELD
cf380c2f
MD
219 case 'r':
220 yield_active |= YIELD_READ;
221 break;
222 case 'w':
223 yield_active |= YIELD_WRITE;
224 break;
bb488185
MD
225#endif
226 case 'n':
227 no_writer_delay = 1;
228 break;
cf380c2f
MD
229 }
230 }
cf380c2f
MD
231
232 printf("running test for %lu seconds.\n", duration);
233 start_time = time(NULL);
87bd15cd
BW
234 printf("thread %-6s, thread id : %lx, tid %lu\n",
235 "main", pthread_self(), (unsigned long)gettid());
236
f69f195a
MD
237 for (i = 0; i < NR_READ; i++) {
238 err = pthread_create(&tid_reader[i], NULL, thr_reader, NULL);
239 if (err != 0)
240 exit(1);
241 }
242 for (i = 0; i < NR_WRITE; i++) {
243 err = pthread_create(&tid_writer[i], NULL, thr_writer, NULL);
244 if (err != 0)
245 exit(1);
246 }
247
20bf310a 248 for (i = 0; i < NR_READ; i++) {
f69f195a
MD
249 err = pthread_join(tid_reader[i], &tret);
250 if (err != 0)
251 exit(1);
252 }
253 for (i = 0; i < NR_WRITE; i++) {
254 err = pthread_join(tid_writer[i], &tret);
255 if (err != 0)
256 exit(1);
257 }
bb488185 258 test_array_free(test_rcu_pointer);
ac260fd9 259
f69f195a 260 return 0;
ac260fd9 261}
This page took 0.033262 seconds and 4 git commands to generate.