]> git.proxmox.com Git - ovs.git/blame - tests/test-atomic.c
raft: Fix the problem of stuck in candidate role forever.
[ovs.git] / tests / test-atomic.c
CommitLineData
31a3fc6e 1/*
8917f72c 2 * Copyright (c) 2013, 2014 Nicira, Inc.
31a3fc6e
BP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
3f636c7e 18#undef NDEBUG
d2843eba 19#include "fatal-signal.h"
31a3fc6e 20#include "ovs-atomic.h"
eadd1644 21#include "ovstest.h"
eba451dc 22#include "ovs-thread.h"
da692cbd
JR
23#include "timeval.h"
24#include "util.h"
25#include "openvswitch/vlog.h"
26
27VLOG_DEFINE_THIS_MODULE(test_atomic);
31a3fc6e
BP
28
29#define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE) \
30 { \
31 ATOMIC_TYPE x = ATOMIC_VAR_INIT(1); \
6ba7f5cc 32 BASE_TYPE value, orig; \
31a3fc6e
BP
33 \
34 atomic_read(&x, &value); \
35 ovs_assert(value == 1); \
36 \
37 atomic_store(&x, 2); \
38 atomic_read(&x, &value); \
39 ovs_assert(value == 2); \
40 \
41 atomic_init(&x, 3); \
42 atomic_read(&x, &value); \
43 ovs_assert(value == 3); \
6ba7f5cc
BP
44 \
45 atomic_add(&x, 1, &orig); \
46 ovs_assert(orig == 3); \
47 atomic_read(&x, &value); \
48 ovs_assert(value == 4); \
49 \
50 atomic_sub(&x, 2, &orig); \
51 ovs_assert(orig == 4); \
52 atomic_read(&x, &value); \
53 ovs_assert(value == 2); \
54 \
55 atomic_or(&x, 6, &orig); \
56 ovs_assert(orig == 2); \
57 atomic_read(&x, &value); \
58 ovs_assert(value == 6); \
59 \
60 atomic_and(&x, 10, &orig); \
61 ovs_assert(orig == 6); \
62 atomic_read(&x, &value); \
63 ovs_assert(value == 2); \
64 \
65 atomic_xor(&x, 10, &orig); \
66 ovs_assert(orig == 2); \
67 atomic_read(&x, &value); \
68 ovs_assert(value == 8); \
31a3fc6e
BP
69 }
70
eba451dc
JR
71#define TEST_ATOMIC_TYPE_EXPLICIT(ATOMIC_TYPE, BASE_TYPE, \
72 ORDER_READ, ORDER_STORE, ORDER_RMW) \
73 { \
74 ATOMIC_TYPE x = ATOMIC_VAR_INIT(1); \
75 BASE_TYPE value, orig; \
76 \
77 atomic_read_explicit(&x, &value, ORDER_READ); \
78 ovs_assert(value == 1); \
79 \
80 atomic_store_explicit(&x, 2, ORDER_STORE); \
81 atomic_read_explicit(&x, &value, ORDER_READ); \
82 ovs_assert(value == 2); \
83 \
84 atomic_init(&x, 3); \
85 atomic_read_explicit(&x, &value, ORDER_READ); \
86 ovs_assert(value == 3); \
87 \
88 atomic_add_explicit(&x, 1, &orig, ORDER_RMW); \
89 ovs_assert(orig == 3); \
90 atomic_read_explicit(&x, &value, ORDER_READ); \
91 ovs_assert(value == 4); \
92 \
93 atomic_sub_explicit(&x, 2, &orig, ORDER_RMW); \
94 ovs_assert(orig == 4); \
95 atomic_read_explicit(&x, &value, ORDER_READ); \
96 ovs_assert(value == 2); \
97 \
98 atomic_or_explicit(&x, 6, &orig, ORDER_RMW); \
99 ovs_assert(orig == 2); \
100 atomic_read_explicit(&x, &value, ORDER_READ); \
101 ovs_assert(value == 6); \
102 \
103 atomic_and_explicit(&x, 10, &orig, ORDER_RMW); \
104 ovs_assert(orig == 6); \
105 atomic_read_explicit(&x, &value, ORDER_READ); \
106 ovs_assert(value == 2); \
107 \
108 atomic_xor_explicit(&x, 10, &orig, ORDER_RMW); \
109 ovs_assert(orig == 2); \
110 atomic_read_explicit(&x, &value, ORDER_READ); \
111 ovs_assert(value == 8); \
112 }
113
114
115#define TEST_ATOMIC_ORDER(ORDER_READ, ORDER_STORE, ORDER_RMW) \
116 { \
117 TEST_ATOMIC_TYPE_EXPLICIT(atomic_char, char, \
118 ORDER_READ, ORDER_STORE, ORDER_RMW); \
119 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uchar, unsigned char, \
120 ORDER_READ, ORDER_STORE, ORDER_RMW); \
121 TEST_ATOMIC_TYPE_EXPLICIT(atomic_schar, signed char, \
122 ORDER_READ, ORDER_STORE, ORDER_RMW); \
123 TEST_ATOMIC_TYPE_EXPLICIT(atomic_short, short, \
124 ORDER_READ, ORDER_STORE, ORDER_RMW); \
125 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ushort, unsigned short, \
126 ORDER_READ, ORDER_STORE, ORDER_RMW); \
127 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int, int, \
128 ORDER_READ, ORDER_STORE, ORDER_RMW); \
129 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint, unsigned int, \
130 ORDER_READ, ORDER_STORE, ORDER_RMW); \
131 TEST_ATOMIC_TYPE_EXPLICIT(atomic_long, long int, \
132 ORDER_READ, ORDER_STORE, ORDER_RMW); \
133 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ulong, unsigned long int, \
134 ORDER_READ, ORDER_STORE, ORDER_RMW); \
135 TEST_ATOMIC_TYPE_EXPLICIT(atomic_llong, long long int, \
136 ORDER_READ, ORDER_STORE, ORDER_RMW); \
137 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ullong, unsigned long long int, \
138 ORDER_READ, ORDER_STORE, ORDER_RMW); \
139 TEST_ATOMIC_TYPE_EXPLICIT(atomic_size_t, size_t, \
140 ORDER_READ, ORDER_STORE, ORDER_RMW); \
141 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ptrdiff_t, ptrdiff_t, \
142 ORDER_READ, ORDER_STORE, ORDER_RMW); \
143 TEST_ATOMIC_TYPE_EXPLICIT(atomic_intmax_t, intmax_t, \
144 ORDER_READ, ORDER_STORE, ORDER_RMW); \
145 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintmax_t, uintmax_t, \
146 ORDER_READ, ORDER_STORE, ORDER_RMW); \
147 TEST_ATOMIC_TYPE_EXPLICIT(atomic_intptr_t, intptr_t, \
148 ORDER_READ, ORDER_STORE, ORDER_RMW); \
149 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintptr_t, uintptr_t, \
150 ORDER_READ, ORDER_STORE, ORDER_RMW); \
151 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint8_t, uint8_t, \
152 ORDER_READ, ORDER_STORE, ORDER_RMW); \
153 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int8_t, int8_t, \
154 ORDER_READ, ORDER_STORE, ORDER_RMW); \
155 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint16_t, uint16_t, \
156 ORDER_READ, ORDER_STORE, ORDER_RMW); \
157 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int16_t, int16_t, \
158 ORDER_READ, ORDER_STORE, ORDER_RMW); \
159 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint32_t, uint32_t, \
160 ORDER_READ, ORDER_STORE, ORDER_RMW); \
161 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int32_t, int32_t, \
162 ORDER_READ, ORDER_STORE, ORDER_RMW); \
163 }
164
13d94ee9
AW
165static void
166test_atomic_flag(void)
167{
168 atomic_flag flag = ATOMIC_FLAG_INIT;
169 ovs_assert(atomic_flag_test_and_set(&flag) == false);
22eb07cd 170 ovs_assert(atomic_flag_test_and_set(&flag) == true);
13d94ee9 171 atomic_flag_clear(&flag);
22eb07cd 172 ovs_assert(atomic_flag_test_and_set(&flag) == false);
13d94ee9
AW
173}
174
fb42720e 175static uint32_t a;
eba451dc
JR
176
177struct atomic_aux {
55eebc01 178 ATOMIC(uint64_t) count;
eba451dc
JR
179 uint32_t b;
180 ATOMIC(uint32_t *) data;
55eebc01 181 ATOMIC(uint64_t) data64;
eba451dc
JR
182};
183
fb42720e 184static ATOMIC(struct atomic_aux *) paux = ATOMIC_VAR_INIT(NULL);
eba451dc
JR
185static struct atomic_aux *auxes = NULL;
186
187#define ATOMIC_ITEM_COUNT 1000000
1593af75 188#define DURATION 5000
eba451dc
JR
189
190static void *
191atomic_consumer(void * arg1 OVS_UNUSED)
192{
193 struct atomic_aux *old_aux = NULL;
55eebc01 194 uint64_t count;
1593af75 195 long long int stop_time = time_msec() + DURATION;
eba451dc
JR
196
197 do {
198 struct atomic_aux *aux;
199 uint32_t b;
200
201 /* Wait for a new item. We may not be fast enough to process every
202 * item, but we are guaranteed to see the last one. */
203 do {
204 atomic_read_explicit(&paux, &aux, memory_order_consume);
205 } while (aux == old_aux);
206
207 b = aux->b;
208 atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
209 ovs_assert(b == count + 42);
210
211 old_aux = aux;
da692cbd
JR
212 } while (count < ATOMIC_ITEM_COUNT - 1 && time_msec() < stop_time);
213
214 if (time_msec() >= stop_time) {
215 if (count < 10) {
216 VLOG_WARN("atomic_consumer test stopped due to excessive runtime. "
217 "Count = %"PRIu64, count);
218 }
219 }
eba451dc
JR
220
221 return NULL;
222}
223
224static void *
225atomic_producer(void * arg1 OVS_UNUSED)
226{
227 size_t i;
228
229 for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
230 struct atomic_aux *aux = &auxes[i];
231
232 aux->count = ATOMIC_VAR_INIT(i);
233 aux->b = i + 42;
234
235 /* Publish the new item. */
236 atomic_store_explicit(&paux, aux, memory_order_release);
237 }
238
239 return NULL;
240}
eadd1644
AZ
241
242static void
eba451dc
JR
243test_cons_rel(void)
244{
245 pthread_t reader, writer;
246
247 atomic_init(&paux, NULL);
248
249 auxes = xmalloc(sizeof *auxes * ATOMIC_ITEM_COUNT);
250
251 reader = ovs_thread_create("consumer", atomic_consumer, NULL);
252 writer = ovs_thread_create("producer", atomic_producer, NULL);
253
254 xpthread_join(reader, NULL);
255 xpthread_join(writer, NULL);
256
257 free(auxes);
258}
259
260static void *
261atomic_reader(void *aux_)
262{
263 struct atomic_aux *aux = aux_;
55eebc01
JR
264 uint64_t count;
265 uint64_t data;
da692cbd 266 long long int now = time_msec();
1593af75 267 long long int stop_time = now + DURATION;
eba451dc
JR
268
269 do {
270 /* Non-synchronized add. */
271 atomic_add_explicit(&aux->count, 1, &count, memory_order_relaxed);
272
273 do {
55eebc01 274 atomic_read_explicit(&aux->data64, &data, memory_order_acquire);
da692cbd
JR
275 } while (!data && (now = time_msec()) < stop_time);
276
277 if (now >= stop_time) {
278 if (count < 10) {
279 VLOG_WARN("atomic_reader test stopped due to excessive "
280 "runtime. Count = %"PRIu64, count);
281 }
282 break;
283 }
eba451dc 284
55eebc01 285 ovs_assert(data == a && data == aux->b && a == aux->b);
eba451dc
JR
286
287 atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
288
55eebc01 289 ovs_assert(count == 2 * a && count == 2 * aux->b && count == 2 * data);
eba451dc 290
55eebc01 291 atomic_store_explicit(&aux->data64, UINT64_C(0), memory_order_release);
eba451dc
JR
292 } while (count < 2 * ATOMIC_ITEM_COUNT);
293
294 return NULL;
295}
296
297static void *
298atomic_writer(void *aux_)
299{
300 struct atomic_aux *aux = aux_;
55eebc01
JR
301 uint64_t old_count;
302 uint64_t data;
eba451dc 303 size_t i;
da692cbd 304 long long int now = time_msec();
1593af75 305 long long int stop_time = now + DURATION;
eba451dc
JR
306
307 for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
308 /* Wait for the reader to be done with the data. */
309 do {
55eebc01 310 atomic_read_explicit(&aux->data64, &data, memory_order_acquire);
da692cbd
JR
311 } while (data && (now = time_msec()) < stop_time);
312
313 if (now >= stop_time) {
314 if (i < 10) {
315 VLOG_WARN("atomic_writer test stopped due to excessive "
316 "runtime, Count = %"PRIuSIZE, i);
317 }
318 break;
319 }
eba451dc
JR
320
321 a = i + 1;
322 atomic_add_explicit(&aux->count, 1, &old_count, memory_order_relaxed);
323 aux->b++;
55eebc01
JR
324 atomic_store_explicit(&aux->data64,
325 (i & 1) ? (uint64_t)aux->b : a, memory_order_release);
eba451dc
JR
326 }
327
328 return NULL;
329}
330
331static void
332test_acq_rel(void)
333{
334 pthread_t reader, writer;
335 struct atomic_aux *aux = xmalloc(sizeof *aux);
336
337 a = 0;
338 aux->b = 0;
339
340 aux->count = ATOMIC_VAR_INIT(0);
341 atomic_init(&aux->data, NULL);
55eebc01 342 aux->data64 = ATOMIC_VAR_INIT(0);
eba451dc
JR
343
344 reader = ovs_thread_create("reader", atomic_reader, aux);
345 writer = ovs_thread_create("writer", atomic_writer, aux);
346
347 xpthread_join(reader, NULL);
348 xpthread_join(writer, NULL);
349 free(aux);
350}
351
352static void
353test_atomic_plain(void)
31a3fc6e
BP
354{
355 TEST_ATOMIC_TYPE(atomic_char, char);
356 TEST_ATOMIC_TYPE(atomic_uchar, unsigned char);
357 TEST_ATOMIC_TYPE(atomic_schar, signed char);
358 TEST_ATOMIC_TYPE(atomic_short, short);
359 TEST_ATOMIC_TYPE(atomic_ushort, unsigned short);
360 TEST_ATOMIC_TYPE(atomic_int, int);
361 TEST_ATOMIC_TYPE(atomic_uint, unsigned int);
362 TEST_ATOMIC_TYPE(atomic_long, long int);
363 TEST_ATOMIC_TYPE(atomic_ulong, unsigned long int);
364 TEST_ATOMIC_TYPE(atomic_llong, long long int);
365 TEST_ATOMIC_TYPE(atomic_ullong, unsigned long long int);
366 TEST_ATOMIC_TYPE(atomic_size_t, size_t);
367 TEST_ATOMIC_TYPE(atomic_ptrdiff_t, ptrdiff_t);
368 TEST_ATOMIC_TYPE(atomic_intmax_t, intmax_t);
369 TEST_ATOMIC_TYPE(atomic_uintmax_t, uintmax_t);
370 TEST_ATOMIC_TYPE(atomic_intptr_t, intptr_t);
371 TEST_ATOMIC_TYPE(atomic_uintptr_t, uintptr_t);
372 TEST_ATOMIC_TYPE(atomic_uint8_t, uint8_t);
373 TEST_ATOMIC_TYPE(atomic_int8_t, int8_t);
374 TEST_ATOMIC_TYPE(atomic_uint16_t, uint16_t);
375 TEST_ATOMIC_TYPE(atomic_int16_t, int16_t);
376 TEST_ATOMIC_TYPE(atomic_uint32_t, uint32_t);
377 TEST_ATOMIC_TYPE(atomic_int32_t, int32_t);
4a0c670a
BP
378 TEST_ATOMIC_TYPE(atomic_uint64_t, uint64_t);
379 TEST_ATOMIC_TYPE(atomic_int64_t, int64_t);
eba451dc
JR
380}
381
382static void
383test_atomic_relaxed(void)
384{
385 TEST_ATOMIC_ORDER(memory_order_relaxed, memory_order_relaxed,
386 memory_order_relaxed);
387}
388
389static void
390test_atomic_consume(void)
391{
392 TEST_ATOMIC_ORDER(memory_order_consume, memory_order_release,
393 memory_order_release);
394}
395
396static void
397test_atomic_acquire(void)
398{
399 TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
400 memory_order_release);
401}
402
403static void
404test_atomic_acq_rel(void)
405{
406 TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
407 memory_order_acq_rel);
408}
409
410static void
411test_atomic_seq_cst(void)
412{
413 TEST_ATOMIC_ORDER(memory_order_seq_cst, memory_order_seq_cst,
414 memory_order_seq_cst);
415}
416
417static void
418test_atomic_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
419{
d2843eba 420 fatal_signal_init();
eba451dc
JR
421 test_atomic_plain();
422 test_atomic_relaxed();
423 test_atomic_consume();
424 test_atomic_acquire();
425 test_atomic_acq_rel();
426 test_atomic_seq_cst();
31a3fc6e 427
13d94ee9 428 test_atomic_flag();
eba451dc
JR
429
430 test_acq_rel();
431 test_cons_rel();
31a3fc6e 432}
eadd1644
AZ
433
434OVSTEST_REGISTER("test-atomic", test_atomic_main);