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