Fix force_mb_all_threads must be called within internal local
[urcu.git] / test_urcu.c
... / ...
CommitLineData
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
11#include <stdio.h>
12#include <pthread.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/types.h>
16#include <sys/wait.h>
17#include <unistd.h>
18#include <stdio.h>
19#include <assert.h>
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
37#include "urcu.h"
38
39struct test_array {
40 int a;
41};
42
43static int no_writer_delay;
44
45static struct test_array *test_rcu_pointer;
46
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
65#define NR_READ 10
66#define NR_WRITE 9
67
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}
90
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
127void *thr_reader(void *arg)
128{
129 struct test_array *local_ptr;
130
131 printf("thread_begin %s, thread id : %lx, tid %lu\n",
132 "reader", pthread_self(), (unsigned long)gettid());
133
134 urcu_register_thread();
135
136 for (;;) {
137 rcu_read_lock();
138 local_ptr = rcu_dereference(test_rcu_pointer);
139 debug_yield_read();
140 if (local_ptr)
141 assert(local_ptr->a == 8);
142 rcu_read_unlock();
143 if (!test_duration())
144 break;
145 }
146
147 urcu_unregister_thread();
148
149 printf("thread_end %s, thread id : %lx, tid %lu\n",
150 "reader", pthread_self(), (unsigned long)gettid());
151 return ((void*)1);
152
153}
154
155void *thr_writer(void *arg)
156{
157 struct test_array *new, *old;
158
159 printf("thread_begin %s, thread id : %lx, tid %lu\n",
160 "writer", pthread_self(), (unsigned long)gettid());
161
162 for (;;) {
163 new = test_array_alloc();
164 rcu_copy_mutex_lock();
165 old = test_rcu_pointer;
166 if (old)
167 assert(old->a == 8);
168 new->a = 8;
169 old = urcu_publish_content(&test_rcu_pointer, new);
170 rcu_copy_mutex_unlock();
171 /* can be done after unlock */
172 if (old)
173 old->a = 0;
174 test_array_free(old);
175 if (!test_duration())
176 break;
177 if (!no_writer_delay)
178 usleep(1);
179 }
180
181 printf("thread_end %s, thread id : %lx, tid %lu\n",
182 "writer", pthread_self(), (unsigned long)gettid());
183 return ((void*)2);
184}
185
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
192 printf(" [-n] (disable writer delay)");
193 printf("\n");
194}
195
196int main(int argc, char **argv)
197{
198 int err;
199 pthread_t tid_reader[NR_READ], tid_writer[NR_WRITE];
200 void *tret;
201 int i;
202
203 if (argc < 2) {
204 show_usage(argc, argv);
205 return -1;
206 }
207
208 err = sscanf(argv[1], "%lu", &duration);
209 if (err != 1) {
210 show_usage(argc, argv);
211 return -1;
212 }
213
214 for (i = 2; i < argc; i++) {
215 if (argv[i][0] != '-')
216 continue;
217 switch (argv[i][1]) {
218#ifdef DEBUG_YIELD
219 case 'r':
220 yield_active |= YIELD_READ;
221 break;
222 case 'w':
223 yield_active |= YIELD_WRITE;
224 break;
225#endif
226 case 'n':
227 no_writer_delay = 1;
228 break;
229 }
230 }
231
232 printf("running test for %lu seconds.\n", duration);
233 start_time = time(NULL);
234 printf("thread %-6s, thread id : %lx, tid %lu\n",
235 "main", pthread_self(), (unsigned long)gettid());
236
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
248 for (i = 0; i < NR_READ; i++) {
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 }
258 test_array_free(test_rcu_pointer);
259
260 return 0;
261}
This page took 0.024405 seconds and 4 git commands to generate.