1 /**************************************************************************
2  *
3  * Copyright 2014 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 #include <gtest/gtest.h>
29 #include <stdint.h>
30 #include <inttypes.h>
31 
32 #include "u_atomic.h"
33 
34 #ifdef _MSC_VER
35 #pragma warning( disable : 28112 ) /* Accessing a local variable via an Interlocked function */
36 #pragma warning( disable : 28113 ) /* A variable which is accessed via an Interlocked function must always be accessed via an Interlocked function */
37 #endif
38 
39 template <typename T> class AtomicAssignment : public testing::Test {};
40 
41 using AtomicAssignmentTypes =
42    testing::Types<int, unsigned, bool,
43                   int8_t, uint8_t, int16_t, uint16_t,
44                   int32_t, uint32_t, int64_t, uint64_t>;
45 
46 TYPED_TEST_SUITE(AtomicAssignment, AtomicAssignmentTypes);
47 
TYPED_TEST(AtomicAssignment, Test)48 TYPED_TEST(AtomicAssignment, Test)
49 {
50    TypeParam v, r;
51    const TypeParam ones = TypeParam(-1);
52 
53    p_atomic_set(&v, ones);
54    ASSERT_EQ(v, ones) << "p_atomic_set";
55 
56    r = p_atomic_read(&v);
57    ASSERT_EQ(r, ones) << "p_atomic_read";
58 
59    v = ones;
60    r = p_atomic_cmpxchg(&v, 0, 1);
61    ASSERT_EQ(v, ones) << "p_atomic_cmpxchg";
62    ASSERT_EQ(r, ones) << "p_atomic_cmpxchg";
63 
64    r = p_atomic_cmpxchg(&v, ones, 0);
65    ASSERT_EQ(v, 0) << "p_atomic_cmpxchg";
66    ASSERT_EQ(r, ones) << "p_atomic_cmpxchg";
67 }
68 
69 
70 template <typename T> class AtomicIncrementDecrement : public testing::Test {};
71 
72 using AtomicIncrementDecrementTypes =
73    testing::Types<int, unsigned,
74                   int16_t, uint16_t,
75                   int32_t, uint32_t, int64_t, uint64_t>;
76 
77 TYPED_TEST_SUITE(AtomicIncrementDecrement, AtomicIncrementDecrementTypes);
78 
TYPED_TEST(AtomicIncrementDecrement, Test)79 TYPED_TEST(AtomicIncrementDecrement, Test)
80 {
81    TypeParam v, r;
82    bool b;
83 
84    const TypeParam ones = TypeParam(-1);
85 
86    v = 2;
87 
88    b = p_atomic_dec_zero(&v);
89    ASSERT_EQ(v, 1) << "p_atomic_dec_zero";
90    ASSERT_FALSE(b) << "p_atomic_dec_zero";
91 
92    b = p_atomic_dec_zero(&v);
93    ASSERT_EQ(v, 0) << "p_atomic_dec_zero";
94    ASSERT_TRUE(b)  << "p_atomic_dec_zero";
95 
96    b = p_atomic_dec_zero(&v);
97    ASSERT_EQ(v, ones) << "p_atomic_dec_zero";
98    ASSERT_FALSE(b) << "p_atomic_dec_zero";
99 
100    v = ones;
101    p_atomic_inc(&v);
102    ASSERT_EQ(v, 0) << "p_atomic_inc";
103 
104    v = ones;
105    r = p_atomic_inc_return(&v);
106    ASSERT_EQ(v, 0) << "p_atomic_inc_return";
107    ASSERT_EQ(r, v) << "p_atomic_inc_return";
108 
109    v = 0;
110    p_atomic_dec(&v);
111    ASSERT_EQ(v, ones) << "p_atomic_dec";
112 
113    v = 0;
114    r = p_atomic_dec_return(&v);
115    ASSERT_EQ(v, ones) << "p_atomic_dec_return";
116    ASSERT_EQ(v, r) << "p_atomic_dec_return";
117 }
118 
119 template <typename T> class AtomicAdd : public testing::Test {};
120 
121 using AtomicAddTypes =
122    testing::Types<int, unsigned,
123                   int8_t, uint8_t, int16_t, uint16_t,
124                   int32_t, uint32_t, int64_t, uint64_t>;
125 
126 TYPED_TEST_SUITE(AtomicAdd, AtomicAddTypes);
127 
TYPED_TEST(AtomicAdd, Test)128 TYPED_TEST(AtomicAdd, Test)
129 {
130    TypeParam v, r;
131 
132    v = 23;
133 
134    p_atomic_add(&v, 42);
135    r = p_atomic_read(&v);
136 
137    ASSERT_EQ(r, 65) << "p_atomic_add";
138 }
139