]>
git.proxmox.com Git - mirror_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 "ovs-atomic.h"
21 #include "ovs-thread.h"
24 #include "openvswitch/vlog.h"
26 VLOG_DEFINE_THIS_MODULE(test_atomic
);
28 #define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE) \
30 ATOMIC_TYPE x = ATOMIC_VAR_INIT(1); \
31 BASE_TYPE value, orig; \
33 atomic_read(&x, &value); \
34 ovs_assert(value == 1); \
36 atomic_store(&x, 2); \
37 atomic_read(&x, &value); \
38 ovs_assert(value == 2); \
41 atomic_read(&x, &value); \
42 ovs_assert(value == 3); \
44 atomic_add(&x, 1, &orig); \
45 ovs_assert(orig == 3); \
46 atomic_read(&x, &value); \
47 ovs_assert(value == 4); \
49 atomic_sub(&x, 2, &orig); \
50 ovs_assert(orig == 4); \
51 atomic_read(&x, &value); \
52 ovs_assert(value == 2); \
54 atomic_or(&x, 6, &orig); \
55 ovs_assert(orig == 2); \
56 atomic_read(&x, &value); \
57 ovs_assert(value == 6); \
59 atomic_and(&x, 10, &orig); \
60 ovs_assert(orig == 6); \
61 atomic_read(&x, &value); \
62 ovs_assert(value == 2); \
64 atomic_xor(&x, 10, &orig); \
65 ovs_assert(orig == 2); \
66 atomic_read(&x, &value); \
67 ovs_assert(value == 8); \
70 #define TEST_ATOMIC_TYPE_EXPLICIT(ATOMIC_TYPE, BASE_TYPE, \
71 ORDER_READ, ORDER_STORE, ORDER_RMW) \
73 ATOMIC_TYPE x = ATOMIC_VAR_INIT(1); \
74 BASE_TYPE value, orig; \
76 atomic_read_explicit(&x, &value, ORDER_READ); \
77 ovs_assert(value == 1); \
79 atomic_store_explicit(&x, 2, ORDER_STORE); \
80 atomic_read_explicit(&x, &value, ORDER_READ); \
81 ovs_assert(value == 2); \
84 atomic_read_explicit(&x, &value, ORDER_READ); \
85 ovs_assert(value == 3); \
87 atomic_add_explicit(&x, 1, &orig, ORDER_RMW); \
88 ovs_assert(orig == 3); \
89 atomic_read_explicit(&x, &value, ORDER_READ); \
90 ovs_assert(value == 4); \
92 atomic_sub_explicit(&x, 2, &orig, ORDER_RMW); \
93 ovs_assert(orig == 4); \
94 atomic_read_explicit(&x, &value, ORDER_READ); \
95 ovs_assert(value == 2); \
97 atomic_or_explicit(&x, 6, &orig, ORDER_RMW); \
98 ovs_assert(orig == 2); \
99 atomic_read_explicit(&x, &value, ORDER_READ); \
100 ovs_assert(value == 6); \
102 atomic_and_explicit(&x, 10, &orig, ORDER_RMW); \
103 ovs_assert(orig == 6); \
104 atomic_read_explicit(&x, &value, ORDER_READ); \
105 ovs_assert(value == 2); \
107 atomic_xor_explicit(&x, 10, &orig, ORDER_RMW); \
108 ovs_assert(orig == 2); \
109 atomic_read_explicit(&x, &value, ORDER_READ); \
110 ovs_assert(value == 8); \
114 #define TEST_ATOMIC_ORDER(ORDER_READ, ORDER_STORE, ORDER_RMW) \
116 TEST_ATOMIC_TYPE_EXPLICIT(atomic_char, char, \
117 ORDER_READ, ORDER_STORE, ORDER_RMW); \
118 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uchar, unsigned char, \
119 ORDER_READ, ORDER_STORE, ORDER_RMW); \
120 TEST_ATOMIC_TYPE_EXPLICIT(atomic_schar, signed char, \
121 ORDER_READ, ORDER_STORE, ORDER_RMW); \
122 TEST_ATOMIC_TYPE_EXPLICIT(atomic_short, short, \
123 ORDER_READ, ORDER_STORE, ORDER_RMW); \
124 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ushort, unsigned short, \
125 ORDER_READ, ORDER_STORE, ORDER_RMW); \
126 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int, int, \
127 ORDER_READ, ORDER_STORE, ORDER_RMW); \
128 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint, unsigned int, \
129 ORDER_READ, ORDER_STORE, ORDER_RMW); \
130 TEST_ATOMIC_TYPE_EXPLICIT(atomic_long, long int, \
131 ORDER_READ, ORDER_STORE, ORDER_RMW); \
132 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ulong, unsigned long int, \
133 ORDER_READ, ORDER_STORE, ORDER_RMW); \
134 TEST_ATOMIC_TYPE_EXPLICIT(atomic_llong, long long int, \
135 ORDER_READ, ORDER_STORE, ORDER_RMW); \
136 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ullong, unsigned long long int, \
137 ORDER_READ, ORDER_STORE, ORDER_RMW); \
138 TEST_ATOMIC_TYPE_EXPLICIT(atomic_size_t, size_t, \
139 ORDER_READ, ORDER_STORE, ORDER_RMW); \
140 TEST_ATOMIC_TYPE_EXPLICIT(atomic_ptrdiff_t, ptrdiff_t, \
141 ORDER_READ, ORDER_STORE, ORDER_RMW); \
142 TEST_ATOMIC_TYPE_EXPLICIT(atomic_intmax_t, intmax_t, \
143 ORDER_READ, ORDER_STORE, ORDER_RMW); \
144 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintmax_t, uintmax_t, \
145 ORDER_READ, ORDER_STORE, ORDER_RMW); \
146 TEST_ATOMIC_TYPE_EXPLICIT(atomic_intptr_t, intptr_t, \
147 ORDER_READ, ORDER_STORE, ORDER_RMW); \
148 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintptr_t, uintptr_t, \
149 ORDER_READ, ORDER_STORE, ORDER_RMW); \
150 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint8_t, uint8_t, \
151 ORDER_READ, ORDER_STORE, ORDER_RMW); \
152 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int8_t, int8_t, \
153 ORDER_READ, ORDER_STORE, ORDER_RMW); \
154 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint16_t, uint16_t, \
155 ORDER_READ, ORDER_STORE, ORDER_RMW); \
156 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int16_t, int16_t, \
157 ORDER_READ, ORDER_STORE, ORDER_RMW); \
158 TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint32_t, uint32_t, \
159 ORDER_READ, ORDER_STORE, ORDER_RMW); \
160 TEST_ATOMIC_TYPE_EXPLICIT(atomic_int32_t, int32_t, \
161 ORDER_READ, ORDER_STORE, ORDER_RMW); \
165 test_atomic_flag(void)
167 atomic_flag flag
= ATOMIC_FLAG_INIT
;
168 ovs_assert(atomic_flag_test_and_set(&flag
) == false);
169 ovs_assert(atomic_flag_test_and_set(&flag
) == true);
170 atomic_flag_clear(&flag
);
171 ovs_assert(atomic_flag_test_and_set(&flag
) == false);
177 ATOMIC(uint64_t) count
;
179 ATOMIC(uint32_t *) data
;
180 ATOMIC(uint64_t) data64
;
183 static ATOMIC(struct atomic_aux
*) paux
= ATOMIC_VAR_INIT(NULL
);
184 static struct atomic_aux
*auxes
= NULL
;
186 #define ATOMIC_ITEM_COUNT 1000000
189 atomic_consumer(void * arg1 OVS_UNUSED
)
191 struct atomic_aux
*old_aux
= NULL
;
193 long long int stop_time
= time_msec() + 1000;
196 struct atomic_aux
*aux
;
199 /* Wait for a new item. We may not be fast enough to process every
200 * item, but we are guaranteed to see the last one. */
202 atomic_read_explicit(&paux
, &aux
, memory_order_consume
);
203 } while (aux
== old_aux
);
206 atomic_read_explicit(&aux
->count
, &count
, memory_order_relaxed
);
207 ovs_assert(b
== count
+ 42);
210 } while (count
< ATOMIC_ITEM_COUNT
- 1 && time_msec() < stop_time
);
212 if (time_msec() >= stop_time
) {
214 VLOG_WARN("atomic_consumer test stopped due to excessive runtime. "
215 "Count = %"PRIu64
, count
);
223 atomic_producer(void * arg1 OVS_UNUSED
)
227 for (i
= 0; i
< ATOMIC_ITEM_COUNT
; i
++) {
228 struct atomic_aux
*aux
= &auxes
[i
];
230 aux
->count
= ATOMIC_VAR_INIT(i
);
233 /* Publish the new item. */
234 atomic_store_explicit(&paux
, aux
, memory_order_release
);
243 pthread_t reader
, writer
;
245 atomic_init(&paux
, NULL
);
247 auxes
= xmalloc(sizeof *auxes
* ATOMIC_ITEM_COUNT
);
249 reader
= ovs_thread_create("consumer", atomic_consumer
, NULL
);
250 writer
= ovs_thread_create("producer", atomic_producer
, NULL
);
252 xpthread_join(reader
, NULL
);
253 xpthread_join(writer
, NULL
);
259 atomic_reader(void *aux_
)
261 struct atomic_aux
*aux
= aux_
;
264 long long int now
= time_msec();
265 long long int stop_time
= now
+ 1000;
268 /* Non-synchronized add. */
269 atomic_add_explicit(&aux
->count
, 1, &count
, memory_order_relaxed
);
272 atomic_read_explicit(&aux
->data64
, &data
, memory_order_acquire
);
273 } while (!data
&& (now
= time_msec()) < stop_time
);
275 if (now
>= stop_time
) {
277 VLOG_WARN("atomic_reader test stopped due to excessive "
278 "runtime. Count = %"PRIu64
, count
);
283 ovs_assert(data
== a
&& data
== aux
->b
&& a
== aux
->b
);
285 atomic_read_explicit(&aux
->count
, &count
, memory_order_relaxed
);
287 ovs_assert(count
== 2 * a
&& count
== 2 * aux
->b
&& count
== 2 * data
);
289 atomic_store_explicit(&aux
->data64
, UINT64_C(0), memory_order_release
);
290 } while (count
< 2 * ATOMIC_ITEM_COUNT
);
296 atomic_writer(void *aux_
)
298 struct atomic_aux
*aux
= aux_
;
302 long long int now
= time_msec();
303 long long int stop_time
= now
+ 1000;
305 for (i
= 0; i
< ATOMIC_ITEM_COUNT
; i
++) {
306 /* Wait for the reader to be done with the data. */
308 atomic_read_explicit(&aux
->data64
, &data
, memory_order_acquire
);
309 } while (data
&& (now
= time_msec()) < stop_time
);
311 if (now
>= stop_time
) {
313 VLOG_WARN("atomic_writer test stopped due to excessive "
314 "runtime, Count = %"PRIuSIZE
, i
);
320 atomic_add_explicit(&aux
->count
, 1, &old_count
, memory_order_relaxed
);
322 atomic_store_explicit(&aux
->data64
,
323 (i
& 1) ? (uint64_t)aux
->b
: a
, memory_order_release
);
332 pthread_t reader
, writer
;
333 struct atomic_aux
*aux
= xmalloc(sizeof *aux
);
338 aux
->count
= ATOMIC_VAR_INIT(0);
339 atomic_init(&aux
->data
, NULL
);
340 aux
->data64
= ATOMIC_VAR_INIT(0);
342 reader
= ovs_thread_create("reader", atomic_reader
, aux
);
343 writer
= ovs_thread_create("writer", atomic_writer
, aux
);
345 xpthread_join(reader
, NULL
);
346 xpthread_join(writer
, NULL
);
351 test_atomic_plain(void)
353 TEST_ATOMIC_TYPE(atomic_char
, char);
354 TEST_ATOMIC_TYPE(atomic_uchar
, unsigned char);
355 TEST_ATOMIC_TYPE(atomic_schar
, signed char);
356 TEST_ATOMIC_TYPE(atomic_short
, short);
357 TEST_ATOMIC_TYPE(atomic_ushort
, unsigned short);
358 TEST_ATOMIC_TYPE(atomic_int
, int);
359 TEST_ATOMIC_TYPE(atomic_uint
, unsigned int);
360 TEST_ATOMIC_TYPE(atomic_long
, long int);
361 TEST_ATOMIC_TYPE(atomic_ulong
, unsigned long int);
362 TEST_ATOMIC_TYPE(atomic_llong
, long long int);
363 TEST_ATOMIC_TYPE(atomic_ullong
, unsigned long long int);
364 TEST_ATOMIC_TYPE(atomic_size_t
, size_t);
365 TEST_ATOMIC_TYPE(atomic_ptrdiff_t
, ptrdiff_t);
366 TEST_ATOMIC_TYPE(atomic_intmax_t
, intmax_t);
367 TEST_ATOMIC_TYPE(atomic_uintmax_t
, uintmax_t);
368 TEST_ATOMIC_TYPE(atomic_intptr_t
, intptr_t);
369 TEST_ATOMIC_TYPE(atomic_uintptr_t
, uintptr_t);
370 TEST_ATOMIC_TYPE(atomic_uint8_t
, uint8_t);
371 TEST_ATOMIC_TYPE(atomic_int8_t
, int8_t);
372 TEST_ATOMIC_TYPE(atomic_uint16_t
, uint16_t);
373 TEST_ATOMIC_TYPE(atomic_int16_t
, int16_t);
374 TEST_ATOMIC_TYPE(atomic_uint32_t
, uint32_t);
375 TEST_ATOMIC_TYPE(atomic_int32_t
, int32_t);
379 test_atomic_relaxed(void)
381 TEST_ATOMIC_ORDER(memory_order_relaxed
, memory_order_relaxed
,
382 memory_order_relaxed
);
386 test_atomic_consume(void)
388 TEST_ATOMIC_ORDER(memory_order_consume
, memory_order_release
,
389 memory_order_release
);
393 test_atomic_acquire(void)
395 TEST_ATOMIC_ORDER(memory_order_acquire
, memory_order_release
,
396 memory_order_release
);
400 test_atomic_acq_rel(void)
402 TEST_ATOMIC_ORDER(memory_order_acquire
, memory_order_release
,
403 memory_order_acq_rel
);
407 test_atomic_seq_cst(void)
409 TEST_ATOMIC_ORDER(memory_order_seq_cst
, memory_order_seq_cst
,
410 memory_order_seq_cst
);
414 test_atomic_main(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
417 test_atomic_relaxed();
418 test_atomic_consume();
419 test_atomic_acquire();
420 test_atomic_acq_rel();
421 test_atomic_seq_cst();
429 OVSTEST_REGISTER("test-atomic", test_atomic_main
);