datapath-windows: Update ovsext.sln to properly build under "Win8 Debug".
[cascardo/ovs.git] / tests / test-atomic.c
1 /*
2  * Copyright (c) 2013, 2014 Nicira, Inc.
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>
18
19 #include "ovs-atomic.h"
20 #include "util.h"
21 #include "ovstest.h"
22 #include "ovs-thread.h"
23
24 #define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE)        \
25     {                                                   \
26         ATOMIC_TYPE x = ATOMIC_VAR_INIT(1);             \
27         BASE_TYPE value, orig;                          \
28                                                         \
29         atomic_read(&x, &value);                        \
30         ovs_assert(value == 1);                         \
31                                                         \
32         atomic_store(&x, 2);                            \
33         atomic_read(&x, &value);                        \
34         ovs_assert(value == 2);                         \
35                                                         \
36         atomic_init(&x, 3);                             \
37         atomic_read(&x, &value);                        \
38         ovs_assert(value == 3);                         \
39                                                         \
40         atomic_add(&x, 1, &orig);                       \
41         ovs_assert(orig == 3);                          \
42         atomic_read(&x, &value);                        \
43         ovs_assert(value == 4);                         \
44                                                         \
45         atomic_sub(&x, 2, &orig);                       \
46         ovs_assert(orig == 4);                          \
47         atomic_read(&x, &value);                        \
48         ovs_assert(value == 2);                         \
49                                                         \
50         atomic_or(&x, 6, &orig);                        \
51         ovs_assert(orig == 2);                          \
52         atomic_read(&x, &value);                        \
53         ovs_assert(value == 6);                         \
54                                                         \
55         atomic_and(&x, 10, &orig);                      \
56         ovs_assert(orig == 6);                          \
57         atomic_read(&x, &value);                        \
58         ovs_assert(value == 2);                         \
59                                                         \
60         atomic_xor(&x, 10, &orig);                      \
61         ovs_assert(orig == 2);                          \
62         atomic_read(&x, &value);                        \
63         ovs_assert(value == 8);                         \
64     }
65
66 #define TEST_ATOMIC_TYPE_EXPLICIT(ATOMIC_TYPE, BASE_TYPE,               \
67                                   ORDER_READ, ORDER_STORE, ORDER_RMW)   \
68     {                                                                   \
69         ATOMIC_TYPE x = ATOMIC_VAR_INIT(1);                             \
70         BASE_TYPE value, orig;                                          \
71                                                                         \
72         atomic_read_explicit(&x, &value, ORDER_READ);                   \
73         ovs_assert(value == 1);                                         \
74                                                                         \
75         atomic_store_explicit(&x, 2, ORDER_STORE);                      \
76         atomic_read_explicit(&x, &value, ORDER_READ);                   \
77         ovs_assert(value == 2);                                         \
78                                                                         \
79         atomic_init(&x, 3);                                             \
80         atomic_read_explicit(&x, &value, ORDER_READ);                   \
81         ovs_assert(value == 3);                                         \
82                                                                         \
83         atomic_add_explicit(&x, 1, &orig, ORDER_RMW);                   \
84         ovs_assert(orig == 3);                                          \
85         atomic_read_explicit(&x, &value, ORDER_READ);                   \
86         ovs_assert(value == 4);                                         \
87                                                                         \
88         atomic_sub_explicit(&x, 2, &orig, ORDER_RMW);                   \
89         ovs_assert(orig == 4);                                          \
90         atomic_read_explicit(&x, &value, ORDER_READ);                   \
91         ovs_assert(value == 2);                                         \
92                                                                         \
93         atomic_or_explicit(&x, 6, &orig, ORDER_RMW);                    \
94         ovs_assert(orig == 2);                                          \
95         atomic_read_explicit(&x, &value, ORDER_READ);                   \
96         ovs_assert(value == 6);                                         \
97                                                                         \
98         atomic_and_explicit(&x, 10, &orig, ORDER_RMW);                  \
99         ovs_assert(orig == 6);                                          \
100         atomic_read_explicit(&x, &value, ORDER_READ);                   \
101         ovs_assert(value == 2);                                         \
102                                                                         \
103         atomic_xor_explicit(&x, 10, &orig, ORDER_RMW);                  \
104         ovs_assert(orig == 2);                                          \
105         atomic_read_explicit(&x, &value, ORDER_READ);                   \
106         ovs_assert(value == 8);                                         \
107     }
108
109
110 #define TEST_ATOMIC_ORDER(ORDER_READ, ORDER_STORE, ORDER_RMW)           \
111     {                                                                   \
112         TEST_ATOMIC_TYPE_EXPLICIT(atomic_char, char,                    \
113                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
114         TEST_ATOMIC_TYPE_EXPLICIT(atomic_uchar, unsigned char,          \
115                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
116         TEST_ATOMIC_TYPE_EXPLICIT(atomic_schar, signed char,            \
117                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
118         TEST_ATOMIC_TYPE_EXPLICIT(atomic_short, short,                  \
119                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
120         TEST_ATOMIC_TYPE_EXPLICIT(atomic_ushort, unsigned short,        \
121                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
122         TEST_ATOMIC_TYPE_EXPLICIT(atomic_int, int,                      \
123                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
124         TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint, unsigned int,            \
125                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
126         TEST_ATOMIC_TYPE_EXPLICIT(atomic_long, long int,                \
127                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
128         TEST_ATOMIC_TYPE_EXPLICIT(atomic_ulong, unsigned long int,      \
129                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
130         TEST_ATOMIC_TYPE_EXPLICIT(atomic_llong, long long int,          \
131                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
132         TEST_ATOMIC_TYPE_EXPLICIT(atomic_ullong, unsigned long long int, \
133                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
134         TEST_ATOMIC_TYPE_EXPLICIT(atomic_size_t, size_t,                \
135                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
136         TEST_ATOMIC_TYPE_EXPLICIT(atomic_ptrdiff_t, ptrdiff_t,          \
137                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
138         TEST_ATOMIC_TYPE_EXPLICIT(atomic_intmax_t, intmax_t,            \
139                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
140         TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintmax_t, uintmax_t,          \
141                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
142         TEST_ATOMIC_TYPE_EXPLICIT(atomic_intptr_t, intptr_t,            \
143                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
144         TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintptr_t, uintptr_t,          \
145                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
146         TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint8_t, uint8_t,              \
147                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
148         TEST_ATOMIC_TYPE_EXPLICIT(atomic_int8_t, int8_t,                \
149                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
150         TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint16_t, uint16_t,            \
151                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
152         TEST_ATOMIC_TYPE_EXPLICIT(atomic_int16_t, int16_t,              \
153                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
154         TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint32_t, uint32_t,            \
155                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
156         TEST_ATOMIC_TYPE_EXPLICIT(atomic_int32_t, int32_t,              \
157                                   ORDER_READ, ORDER_STORE, ORDER_RMW);  \
158     }
159
160 static void
161 test_atomic_flag(void)
162 {
163     atomic_flag flag = ATOMIC_FLAG_INIT;
164     ovs_assert(atomic_flag_test_and_set(&flag) == false);
165     ovs_assert(atomic_flag_test_and_set(&flag) == true);
166     atomic_flag_clear(&flag);
167     ovs_assert(atomic_flag_test_and_set(&flag) == false);
168 }
169
170 uint32_t a;
171
172 struct atomic_aux {
173     atomic_uint32_t count;
174     uint32_t b;
175     ATOMIC(uint32_t *) data;
176 };
177
178 ATOMIC(struct atomic_aux *) paux = ATOMIC_VAR_INIT(NULL);
179 static struct atomic_aux *auxes = NULL;
180
181 #define ATOMIC_ITEM_COUNT 1000000
182
183 static void *
184 atomic_consumer(void * arg1 OVS_UNUSED)
185 {
186     struct atomic_aux *old_aux = NULL;
187     uint32_t count;
188
189     do {
190         struct atomic_aux *aux;
191         uint32_t b;
192
193         /* Wait for a new item.  We may not be fast enough to process every
194          * item, but we are guaranteed to see the last one. */
195         do {
196             atomic_read_explicit(&paux, &aux, memory_order_consume);
197         } while (aux == old_aux);
198
199         b = aux->b;
200         atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
201         ovs_assert(b == count + 42);
202
203         old_aux = aux;
204     } while (count < ATOMIC_ITEM_COUNT - 1);
205
206     return NULL;
207 }
208
209 static void *
210 atomic_producer(void * arg1 OVS_UNUSED)
211 {
212     size_t i;
213
214     for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
215         struct atomic_aux *aux = &auxes[i];
216
217         aux->count = ATOMIC_VAR_INIT(i);
218         aux->b = i + 42;
219
220         /* Publish the new item. */
221         atomic_store_explicit(&paux, aux, memory_order_release);
222     }
223
224     return NULL;
225 }
226
227 static void
228 test_cons_rel(void)
229 {
230     pthread_t reader, writer;
231
232     atomic_init(&paux, NULL);
233
234     auxes = xmalloc(sizeof *auxes * ATOMIC_ITEM_COUNT);
235
236     reader = ovs_thread_create("consumer", atomic_consumer, NULL);
237     writer = ovs_thread_create("producer", atomic_producer, NULL);
238
239     xpthread_join(reader, NULL);
240     xpthread_join(writer, NULL);
241
242     free(auxes);
243 }
244
245 static void *
246 atomic_reader(void *aux_)
247 {
248     struct atomic_aux *aux = aux_;
249     uint32_t count;
250     uint32_t *data;
251
252     do {
253         /* Non-synchronized add. */
254         atomic_add_explicit(&aux->count, 1, &count, memory_order_relaxed);
255
256         do {
257             atomic_read_explicit(&aux->data, &data, memory_order_acquire);
258         } while (!data);
259
260         ovs_assert(*data == a && *data == aux->b && a == aux->b);
261
262         atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
263
264         ovs_assert(count == 2 * a && count == 2 * aux->b && count == 2 * *data);
265
266         atomic_store_explicit(&aux->data, NULL, memory_order_release);
267     } while (count < 2 * ATOMIC_ITEM_COUNT);
268
269     return NULL;
270 }
271
272 static void *
273 atomic_writer(void *aux_)
274 {
275     struct atomic_aux *aux = aux_;
276     atomic_uint32_t old_count;
277     uint32_t *data;
278     size_t i;
279
280     for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
281         /* Wait for the reader to be done with the data. */
282         do {
283             atomic_read_explicit(&aux->data, &data, memory_order_acquire);
284         } while (data);
285
286         a = i + 1;
287         atomic_add_explicit(&aux->count, 1, &old_count, memory_order_relaxed);
288         aux->b++;
289         atomic_store_explicit(&aux->data,
290                               (i & 1) ? &aux->b : &a, memory_order_release);
291     }
292
293     return NULL;
294 }
295
296 static void
297 test_acq_rel(void)
298 {
299     pthread_t reader, writer;
300     struct atomic_aux *aux = xmalloc(sizeof *aux);
301
302     a = 0;
303     aux->b = 0;
304
305     aux->count = ATOMIC_VAR_INIT(0);
306     atomic_init(&aux->data, NULL);
307
308     reader = ovs_thread_create("reader", atomic_reader, aux);
309     writer = ovs_thread_create("writer", atomic_writer, aux);
310
311     xpthread_join(reader, NULL);
312     xpthread_join(writer, NULL);
313     free(aux);
314 }
315
316 static void
317 test_atomic_plain(void)
318 {
319     TEST_ATOMIC_TYPE(atomic_char, char);
320     TEST_ATOMIC_TYPE(atomic_uchar, unsigned char);
321     TEST_ATOMIC_TYPE(atomic_schar, signed char);
322     TEST_ATOMIC_TYPE(atomic_short, short);
323     TEST_ATOMIC_TYPE(atomic_ushort, unsigned short);
324     TEST_ATOMIC_TYPE(atomic_int, int);
325     TEST_ATOMIC_TYPE(atomic_uint, unsigned int);
326     TEST_ATOMIC_TYPE(atomic_long, long int);
327     TEST_ATOMIC_TYPE(atomic_ulong, unsigned long int);
328     TEST_ATOMIC_TYPE(atomic_llong, long long int);
329     TEST_ATOMIC_TYPE(atomic_ullong, unsigned long long int);
330     TEST_ATOMIC_TYPE(atomic_size_t, size_t);
331     TEST_ATOMIC_TYPE(atomic_ptrdiff_t, ptrdiff_t);
332     TEST_ATOMIC_TYPE(atomic_intmax_t, intmax_t);
333     TEST_ATOMIC_TYPE(atomic_uintmax_t, uintmax_t);
334     TEST_ATOMIC_TYPE(atomic_intptr_t, intptr_t);
335     TEST_ATOMIC_TYPE(atomic_uintptr_t, uintptr_t);
336     TEST_ATOMIC_TYPE(atomic_uint8_t, uint8_t);
337     TEST_ATOMIC_TYPE(atomic_int8_t, int8_t);
338     TEST_ATOMIC_TYPE(atomic_uint16_t, uint16_t);
339     TEST_ATOMIC_TYPE(atomic_int16_t, int16_t);
340     TEST_ATOMIC_TYPE(atomic_uint32_t, uint32_t);
341     TEST_ATOMIC_TYPE(atomic_int32_t, int32_t);
342 }
343
344 static void
345 test_atomic_relaxed(void)
346 {
347     TEST_ATOMIC_ORDER(memory_order_relaxed, memory_order_relaxed,
348                       memory_order_relaxed);
349 }
350
351 static void
352 test_atomic_consume(void)
353 {
354     TEST_ATOMIC_ORDER(memory_order_consume, memory_order_release,
355                       memory_order_release);
356 }
357
358 static void
359 test_atomic_acquire(void)
360 {
361     TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
362                       memory_order_release);
363 }
364
365 static void
366 test_atomic_acq_rel(void)
367 {
368     TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
369                       memory_order_acq_rel);
370 }
371
372 static void
373 test_atomic_seq_cst(void)
374 {
375     TEST_ATOMIC_ORDER(memory_order_seq_cst, memory_order_seq_cst,
376                       memory_order_seq_cst);
377 }
378
379 static void
380 test_atomic_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
381 {
382     test_atomic_plain();
383     test_atomic_relaxed();
384     test_atomic_consume();
385     test_atomic_acquire();
386     test_atomic_acq_rel();
387     test_atomic_seq_cst();
388
389     test_atomic_flag();
390
391     test_acq_rel();
392     test_cons_rel();
393 }
394
395 OVSTEST_REGISTER("test-atomic", test_atomic_main);