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 r = p_atomic_read_relaxed(&v);
60 ASSERT_EQ(r, ones) << "p_atomic_read_relaxed";
61
62 v = ones;
63 r = p_atomic_cmpxchg(&v, 0, 1);
64 ASSERT_EQ(v, ones) << "p_atomic_cmpxchg";
65 ASSERT_EQ(r, ones) << "p_atomic_cmpxchg";
66
67 r = p_atomic_cmpxchg(&v, ones, 0);
68 ASSERT_EQ(v, 0) << "p_atomic_cmpxchg";
69 ASSERT_EQ(r, ones) << "p_atomic_cmpxchg";
70
71 v = 0;
72 r = p_atomic_xchg(&v, ones);
73 ASSERT_EQ(v, ones) << "p_atomic_xchg";
74 ASSERT_EQ(r, 0) << "p_atomic_xchg";
75 }
76
77
78 template <typename T> class AtomicIncrementDecrement : public testing::Test {};
79
80 using AtomicIncrementDecrementTypes =
81 testing::Types<int, unsigned,
82 int8_t, uint8_t,
83 int16_t, uint16_t,
84 int32_t, uint32_t, int64_t, uint64_t>;
85
86 TYPED_TEST_SUITE(AtomicIncrementDecrement, AtomicIncrementDecrementTypes);
87
TYPED_TEST(AtomicIncrementDecrement,Test)88 TYPED_TEST(AtomicIncrementDecrement, Test)
89 {
90 TypeParam v, r;
91 bool b;
92
93 const TypeParam ones = TypeParam(-1);
94
95 v = 2;
96
97 b = p_atomic_dec_zero(&v);
98 ASSERT_EQ(v, 1) << "p_atomic_dec_zero";
99 ASSERT_FALSE(b) << "p_atomic_dec_zero";
100
101 b = p_atomic_dec_zero(&v);
102 ASSERT_EQ(v, 0) << "p_atomic_dec_zero";
103 ASSERT_TRUE(b) << "p_atomic_dec_zero";
104
105 b = p_atomic_dec_zero(&v);
106 ASSERT_EQ(v, ones) << "p_atomic_dec_zero";
107 ASSERT_FALSE(b) << "p_atomic_dec_zero";
108
109 v = ones;
110 p_atomic_inc(&v);
111 ASSERT_EQ(v, 0) << "p_atomic_inc";
112
113 v = ones;
114 r = p_atomic_inc_return(&v);
115 ASSERT_EQ(v, 0) << "p_atomic_inc_return";
116 ASSERT_EQ(r, v) << "p_atomic_inc_return";
117
118 v = 0;
119 p_atomic_dec(&v);
120 ASSERT_EQ(v, ones) << "p_atomic_dec";
121
122 v = 0;
123 r = p_atomic_dec_return(&v);
124 ASSERT_EQ(v, ones) << "p_atomic_dec_return";
125 ASSERT_EQ(v, r) << "p_atomic_dec_return";
126
127 v = 0;
128 r = p_atomic_add_return(&v, -1);
129 ASSERT_EQ(v, ones) << "p_atomic_add_return";
130 ASSERT_EQ(v, r) << "p_atomic_add_return";
131
132 v = 0;
133 r = p_atomic_fetch_add(&v, -1);
134 ASSERT_EQ(v, ones) << "p_atomic_fetch_add";
135 ASSERT_EQ(r, 0) << "p_atomic_fetch_add";
136 }
137
138 template <typename T> class AtomicAdd : public testing::Test {};
139
140 using AtomicAddTypes =
141 testing::Types<int, unsigned,
142 int8_t, uint8_t, int16_t, uint16_t,
143 int32_t, uint32_t, int64_t, uint64_t>;
144
145 TYPED_TEST_SUITE(AtomicAdd, AtomicAddTypes);
146
TYPED_TEST(AtomicAdd,Test)147 TYPED_TEST(AtomicAdd, Test)
148 {
149 TypeParam v, r;
150
151 v = 23;
152
153 p_atomic_add(&v, 42);
154 r = p_atomic_read(&v);
155
156 ASSERT_EQ(r, 65) << "p_atomic_add";
157 }
158