datapath-windows: Make VPORT ovs number values smaller than MAXUINT16
[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 static uint32_t a;
171
172 struct atomic_aux {
173     ATOMIC(uint64_t) count;
174     uint32_t b;
175     ATOMIC(uint32_t *) data;
176     ATOMIC(uint64_t) data64;
177 };
178
179 static ATOMIC(struct atomic_aux *) paux = ATOMIC_VAR_INIT(NULL);
180 static struct atomic_aux *auxes = NULL;
181
182 #define ATOMIC_ITEM_COUNT 1000000
183
184 static void *
185 atomic_consumer(void * arg1 OVS_UNUSED)
186 {
187     struct atomic_aux *old_aux = NULL;
188     uint64_t count;
189
190     do {
191         struct atomic_aux *aux;
192         uint32_t b;
193
194         /* Wait for a new item.  We may not be fast enough to process every
195          * item, but we are guaranteed to see the last one. */
196         do {
197             atomic_read_explicit(&paux, &aux, memory_order_consume);
198         } while (aux == old_aux);
199
200         b = aux->b;
201         atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
202         ovs_assert(b == count + 42);
203
204         old_aux = aux;
205     } while (count < ATOMIC_ITEM_COUNT - 1);
206
207     return NULL;
208 }
209
210 static void *
211 atomic_producer(void * arg1 OVS_UNUSED)
212 {
213     size_t i;
214
215     for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
216         struct atomic_aux *aux = &auxes[i];
217
218         aux->count = ATOMIC_VAR_INIT(i);
219         aux->b = i + 42;
220
221         /* Publish the new item. */
222         atomic_store_explicit(&paux, aux, memory_order_release);
223     }
224
225     return NULL;
226 }
227
228 static void
229 test_cons_rel(void)
230 {
231     pthread_t reader, writer;
232
233     atomic_init(&paux, NULL);
234
235     auxes = xmalloc(sizeof *auxes * ATOMIC_ITEM_COUNT);
236
237     reader = ovs_thread_create("consumer", atomic_consumer, NULL);
238     writer = ovs_thread_create("producer", atomic_producer, NULL);
239
240     xpthread_join(reader, NULL);
241     xpthread_join(writer, NULL);
242
243     free(auxes);
244 }
245
246 static void *
247 atomic_reader(void *aux_)
248 {
249     struct atomic_aux *aux = aux_;
250     uint64_t count;
251     uint64_t data;
252
253     do {
254         /* Non-synchronized add. */
255         atomic_add_explicit(&aux->count, 1, &count, memory_order_relaxed);
256
257         do {
258             atomic_read_explicit(&aux->data64, &data, memory_order_acquire);
259         } while (!data);
260
261         ovs_assert(data == a && data == aux->b && a == aux->b);
262
263         atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
264
265         ovs_assert(count == 2 * a && count == 2 * aux->b && count == 2 * data);
266
267         atomic_store_explicit(&aux->data64, UINT64_C(0), memory_order_release);
268     } while (count < 2 * ATOMIC_ITEM_COUNT);
269
270     return NULL;
271 }
272
273 static void *
274 atomic_writer(void *aux_)
275 {
276     struct atomic_aux *aux = aux_;
277     uint64_t old_count;
278     uint64_t data;
279     size_t i;
280
281     for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
282         /* Wait for the reader to be done with the data. */
283         do {
284             atomic_read_explicit(&aux->data64, &data, memory_order_acquire);
285         } while (data);
286
287         a = i + 1;
288         atomic_add_explicit(&aux->count, 1, &old_count, memory_order_relaxed);
289         aux->b++;
290         atomic_store_explicit(&aux->data64,
291                               (i & 1) ? (uint64_t)aux->b : a, memory_order_release);
292     }
293
294     return NULL;
295 }
296
297 static void
298 test_acq_rel(void)
299 {
300     pthread_t reader, writer;
301     struct atomic_aux *aux = xmalloc(sizeof *aux);
302
303     a = 0;
304     aux->b = 0;
305
306     aux->count = ATOMIC_VAR_INIT(0);
307     atomic_init(&aux->data, NULL);
308     aux->data64 = ATOMIC_VAR_INIT(0);
309
310     reader = ovs_thread_create("reader", atomic_reader, aux);
311     writer = ovs_thread_create("writer", atomic_writer, aux);
312
313     xpthread_join(reader, NULL);
314     xpthread_join(writer, NULL);
315     free(aux);
316 }
317
318 static void
319 test_atomic_plain(void)
320 {
321     TEST_ATOMIC_TYPE(atomic_char, char);
322     TEST_ATOMIC_TYPE(atomic_uchar, unsigned char);
323     TEST_ATOMIC_TYPE(atomic_schar, signed char);
324     TEST_ATOMIC_TYPE(atomic_short, short);
325     TEST_ATOMIC_TYPE(atomic_ushort, unsigned short);
326     TEST_ATOMIC_TYPE(atomic_int, int);
327     TEST_ATOMIC_TYPE(atomic_uint, unsigned int);
328     TEST_ATOMIC_TYPE(atomic_long, long int);
329     TEST_ATOMIC_TYPE(atomic_ulong, unsigned long int);
330     TEST_ATOMIC_TYPE(atomic_llong, long long int);
331     TEST_ATOMIC_TYPE(atomic_ullong, unsigned long long int);
332     TEST_ATOMIC_TYPE(atomic_size_t, size_t);
333     TEST_ATOMIC_TYPE(atomic_ptrdiff_t, ptrdiff_t);
334     TEST_ATOMIC_TYPE(atomic_intmax_t, intmax_t);
335     TEST_ATOMIC_TYPE(atomic_uintmax_t, uintmax_t);
336     TEST_ATOMIC_TYPE(atomic_intptr_t, intptr_t);
337     TEST_ATOMIC_TYPE(atomic_uintptr_t, uintptr_t);
338     TEST_ATOMIC_TYPE(atomic_uint8_t, uint8_t);
339     TEST_ATOMIC_TYPE(atomic_int8_t, int8_t);
340     TEST_ATOMIC_TYPE(atomic_uint16_t, uint16_t);
341     TEST_ATOMIC_TYPE(atomic_int16_t, int16_t);
342     TEST_ATOMIC_TYPE(atomic_uint32_t, uint32_t);
343     TEST_ATOMIC_TYPE(atomic_int32_t, int32_t);
344 }
345
346 static void
347 test_atomic_relaxed(void)
348 {
349     TEST_ATOMIC_ORDER(memory_order_relaxed, memory_order_relaxed,
350                       memory_order_relaxed);
351 }
352
353 static void
354 test_atomic_consume(void)
355 {
356     TEST_ATOMIC_ORDER(memory_order_consume, memory_order_release,
357                       memory_order_release);
358 }
359
360 static void
361 test_atomic_acquire(void)
362 {
363     TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
364                       memory_order_release);
365 }
366
367 static void
368 test_atomic_acq_rel(void)
369 {
370     TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
371                       memory_order_acq_rel);
372 }
373
374 static void
375 test_atomic_seq_cst(void)
376 {
377     TEST_ATOMIC_ORDER(memory_order_seq_cst, memory_order_seq_cst,
378                       memory_order_seq_cst);
379 }
380
381 static void
382 test_atomic_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
383 {
384     test_atomic_plain();
385     test_atomic_relaxed();
386     test_atomic_consume();
387     test_atomic_acquire();
388     test_atomic_acq_rel();
389     test_atomic_seq_cst();
390
391     test_atomic_flag();
392
393     test_acq_rel();
394     test_cons_rel();
395 }
396
397 OVSTEST_REGISTER("test-atomic", test_atomic_main);