Make sure the rwlock and per thread lock could detect races
[urcu.git] / test_rwlock.c
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 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #include <stdio.h>
24 #include <pthread.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <assert.h>
32 #include <sys/syscall.h>
33
34 #include "arch.h"
35
36 #if defined(_syscall0)
37 _syscall0(pid_t, gettid)
38 #elif defined(__NR_gettid)
39 static inline pid_t gettid(void)
40 {
41 return syscall(__NR_gettid);
42 }
43 #else
44 #warning "use pid as tid"
45 static inline pid_t gettid(void)
46 {
47 return getpid();
48 }
49 #endif
50
51 #ifndef DYNAMIC_LINK_TEST
52 #define _LGPL_SOURCE
53 #else
54 #define debug_yield_read()
55 #endif
56 #include "urcu.h"
57
58 struct test_array {
59 int a;
60 };
61
62 pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
63
64 static volatile int test_go, test_stop;
65
66 static int wdelay;
67
68 static volatile struct test_array test_array = { 8 };
69
70 static unsigned long duration;
71
72 /*
73 * returns 0 if test should end.
74 */
75 static int test_duration_write(void)
76 {
77 return !test_stop;
78 }
79
80 static int test_duration_read(void)
81 {
82 return !test_stop;
83 }
84
85 static unsigned long long __thread nr_writes;
86 static unsigned long long __thread nr_reads;
87
88 static unsigned int nr_readers;
89 static unsigned int nr_writers;
90
91 pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
92
93 void rcu_copy_mutex_lock(void)
94 {
95 int ret;
96 ret = pthread_mutex_lock(&rcu_copy_mutex);
97 if (ret) {
98 perror("Error in pthread mutex lock");
99 exit(-1);
100 }
101 }
102
103 void rcu_copy_mutex_unlock(void)
104 {
105 int ret;
106
107 ret = pthread_mutex_unlock(&rcu_copy_mutex);
108 if (ret) {
109 perror("Error in pthread mutex unlock");
110 exit(-1);
111 }
112 }
113
114 void *thr_reader(void *_count)
115 {
116 unsigned long long *count = _count;
117
118 printf("thread_begin %s, thread id : %lx, tid %lu\n",
119 "reader", pthread_self(), (unsigned long)gettid());
120
121 while (!test_go)
122 {
123 }
124
125 for (;;) {
126 pthread_rwlock_rdlock(&lock);
127 assert(test_array.a == 8);
128 pthread_rwlock_unlock(&lock);
129 nr_reads++;
130 if (!test_duration_read())
131 break;
132 }
133
134 *count = nr_reads;
135 printf("thread_end %s, thread id : %lx, tid %lu\n",
136 "reader", pthread_self(), (unsigned long)gettid());
137 return ((void*)1);
138
139 }
140
141 void *thr_writer(void *_count)
142 {
143 unsigned long long *count = _count;
144
145 printf("thread_begin %s, thread id : %lx, tid %lu\n",
146 "writer", pthread_self(), (unsigned long)gettid());
147
148 while (!test_go)
149 {
150 }
151 smp_mb();
152
153 for (;;) {
154 pthread_rwlock_wrlock(&lock);
155 test_array.a = 0;
156 test_array.a = 8;
157 pthread_rwlock_unlock(&lock);
158 nr_writes++;
159 if (!test_duration_write())
160 break;
161 if (wdelay)
162 usleep(wdelay);
163 }
164
165 printf("thread_end %s, thread id : %lx, tid %lu\n",
166 "writer", pthread_self(), (unsigned long)gettid());
167 *count = nr_writes;
168 return ((void*)2);
169 }
170
171 void show_usage(int argc, char **argv)
172 {
173 printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]);
174 #ifdef DEBUG_YIELD
175 printf(" [-r] [-w] (yield reader and/or writer)");
176 #endif
177 printf(" [-d delay] (writer period (us))");
178 printf("\n");
179 }
180
181 int main(int argc, char **argv)
182 {
183 int err;
184 pthread_t *tid_reader, *tid_writer;
185 void *tret;
186 unsigned long long *count_reader, *count_writer;
187 unsigned long long tot_reads = 0, tot_writes = 0;
188 int i;
189
190 if (argc < 4) {
191 show_usage(argc, argv);
192 return -1;
193 }
194 smp_mb();
195
196 err = sscanf(argv[1], "%u", &nr_readers);
197 if (err != 1) {
198 show_usage(argc, argv);
199 return -1;
200 }
201
202 err = sscanf(argv[2], "%u", &nr_writers);
203 if (err != 1) {
204 show_usage(argc, argv);
205 return -1;
206 }
207
208 err = sscanf(argv[3], "%lu", &duration);
209 if (err != 1) {
210 show_usage(argc, argv);
211 return -1;
212 }
213
214 for (i = 4; 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 'd':
227 if (argc < i + 2) {
228 show_usage(argc, argv);
229 return -1;
230 }
231 wdelay = atoi(argv[++i]);
232 break;
233 }
234 }
235
236 printf("running test for %lu seconds, %u readers, %u writers.\n",
237 duration, nr_readers, nr_writers);
238 printf("Writer delay : %u us.\n", wdelay);
239 printf("thread %-6s, thread id : %lx, tid %lu\n",
240 "main", pthread_self(), (unsigned long)gettid());
241
242 tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
243 tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
244 count_reader = malloc(sizeof(*count_reader) * nr_readers);
245 count_writer = malloc(sizeof(*count_writer) * nr_writers);
246
247 for (i = 0; i < nr_readers; i++) {
248 err = pthread_create(&tid_reader[i], NULL, thr_reader,
249 &count_reader[i]);
250 if (err != 0)
251 exit(1);
252 }
253 for (i = 0; i < nr_writers; i++) {
254 err = pthread_create(&tid_writer[i], NULL, thr_writer,
255 &count_writer[i]);
256 if (err != 0)
257 exit(1);
258 }
259
260 smp_mb();
261
262 test_go = 1;
263
264 sleep(duration);
265
266 test_stop = 1;
267
268 for (i = 0; i < nr_readers; i++) {
269 err = pthread_join(tid_reader[i], &tret);
270 if (err != 0)
271 exit(1);
272 tot_reads += count_reader[i];
273 }
274 for (i = 0; i < nr_writers; i++) {
275 err = pthread_join(tid_writer[i], &tret);
276 if (err != 0)
277 exit(1);
278 tot_writes += count_writer[i];
279 }
280
281 printf("total number of reads : %llu, writes %llu\n", tot_reads,
282 tot_writes);
283 free(tid_reader);
284 free(tid_writer);
285 free(count_reader);
286 free(count_writer);
287 return 0;
288 }
This page took 0.049566 seconds and 4 git commands to generate.