datapath: Add Stateless TCP Tunneling protocol.
[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 #undef NDEBUG
19 #include "ovs-atomic.h"
20 #include "ovstest.h"
21 #include "ovs-thread.h"
22 #include "timeval.h"
23 #include "util.h"
24 #include "openvswitch/vlog.h"
25
26 VLOG_DEFINE_THIS_MODULE(test_atomic);
27
28 #define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE)        \
29     {                                                   \
30         ATOMIC_TYPE x = ATOMIC_VAR_INIT(1);             \
31         BASE_TYPE value, orig;                          \
32                                                         \
33         atomic_read(&x, &value);                        \
34         ovs_assert(value == 1);                         \
35                                                         \
36         atomic_store(&x, 2);                            \
37         atomic_read(&x, &value);                        \
38         ovs_assert(value == 2);                         \
39                                                         \
40         atomic_init(&x, 3);                             \
41         atomic_read(&x, &value);                        \
42         ovs_assert(value == 3);                         \
43                                                         \
44         atomic_add(&x, 1, &orig);                       \
45         ovs_assert(orig == 3);                          \
46         atomic_read(&x, &value);                        \
47         ovs_assert(value == 4);                         \
48                                                         \
49         atomic_sub(&x, 2, &orig);                       \
50         ovs_assert(orig == 4);                          \
51         atomic_read(&x, &value);                        \
52         ovs_assert(value == 2);                         \
53                                                         \
54         atomic_or(&x, 6, &orig);                        \
55         ovs_assert(orig == 2);                          \
56         atomic_read(&x, &value);                        \
57         ovs_assert(value == 6);                         \
58                                                         \
59         atomic_and(&x, 10, &orig);                      \
60         ovs_assert(orig == 6);                          \
61         atomic_read(&x, &value);                        \
62         ovs_assert(value == 2);                         \
63                                                         \
64         atomic_xor(&x, 10, &orig);                      \
65         ovs_assert(orig == 2);                          \
66         atomic_read(&x, &value);                        \
67         ovs_assert(value == 8);                         \
68     }
69
70 #define TEST_ATOMIC_TYPE_EXPLICIT(ATOMIC_TYPE, BASE_TYPE,               \
71                                   ORDER_READ, ORDER_STORE, ORDER_RMW)   \
72     {                                                                   \
73         ATOMIC_TYPE x = ATOMIC_VAR_INIT(1);                             \
74         BASE_TYPE value, orig;                                          \
75                                                                         \
76         atomic_read_explicit(&x, &value, ORDER_READ);                   \
77         ovs_assert(value == 1);                                         \
78                                                                         \
79         atomic_store_explicit(&x, 2, ORDER_STORE);                      \
80         atomic_read_explicit(&x, &value, ORDER_READ);                   \
81         ovs_assert(value == 2);                                         \
82                                                                         \
83         atomic_init(&x, 3);                                             \
84         atomic_read_explicit(&x, &value, ORDER_READ);                   \
85         ovs_assert(value == 3);                                         \
86                                                                         \
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);                                         \
91                                                                         \
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);                                         \
96                                                                         \
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);                                         \
101                                                                         \
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);                                         \
106                                                                         \
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);                                         \
111     }
112
113
114 #define TEST_ATOMIC_ORDER(ORDER_READ, ORDER_STORE, ORDER_RMW)           \
115     {                                                                   \
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);  \
162     }
163
164 static void
165 test_atomic_flag(void)
166 {
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);
172 }
173
174 static uint32_t a;
175
176 struct atomic_aux {
177     ATOMIC(uint64_t) count;
178     uint32_t b;
179     ATOMIC(uint32_t *) data;
180     ATOMIC(uint64_t) data64;
181 };
182
183 static ATOMIC(struct atomic_aux *) paux = ATOMIC_VAR_INIT(NULL);
184 static struct atomic_aux *auxes = NULL;
185
186 #define ATOMIC_ITEM_COUNT 1000000
187
188 static void *
189 atomic_consumer(void * arg1 OVS_UNUSED)
190 {
191     struct atomic_aux *old_aux = NULL;
192     uint64_t count;
193     long long int stop_time = time_msec() + 1000;
194
195     do {
196         struct atomic_aux *aux;
197         uint32_t b;
198
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. */
201         do {
202             atomic_read_explicit(&paux, &aux, memory_order_consume);
203         } while (aux == old_aux);
204
205         b = aux->b;
206         atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
207         ovs_assert(b == count + 42);
208
209         old_aux = aux;
210     } while (count < ATOMIC_ITEM_COUNT - 1 && time_msec() < stop_time);
211
212     if (time_msec() >= stop_time) {
213         if (count < 10) {
214             VLOG_WARN("atomic_consumer test stopped due to excessive runtime. "
215                       "Count = %"PRIu64, count);
216         }
217     }
218
219     return NULL;
220 }
221
222 static void *
223 atomic_producer(void * arg1 OVS_UNUSED)
224 {
225     size_t i;
226
227     for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
228         struct atomic_aux *aux = &auxes[i];
229
230         aux->count = ATOMIC_VAR_INIT(i);
231         aux->b = i + 42;
232
233         /* Publish the new item. */
234         atomic_store_explicit(&paux, aux, memory_order_release);
235     }
236
237     return NULL;
238 }
239
240 static void
241 test_cons_rel(void)
242 {
243     pthread_t reader, writer;
244
245     atomic_init(&paux, NULL);
246
247     auxes = xmalloc(sizeof *auxes * ATOMIC_ITEM_COUNT);
248
249     reader = ovs_thread_create("consumer", atomic_consumer, NULL);
250     writer = ovs_thread_create("producer", atomic_producer, NULL);
251
252     xpthread_join(reader, NULL);
253     xpthread_join(writer, NULL);
254
255     free(auxes);
256 }
257
258 static void *
259 atomic_reader(void *aux_)
260 {
261     struct atomic_aux *aux = aux_;
262     uint64_t count;
263     uint64_t data;
264     long long int now = time_msec();
265     long long int stop_time = now + 1000;
266
267     do {
268         /* Non-synchronized add. */
269         atomic_add_explicit(&aux->count, 1, &count, memory_order_relaxed);
270
271         do {
272             atomic_read_explicit(&aux->data64, &data, memory_order_acquire);
273         } while (!data && (now = time_msec()) < stop_time);
274
275         if (now >= stop_time) {
276             if (count < 10) {
277                 VLOG_WARN("atomic_reader test stopped due to excessive "
278                           "runtime. Count = %"PRIu64, count);
279             }
280             break;
281         }
282
283         ovs_assert(data == a && data == aux->b && a == aux->b);
284
285         atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
286
287         ovs_assert(count == 2 * a && count == 2 * aux->b && count == 2 * data);
288
289         atomic_store_explicit(&aux->data64, UINT64_C(0), memory_order_release);
290     } while (count < 2 * ATOMIC_ITEM_COUNT);
291
292     return NULL;
293 }
294
295 static void *
296 atomic_writer(void *aux_)
297 {
298     struct atomic_aux *aux = aux_;
299     uint64_t old_count;
300     uint64_t data;
301     size_t i;
302     long long int now = time_msec();
303     long long int stop_time = now + 1000;
304
305     for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
306         /* Wait for the reader to be done with the data. */
307         do {
308             atomic_read_explicit(&aux->data64, &data, memory_order_acquire);
309         } while (data && (now = time_msec()) < stop_time);
310
311         if (now >= stop_time) {
312             if (i < 10) {
313                 VLOG_WARN("atomic_writer test stopped due to excessive "
314                           "runtime, Count = %"PRIuSIZE, i);
315             }
316             break;
317         }
318
319         a = i + 1;
320         atomic_add_explicit(&aux->count, 1, &old_count, memory_order_relaxed);
321         aux->b++;
322         atomic_store_explicit(&aux->data64,
323                               (i & 1) ? (uint64_t)aux->b : a, memory_order_release);
324     }
325
326     return NULL;
327 }
328
329 static void
330 test_acq_rel(void)
331 {
332     pthread_t reader, writer;
333     struct atomic_aux *aux = xmalloc(sizeof *aux);
334
335     a = 0;
336     aux->b = 0;
337
338     aux->count = ATOMIC_VAR_INIT(0);
339     atomic_init(&aux->data, NULL);
340     aux->data64 = ATOMIC_VAR_INIT(0);
341
342     reader = ovs_thread_create("reader", atomic_reader, aux);
343     writer = ovs_thread_create("writer", atomic_writer, aux);
344
345     xpthread_join(reader, NULL);
346     xpthread_join(writer, NULL);
347     free(aux);
348 }
349
350 static void
351 test_atomic_plain(void)
352 {
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);
376 }
377
378 static void
379 test_atomic_relaxed(void)
380 {
381     TEST_ATOMIC_ORDER(memory_order_relaxed, memory_order_relaxed,
382                       memory_order_relaxed);
383 }
384
385 static void
386 test_atomic_consume(void)
387 {
388     TEST_ATOMIC_ORDER(memory_order_consume, memory_order_release,
389                       memory_order_release);
390 }
391
392 static void
393 test_atomic_acquire(void)
394 {
395     TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
396                       memory_order_release);
397 }
398
399 static void
400 test_atomic_acq_rel(void)
401 {
402     TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
403                       memory_order_acq_rel);
404 }
405
406 static void
407 test_atomic_seq_cst(void)
408 {
409     TEST_ATOMIC_ORDER(memory_order_seq_cst, memory_order_seq_cst,
410                       memory_order_seq_cst);
411 }
412
413 static void
414 test_atomic_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
415 {
416     test_atomic_plain();
417     test_atomic_relaxed();
418     test_atomic_consume();
419     test_atomic_acquire();
420     test_atomic_acq_rel();
421     test_atomic_seq_cst();
422
423     test_atomic_flag();
424
425     test_acq_rel();
426     test_cons_rel();
427 }
428
429 OVSTEST_REGISTER("test-atomic", test_atomic_main);