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