/Users/deen/code/yugabyte-db/src/yb/util/atomic-test.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | |
33 | | #include <thread> |
34 | | |
35 | | #include <gtest/gtest.h> |
36 | | #include "yb/util/random_util.h" |
37 | | #include "yb/util/atomic.h" |
38 | | |
39 | | namespace yb { |
40 | | |
41 | | using std::numeric_limits; |
42 | | using std::vector; |
43 | | |
44 | | // TODO Add some multi-threaded tests; currently AtomicInt is just a |
45 | | // wrapper around 'atomicops.h', but should the underlying |
46 | | // implemention change, it would help to have tests that make sure |
47 | | // invariants are preserved in a multi-threaded environment. |
48 | | |
49 | | template<typename T> |
50 | | class AtomicIntTest : public ::testing::Test { |
51 | | public: |
52 | | |
53 | | AtomicIntTest() |
54 | | : max_(numeric_limits<T>::max()), |
55 | 16 | min_(numeric_limits<T>::min()) { |
56 | 16 | acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease }; |
57 | 16 | barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier }; |
58 | 16 | } _ZN2yb13AtomicIntTestIiEC2Ev Line | Count | Source | 55 | 4 | min_(numeric_limits<T>::min()) { | 56 | 4 | acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease }; | 57 | 4 | barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier }; | 58 | 4 | } |
_ZN2yb13AtomicIntTestIxEC2Ev Line | Count | Source | 55 | 4 | min_(numeric_limits<T>::min()) { | 56 | 4 | acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease }; | 57 | 4 | barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier }; | 58 | 4 | } |
_ZN2yb13AtomicIntTestIjEC2Ev Line | Count | Source | 55 | 4 | min_(numeric_limits<T>::min()) { | 56 | 4 | acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease }; | 57 | 4 | barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier }; | 58 | 4 | } |
_ZN2yb13AtomicIntTestIyEC2Ev Line | Count | Source | 55 | 4 | min_(numeric_limits<T>::min()) { | 56 | 4 | acquire_release_ = { kMemOrderNoBarrier, kMemOrderAcquire, kMemOrderRelease }; | 57 | 4 | barrier_ = { kMemOrderNoBarrier, kMemOrderBarrier }; | 58 | 4 | } |
|
59 | | |
60 | | vector<MemoryOrder> acquire_release_; |
61 | | vector<MemoryOrder> barrier_; |
62 | | |
63 | | T max_; |
64 | | T min_; |
65 | | }; |
66 | | |
67 | | typedef ::testing::Types<int32_t, int64_t, uint32_t, uint64_t> IntTypes; |
68 | | TYPED_TEST_CASE(AtomicIntTest, IntTypes); |
69 | | |
70 | 4 | TYPED_TEST(AtomicIntTest, LoadStore) { |
71 | 12 | for (const MemoryOrder mem_order : this->acquire_release_) { |
72 | 12 | AtomicInt<TypeParam> i(0); |
73 | 12 | EXPECT_EQ(0, i.Load(mem_order)); |
74 | 12 | i.Store(42, mem_order); |
75 | 12 | EXPECT_EQ(42, i.Load(mem_order)); |
76 | 12 | i.Store(this->min_, mem_order); |
77 | 12 | EXPECT_EQ(this->min_, i.Load(mem_order)); |
78 | 12 | i.Store(this->max_, mem_order); |
79 | 12 | EXPECT_EQ(this->max_, i.Load(mem_order)); |
80 | 12 | } |
81 | 4 | } _ZN2yb28AtomicIntTest_LoadStore_TestIiE8TestBodyEv Line | Count | Source | 70 | 1 | TYPED_TEST(AtomicIntTest, LoadStore) { | 71 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 72 | 3 | AtomicInt<TypeParam> i(0); | 73 | 3 | EXPECT_EQ(0, i.Load(mem_order)); | 74 | 3 | i.Store(42, mem_order); | 75 | 3 | EXPECT_EQ(42, i.Load(mem_order)); | 76 | 3 | i.Store(this->min_, mem_order); | 77 | 3 | EXPECT_EQ(this->min_, i.Load(mem_order)); | 78 | 3 | i.Store(this->max_, mem_order); | 79 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 80 | 3 | } | 81 | 1 | } |
_ZN2yb28AtomicIntTest_LoadStore_TestIxE8TestBodyEv Line | Count | Source | 70 | 1 | TYPED_TEST(AtomicIntTest, LoadStore) { | 71 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 72 | 3 | AtomicInt<TypeParam> i(0); | 73 | 3 | EXPECT_EQ(0, i.Load(mem_order)); | 74 | 3 | i.Store(42, mem_order); | 75 | 3 | EXPECT_EQ(42, i.Load(mem_order)); | 76 | 3 | i.Store(this->min_, mem_order); | 77 | 3 | EXPECT_EQ(this->min_, i.Load(mem_order)); | 78 | 3 | i.Store(this->max_, mem_order); | 79 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 80 | 3 | } | 81 | 1 | } |
_ZN2yb28AtomicIntTest_LoadStore_TestIjE8TestBodyEv Line | Count | Source | 70 | 1 | TYPED_TEST(AtomicIntTest, LoadStore) { | 71 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 72 | 3 | AtomicInt<TypeParam> i(0); | 73 | 3 | EXPECT_EQ(0, i.Load(mem_order)); | 74 | 3 | i.Store(42, mem_order); | 75 | 3 | EXPECT_EQ(42, i.Load(mem_order)); | 76 | 3 | i.Store(this->min_, mem_order); | 77 | 3 | EXPECT_EQ(this->min_, i.Load(mem_order)); | 78 | 3 | i.Store(this->max_, mem_order); | 79 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 80 | 3 | } | 81 | 1 | } |
_ZN2yb28AtomicIntTest_LoadStore_TestIyE8TestBodyEv Line | Count | Source | 70 | 1 | TYPED_TEST(AtomicIntTest, LoadStore) { | 71 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 72 | 3 | AtomicInt<TypeParam> i(0); | 73 | 3 | EXPECT_EQ(0, i.Load(mem_order)); | 74 | 3 | i.Store(42, mem_order); | 75 | 3 | EXPECT_EQ(42, i.Load(mem_order)); | 76 | 3 | i.Store(this->min_, mem_order); | 77 | 3 | EXPECT_EQ(this->min_, i.Load(mem_order)); | 78 | 3 | i.Store(this->max_, mem_order); | 79 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 80 | 3 | } | 81 | 1 | } |
|
82 | | |
83 | 4 | TYPED_TEST(AtomicIntTest, SetSwapExchange) { |
84 | 12 | for (const MemoryOrder mem_order : this->acquire_release_) { |
85 | 12 | AtomicInt<TypeParam> i(0); |
86 | 12 | EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order)); |
87 | 12 | EXPECT_EQ(5, i.Load(mem_order)); |
88 | 12 | EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order)); |
89 | | |
90 | 12 | EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order)); |
91 | 12 | EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order)); |
92 | 12 | EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order)); |
93 | | |
94 | 12 | EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order)); |
95 | 12 | EXPECT_EQ(this->max_, i.Load(mem_order)); |
96 | 12 | } |
97 | 4 | } _ZN2yb34AtomicIntTest_SetSwapExchange_TestIiE8TestBodyEv Line | Count | Source | 83 | 1 | TYPED_TEST(AtomicIntTest, SetSwapExchange) { | 84 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 85 | 3 | AtomicInt<TypeParam> i(0); | 86 | 3 | EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order)); | 87 | 3 | EXPECT_EQ(5, i.Load(mem_order)); | 88 | 3 | EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order)); | 89 | | | 90 | 3 | EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order)); | 91 | 3 | EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order)); | 92 | 3 | EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order)); | 93 | | | 94 | 3 | EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order)); | 95 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 96 | 3 | } | 97 | 1 | } |
_ZN2yb34AtomicIntTest_SetSwapExchange_TestIxE8TestBodyEv Line | Count | Source | 83 | 1 | TYPED_TEST(AtomicIntTest, SetSwapExchange) { | 84 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 85 | 3 | AtomicInt<TypeParam> i(0); | 86 | 3 | EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order)); | 87 | 3 | EXPECT_EQ(5, i.Load(mem_order)); | 88 | 3 | EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order)); | 89 | | | 90 | 3 | EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order)); | 91 | 3 | EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order)); | 92 | 3 | EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order)); | 93 | | | 94 | 3 | EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order)); | 95 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 96 | 3 | } | 97 | 1 | } |
_ZN2yb34AtomicIntTest_SetSwapExchange_TestIjE8TestBodyEv Line | Count | Source | 83 | 1 | TYPED_TEST(AtomicIntTest, SetSwapExchange) { | 84 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 85 | 3 | AtomicInt<TypeParam> i(0); | 86 | 3 | EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order)); | 87 | 3 | EXPECT_EQ(5, i.Load(mem_order)); | 88 | 3 | EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order)); | 89 | | | 90 | 3 | EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order)); | 91 | 3 | EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order)); | 92 | 3 | EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order)); | 93 | | | 94 | 3 | EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order)); | 95 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 96 | 3 | } | 97 | 1 | } |
_ZN2yb34AtomicIntTest_SetSwapExchange_TestIyE8TestBodyEv Line | Count | Source | 83 | 1 | TYPED_TEST(AtomicIntTest, SetSwapExchange) { | 84 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 85 | 3 | AtomicInt<TypeParam> i(0); | 86 | 3 | EXPECT_TRUE(i.CompareAndSet(0, 5, mem_order)); | 87 | 3 | EXPECT_EQ(5, i.Load(mem_order)); | 88 | 3 | EXPECT_FALSE(i.CompareAndSet(0, 10, mem_order)); | 89 | | | 90 | 3 | EXPECT_EQ(5, i.CompareAndSwap(5, this->max_, mem_order)); | 91 | 3 | EXPECT_EQ(this->max_, i.CompareAndSwap(42, 42, mem_order)); | 92 | 3 | EXPECT_EQ(this->max_, i.CompareAndSwap(this->max_, this->min_, mem_order)); | 93 | | | 94 | 3 | EXPECT_EQ(this->min_, i.Exchange(this->max_, mem_order)); | 95 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 96 | 3 | } | 97 | 1 | } |
|
98 | | |
99 | 4 | TYPED_TEST(AtomicIntTest, MinMax) { |
100 | 12 | for (const MemoryOrder mem_order : this->acquire_release_) { |
101 | 12 | AtomicInt<TypeParam> i(0); |
102 | | |
103 | 12 | i.StoreMax(100, mem_order); |
104 | 12 | EXPECT_EQ(100, i.Load(mem_order)); |
105 | 12 | i.StoreMin(50, mem_order); |
106 | 12 | EXPECT_EQ(50, i.Load(mem_order)); |
107 | | |
108 | 12 | i.StoreMax(25, mem_order); |
109 | 12 | EXPECT_EQ(50, i.Load(mem_order)); |
110 | 12 | i.StoreMin(75, mem_order); |
111 | 12 | EXPECT_EQ(50, i.Load(mem_order)); |
112 | | |
113 | 12 | i.StoreMax(this->max_, mem_order); |
114 | 12 | EXPECT_EQ(this->max_, i.Load(mem_order)); |
115 | 12 | i.StoreMin(this->min_, mem_order); |
116 | 12 | EXPECT_EQ(this->min_, i.Load(mem_order)); |
117 | 12 | } |
118 | 4 | } _ZN2yb25AtomicIntTest_MinMax_TestIiE8TestBodyEv Line | Count | Source | 99 | 1 | TYPED_TEST(AtomicIntTest, MinMax) { | 100 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 101 | 3 | AtomicInt<TypeParam> i(0); | 102 | | | 103 | 3 | i.StoreMax(100, mem_order); | 104 | 3 | EXPECT_EQ(100, i.Load(mem_order)); | 105 | 3 | i.StoreMin(50, mem_order); | 106 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 107 | | | 108 | 3 | i.StoreMax(25, mem_order); | 109 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 110 | 3 | i.StoreMin(75, mem_order); | 111 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 112 | | | 113 | 3 | i.StoreMax(this->max_, mem_order); | 114 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 115 | 3 | i.StoreMin(this->min_, mem_order); | 116 | 3 | EXPECT_EQ(this->min_, i.Load(mem_order)); | 117 | 3 | } | 118 | 1 | } |
_ZN2yb25AtomicIntTest_MinMax_TestIxE8TestBodyEv Line | Count | Source | 99 | 1 | TYPED_TEST(AtomicIntTest, MinMax) { | 100 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 101 | 3 | AtomicInt<TypeParam> i(0); | 102 | | | 103 | 3 | i.StoreMax(100, mem_order); | 104 | 3 | EXPECT_EQ(100, i.Load(mem_order)); | 105 | 3 | i.StoreMin(50, mem_order); | 106 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 107 | | | 108 | 3 | i.StoreMax(25, mem_order); | 109 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 110 | 3 | i.StoreMin(75, mem_order); | 111 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 112 | | | 113 | 3 | i.StoreMax(this->max_, mem_order); | 114 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 115 | 3 | i.StoreMin(this->min_, mem_order); | 116 | 3 | EXPECT_EQ(this->min_, i.Load(mem_order)); | 117 | 3 | } | 118 | 1 | } |
_ZN2yb25AtomicIntTest_MinMax_TestIjE8TestBodyEv Line | Count | Source | 99 | 1 | TYPED_TEST(AtomicIntTest, MinMax) { | 100 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 101 | 3 | AtomicInt<TypeParam> i(0); | 102 | | | 103 | 3 | i.StoreMax(100, mem_order); | 104 | 3 | EXPECT_EQ(100, i.Load(mem_order)); | 105 | 3 | i.StoreMin(50, mem_order); | 106 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 107 | | | 108 | 3 | i.StoreMax(25, mem_order); | 109 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 110 | 3 | i.StoreMin(75, mem_order); | 111 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 112 | | | 113 | 3 | i.StoreMax(this->max_, mem_order); | 114 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 115 | 3 | i.StoreMin(this->min_, mem_order); | 116 | 3 | EXPECT_EQ(this->min_, i.Load(mem_order)); | 117 | 3 | } | 118 | 1 | } |
_ZN2yb25AtomicIntTest_MinMax_TestIyE8TestBodyEv Line | Count | Source | 99 | 1 | TYPED_TEST(AtomicIntTest, MinMax) { | 100 | 3 | for (const MemoryOrder mem_order : this->acquire_release_) { | 101 | 3 | AtomicInt<TypeParam> i(0); | 102 | | | 103 | 3 | i.StoreMax(100, mem_order); | 104 | 3 | EXPECT_EQ(100, i.Load(mem_order)); | 105 | 3 | i.StoreMin(50, mem_order); | 106 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 107 | | | 108 | 3 | i.StoreMax(25, mem_order); | 109 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 110 | 3 | i.StoreMin(75, mem_order); | 111 | 3 | EXPECT_EQ(50, i.Load(mem_order)); | 112 | | | 113 | 3 | i.StoreMax(this->max_, mem_order); | 114 | 3 | EXPECT_EQ(this->max_, i.Load(mem_order)); | 115 | 3 | i.StoreMin(this->min_, mem_order); | 116 | 3 | EXPECT_EQ(this->min_, i.Load(mem_order)); | 117 | 3 | } | 118 | 1 | } |
|
119 | | |
120 | 4 | TYPED_TEST(AtomicIntTest, Increment) { |
121 | 8 | for (const MemoryOrder mem_order : this->barrier_) { |
122 | 8 | AtomicInt<TypeParam> i(0); |
123 | 8 | EXPECT_EQ(1, i.Increment(mem_order)); |
124 | 8 | EXPECT_EQ(3, i.IncrementBy(2, mem_order)); |
125 | 8 | EXPECT_EQ(3, i.IncrementBy(0, mem_order)); |
126 | 8 | } |
127 | 4 | } _ZN2yb28AtomicIntTest_Increment_TestIiE8TestBodyEv Line | Count | Source | 120 | 1 | TYPED_TEST(AtomicIntTest, Increment) { | 121 | 2 | for (const MemoryOrder mem_order : this->barrier_) { | 122 | 2 | AtomicInt<TypeParam> i(0); | 123 | 2 | EXPECT_EQ(1, i.Increment(mem_order)); | 124 | 2 | EXPECT_EQ(3, i.IncrementBy(2, mem_order)); | 125 | 2 | EXPECT_EQ(3, i.IncrementBy(0, mem_order)); | 126 | 2 | } | 127 | 1 | } |
_ZN2yb28AtomicIntTest_Increment_TestIxE8TestBodyEv Line | Count | Source | 120 | 1 | TYPED_TEST(AtomicIntTest, Increment) { | 121 | 2 | for (const MemoryOrder mem_order : this->barrier_) { | 122 | 2 | AtomicInt<TypeParam> i(0); | 123 | 2 | EXPECT_EQ(1, i.Increment(mem_order)); | 124 | 2 | EXPECT_EQ(3, i.IncrementBy(2, mem_order)); | 125 | 2 | EXPECT_EQ(3, i.IncrementBy(0, mem_order)); | 126 | 2 | } | 127 | 1 | } |
_ZN2yb28AtomicIntTest_Increment_TestIjE8TestBodyEv Line | Count | Source | 120 | 1 | TYPED_TEST(AtomicIntTest, Increment) { | 121 | 2 | for (const MemoryOrder mem_order : this->barrier_) { | 122 | 2 | AtomicInt<TypeParam> i(0); | 123 | 2 | EXPECT_EQ(1, i.Increment(mem_order)); | 124 | 2 | EXPECT_EQ(3, i.IncrementBy(2, mem_order)); | 125 | 2 | EXPECT_EQ(3, i.IncrementBy(0, mem_order)); | 126 | 2 | } | 127 | 1 | } |
_ZN2yb28AtomicIntTest_Increment_TestIyE8TestBodyEv Line | Count | Source | 120 | 1 | TYPED_TEST(AtomicIntTest, Increment) { | 121 | 2 | for (const MemoryOrder mem_order : this->barrier_) { | 122 | 2 | AtomicInt<TypeParam> i(0); | 123 | 2 | EXPECT_EQ(1, i.Increment(mem_order)); | 124 | 2 | EXPECT_EQ(3, i.IncrementBy(2, mem_order)); | 125 | 2 | EXPECT_EQ(3, i.IncrementBy(0, mem_order)); | 126 | 2 | } | 127 | 1 | } |
|
128 | | |
129 | 1 | TEST(Atomic, AtomicBool) { |
130 | 1 | vector<MemoryOrder> memory_orders = { kMemOrderNoBarrier, kMemOrderRelease, kMemOrderAcquire }; |
131 | 3 | for (const MemoryOrder mem_order : memory_orders) { |
132 | 3 | AtomicBool b(false); |
133 | 3 | EXPECT_FALSE(b.Load(mem_order)); |
134 | 3 | b.Store(true, mem_order); |
135 | 3 | EXPECT_TRUE(b.Load(mem_order)); |
136 | 3 | EXPECT_TRUE(b.CompareAndSet(true, false, mem_order)); |
137 | 3 | EXPECT_FALSE(b.Load(mem_order)); |
138 | 3 | EXPECT_FALSE(b.CompareAndSet(true, false, mem_order)); |
139 | 3 | EXPECT_FALSE(b.CompareAndSwap(false, true, mem_order)); |
140 | 3 | EXPECT_TRUE(b.Load(mem_order)); |
141 | 3 | EXPECT_TRUE(b.Exchange(false, mem_order)); |
142 | 3 | EXPECT_FALSE(b.Load(mem_order)); |
143 | 3 | } |
144 | 1 | } |
145 | | |
146 | | class TestObj { |
147 | | public: |
148 | 250k | TestObj(size_t index, std::atomic<size_t>* counter) : index_(index), counter_(counter) { |
149 | 250k | ++(*counter_); |
150 | 250k | } |
151 | 326k | ~TestObj() { --(*counter_); } |
152 | 2.00k | size_t index() { return index_; } |
153 | | |
154 | | private: |
155 | | size_t index_; |
156 | | std::atomic<size_t>* counter_; |
157 | | }; |
158 | | |
159 | 1 | TEST(Atomic, AtomicUniquePtr) { |
160 | 1 | static constexpr size_t kNumObjects = 1000; |
161 | 1 | static constexpr size_t kNumThreads = 32; |
162 | 1 | static constexpr size_t kNumIterations = 50000; |
163 | | |
164 | 1 | std::atomic<size_t> counter = { 0 }; |
165 | | |
166 | 1 | { |
167 | 1 | std::vector<AtomicUniquePtr<TestObj>> ptrs; |
168 | 1 | ptrs.reserve(kNumObjects); |
169 | | |
170 | 1.00k | for (size_t i = 0; i < kNumObjects; ++i) { |
171 | 1.00k | ptrs.push_back(MakeAtomicUniquePtr<TestObj>(i, &counter)); |
172 | 1.00k | } |
173 | 1 | EXPECT_EQ(kNumObjects, counter.load()); |
174 | 1.00k | for (size_t i = 0; i < kNumObjects; ++i) { |
175 | 1.00k | ASSERT_EQ(ptrs[i].get()->index(), i); |
176 | 1.00k | } |
177 | | |
178 | 30 | auto task = [&ptrs, &counter]() { |
179 | 30 | std::mt19937 rng; |
180 | 30 | Seed(&rng); |
181 | 30 | std::uniform_int_distribution<size_t> random_op(0, 4); |
182 | 30 | std::uniform_int_distribution<size_t> random_index(0, kNumObjects - 1); |
183 | | |
184 | 1.13M | for (size_t i = 0; i < kNumIterations; ++i) { |
185 | 1.13M | switch (random_op(rng)) { |
186 | 253k | case 0: { |
187 | | // Get. |
188 | 253k | auto i1 = random_index(rng); |
189 | 253k | ptrs[i1].get(); |
190 | 253k | break; |
191 | 0 | } |
192 | 254k | case 1: { |
193 | | // Release (only half of ptrs, keep the other half to test release on destruction). |
194 | 254k | auto i1 = random_index(rng); |
195 | 254k | if (i1 % 2 == 0) { |
196 | 142k | TestObj *ptr = ptrs[i1].release(); |
197 | 142k | delete ptr; |
198 | 142k | } |
199 | 254k | break; |
200 | 0 | } |
201 | 253k | case 2: { |
202 | | // Reset. |
203 | 253k | auto i1 = random_index(rng); |
204 | 253k | ptrs[i1].reset(new TestObj(i1, &counter)); |
205 | 253k | break; |
206 | 0 | } |
207 | 253k | case 3: { |
208 | | // Assign. |
209 | 253k | auto i1 = random_index(rng); |
210 | 253k | auto i2 = random_index(rng); |
211 | 253k | ptrs[i1] = std::move(ptrs[i2]); |
212 | 253k | break; |
213 | 0 | } |
214 | 254k | case 4: { |
215 | | // Move construction. |
216 | 254k | auto i1 = random_index(rng); |
217 | 254k | AtomicUniquePtr<TestObj> ptr(std::move(ptrs[i1])); |
218 | 254k | break; |
219 | 0 | } |
220 | 0 | default: |
221 | 0 | ASSERT_TRUE(false) << "Test internal error, missed case in switch"; |
222 | 0 | break; |
223 | 1.13M | } |
224 | 1.13M | } |
225 | 30 | }; |
226 | | |
227 | 1 | std::vector<std::thread> threads; |
228 | 1 | threads.reserve(kNumThreads); |
229 | 33 | for (size_t i = 0; i < kNumThreads; ++i) { |
230 | 32 | threads.push_back(std::thread(task)); |
231 | 32 | } |
232 | 32 | for (auto& thread : threads) { |
233 | 32 | thread.join(); |
234 | 32 | } |
235 | 1 | } |
236 | | |
237 | 1 | EXPECT_EQ(0, counter.load()); |
238 | 1 | } |
239 | | |
240 | | } // namespace yb |