]>
git.proxmox.com Git - ovs.git/blob - tests/test-atomic.c
2 * Copyright (c) 2013, 2014 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "fatal-signal.h"
20 #include "ovs-atomic.h"
22 #include "ovs-thread.h"
25 #include "openvswitch/vlog.h"
27 VLOG_DEFINE_THIS_MODULE(test_atomic
);
29 #define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE) \
31 ATOMIC_TYPE x = ATOMIC_VAR_INIT(1); \
32 BASE_TYPE value, orig; \
34 atomic_read(&x, &value); \
35 ovs_assert(value == 1); \
37 atomic_store(&x, 2); \
38 atomic_read(&x, &value); \
39 ovs_assert(value == 2); \
42 atomic_read(&x, &value); \
43 ovs_assert(value == 3); \
45 atomic_add(&x, 1, &orig); \
46 ovs_assert(orig == 3); \
47 atomic_read(&x, &value); \
48 ovs_assert(value == 4); \
50 atomic_sub(&x, 2, &orig); \
51 ovs_assert(orig == 4); \
52 atomic_read(&x, &value); \
53 ovs_assert(value == 2); \
55 atomic_or(&x, 6, &orig); \
56 ovs_assert(orig == 2); \
57 atomic_read(&x, &value); \
58 ovs_assert(value == 6); \
60 atomic_and(&x, 10, &orig); \
61 ovs_assert(orig == 6); \
62 atomic_read(&x, &value); \
63 ovs_assert(value == 2); \
65 atomic_xor(&x, 10, &orig); \
66 ovs_assert(orig == 2); \
67 atomic_read(&x, &value); \
68 ovs_assert(value == 8); \
71 #define TEST_ATOMIC_TYPE_EXPLICIT(ATOMIC_TYPE, BASE_TYPE, \
72 ORDER_READ, ORDER_STORE, ORDER_RMW) \
74 ATOMIC_TYPE x = ATOMIC_VAR_INIT(1); \
75 BASE_TYPE value, orig; \
77 atomic_read_explicit(&x, &value, ORDER_READ); \
78 ovs_assert(value == 1); \
80 atomic_store_explicit(&x, 2, ORDER_STORE); \
81 atomic_read_explicit(&x, &value, ORDER_READ); \
82 ovs_assert(value == 2); \
85 atomic_read_explicit(&x, &value, ORDER_READ); \
86 ovs_assert(value == 3); \
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); \
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); \
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); \
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); \
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); \
115 #define TEST_ATOMIC_ORDER(ORDER_READ, ORDER_STORE, ORDER_RMW) \
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); \
166 test_atomic_flag(void)
168 atomic_flag flag
= ATOMIC_FLAG_INIT
;
169 ovs_assert(atomic_flag_test_and_set(&flag
) == false);
170 ovs_assert(atomic_flag_test_and_set(&flag
) == true);
171 atomic_flag_clear(&flag
);
172 ovs_assert(atomic_flag_test_and_set(&flag
) == false);
178 ATOMIC(uint64_t) count
;
180 ATOMIC(uint32_t *) data
;
181 ATOMIC(uint64_t) data64
;
184 static ATOMIC(struct atomic_aux
*) paux
= ATOMIC_VAR_INIT(NULL
);
185 static struct atomic_aux
*auxes
= NULL
;
187 #define ATOMIC_ITEM_COUNT 1000000
188 #define DURATION 5000
191 atomic_consumer(void * arg1 OVS_UNUSED
)
193 struct atomic_aux
*old_aux
= NULL
;
195 long long int stop_time
= time_msec() + DURATION
;
198 struct atomic_aux
*aux
;
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. */
204 atomic_read_explicit(&paux
, &aux
, memory_order_consume
);
205 } while (aux
== old_aux
);
208 atomic_read_explicit(&aux
->count
, &count
, memory_order_relaxed
);
209 ovs_assert(b
== count
+ 42);
212 } while (count
< ATOMIC_ITEM_COUNT
- 1 && time_msec() < stop_time
);
214 if (time_msec() >= stop_time
) {
216 VLOG_WARN("atomic_consumer test stopped due to excessive runtime. "
217 "Count = %"PRIu64
, count
);
225 atomic_producer(void * arg1 OVS_UNUSED
)
229 for (i
= 0; i
< ATOMIC_ITEM_COUNT
; i
++) {
230 struct atomic_aux
*aux
= &auxes
[i
];
232 aux
->count
= ATOMIC_VAR_INIT(i
);
235 /* Publish the new item. */
236 atomic_store_explicit(&paux
, aux
, memory_order_release
);
245 pthread_t reader
, writer
;
247 atomic_init(&paux
, NULL
);
249 auxes
= xmalloc(sizeof *auxes
* ATOMIC_ITEM_COUNT
);
251 reader
= ovs_thread_create("consumer", atomic_consumer
, NULL
);
252 writer
= ovs_thread_create("producer", atomic_producer
, NULL
);
254 xpthread_join(reader
, NULL
);
255 xpthread_join(writer
, NULL
);
261 atomic_reader(void *aux_
)
263 struct atomic_aux
*aux
= aux_
;
266 long long int now
= time_msec();
267 long long int stop_time
= now
+ DURATION
;
270 /* Non-synchronized add. */
271 atomic_add_explicit(&aux
->count
, 1, &count
, memory_order_relaxed
);
274 atomic_read_explicit(&aux
->data64
, &data
, memory_order_acquire
);
275 } while (!data
&& (now
= time_msec()) < stop_time
);
277 if (now
>= stop_time
) {
279 VLOG_WARN("atomic_reader test stopped due to excessive "
280 "runtime. Count = %"PRIu64
, count
);
285 ovs_assert(data
== a
&& data
== aux
->b
&& a
== aux
->b
);
287 atomic_read_explicit(&aux
->count
, &count
, memory_order_relaxed
);
289 ovs_assert(count
== 2 * a
&& count
== 2 * aux
->b
&& count
== 2 * data
);
291 atomic_store_explicit(&aux
->data64
, UINT64_C(0), memory_order_release
);
292 } while (count
< 2 * ATOMIC_ITEM_COUNT
);
298 atomic_writer(void *aux_
)
300 struct atomic_aux
*aux
= aux_
;
304 long long int now
= time_msec();
305 long long int stop_time
= now
+ DURATION
;
307 for (i
= 0; i
< ATOMIC_ITEM_COUNT
; i
++) {
308 /* Wait for the reader to be done with the data. */
310 atomic_read_explicit(&aux
->data64
, &data
, memory_order_acquire
);
311 } while (data
&& (now
= time_msec()) < stop_time
);
313 if (now
>= stop_time
) {
315 VLOG_WARN("atomic_writer test stopped due to excessive "
316 "runtime, Count = %"PRIuSIZE
, i
);
322 atomic_add_explicit(&aux
->count
, 1, &old_count
, memory_order_relaxed
);
324 atomic_store_explicit(&aux
->data64
,
325 (i
& 1) ? (uint64_t)aux
->b
: a
, memory_order_release
);
334 pthread_t reader
, writer
;
335 struct atomic_aux
*aux
= xmalloc(sizeof *aux
);
340 aux
->count
= ATOMIC_VAR_INIT(0);
341 atomic_init(&aux
->data
, NULL
);
342 aux
->data64
= ATOMIC_VAR_INIT(0);
344 reader
= ovs_thread_create("reader", atomic_reader
, aux
);
345 writer
= ovs_thread_create("writer", atomic_writer
, aux
);
347 xpthread_join(reader
, NULL
);
348 xpthread_join(writer
, NULL
);
353 test_atomic_plain(void)
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);
381 test_atomic_relaxed(void)
383 TEST_ATOMIC_ORDER(memory_order_relaxed
, memory_order_relaxed
,
384 memory_order_relaxed
);
388 test_atomic_consume(void)
390 TEST_ATOMIC_ORDER(memory_order_consume
, memory_order_release
,
391 memory_order_release
);
395 test_atomic_acquire(void)
397 TEST_ATOMIC_ORDER(memory_order_acquire
, memory_order_release
,
398 memory_order_release
);
402 test_atomic_acq_rel(void)
404 TEST_ATOMIC_ORDER(memory_order_acquire
, memory_order_release
,
405 memory_order_acq_rel
);
409 test_atomic_seq_cst(void)
411 TEST_ATOMIC_ORDER(memory_order_seq_cst
, memory_order_seq_cst
,
412 memory_order_seq_cst
);
416 test_atomic_main(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
420 test_atomic_relaxed();
421 test_atomic_consume();
422 test_atomic_acquire();
423 test_atomic_acq_rel();
424 test_atomic_seq_cst();
432 OVSTEST_REGISTER("test-atomic", test_atomic_main
);