1 /* 2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <set> 12 #include <vector> 13 14 #include "webrtc/base/criticalsection.h" 15 #include "webrtc/base/event.h" 16 #include "webrtc/base/gunit.h" 17 #include "webrtc/base/scopedptrcollection.h" 18 #include "webrtc/base/thread.h" 19 #include "webrtc/test/testsupport/gtest_disable.h" 20 21 namespace rtc { 22 23 namespace { 24 25 const int kLongTime = 10000; // 10 seconds 26 const int kNumThreads = 16; 27 const int kOperationsToRun = 1000; 28 29 template <class T> 30 class AtomicOpRunner : public MessageHandler { 31 public: 32 explicit AtomicOpRunner(int initial_value) 33 : value_(initial_value), 34 threads_active_(0), 35 start_event_(true, false), 36 done_event_(true, false) {} 37 38 int value() const { return value_; } 39 40 bool Run() { 41 // Signal all threads to start. 42 start_event_.Set(); 43 44 // Wait for all threads to finish. 45 return done_event_.Wait(kLongTime); 46 } 47 48 void SetExpectedThreadCount(int count) { 49 threads_active_ = count; 50 } 51 52 virtual void OnMessage(Message* msg) { 53 std::vector<int> values; 54 values.reserve(kOperationsToRun); 55 56 // Wait to start. 57 ASSERT_TRUE(start_event_.Wait(kLongTime)); 58 59 // Generate a bunch of values by updating value_ atomically. 60 for (int i = 0; i < kOperationsToRun; ++i) { 61 values.push_back(T::AtomicOp(&value_)); 62 } 63 64 { // Add them all to the set. 65 CritScope cs(&all_values_crit_); 66 for (size_t i = 0; i < values.size(); ++i) { 67 std::pair<std::set<int>::iterator, bool> result = 68 all_values_.insert(values[i]); 69 // Each value should only be taken by one thread, so if this value 70 // has already been added, something went wrong. 71 EXPECT_TRUE(result.second) 72 << "Thread=" << Thread::Current() << " value=" << values[i]; 73 } 74 } 75 76 // Signal that we're done. 77 if (AtomicOps::Decrement(&threads_active_) == 0) { 78 done_event_.Set(); 79 } 80 } 81 82 private: 83 int value_; 84 int threads_active_; 85 CriticalSection all_values_crit_; 86 std::set<int> all_values_; 87 Event start_event_; 88 Event done_event_; 89 }; 90 91 struct IncrementOp { 92 static int AtomicOp(int* i) { return AtomicOps::Increment(i); } 93 }; 94 95 struct DecrementOp { 96 static int AtomicOp(int* i) { return AtomicOps::Decrement(i); } 97 }; 98 99 void StartThreads(ScopedPtrCollection<Thread>* threads, 100 MessageHandler* handler) { 101 for (int i = 0; i < kNumThreads; ++i) { 102 Thread* thread = new Thread(); 103 thread->Start(); 104 thread->Post(handler); 105 threads->PushBack(thread); 106 } 107 } 108 109 } // namespace 110 111 TEST(AtomicOpsTest, Simple) { 112 int value = 0; 113 EXPECT_EQ(1, AtomicOps::Increment(&value)); 114 EXPECT_EQ(1, value); 115 EXPECT_EQ(2, AtomicOps::Increment(&value)); 116 EXPECT_EQ(2, value); 117 EXPECT_EQ(1, AtomicOps::Decrement(&value)); 118 EXPECT_EQ(1, value); 119 EXPECT_EQ(0, AtomicOps::Decrement(&value)); 120 EXPECT_EQ(0, value); 121 } 122 123 TEST(AtomicOpsTest, DISABLED_ON_MAC(Increment)) { 124 // Create and start lots of threads. 125 AtomicOpRunner<IncrementOp> runner(0); 126 ScopedPtrCollection<Thread> threads; 127 StartThreads(&threads, &runner); 128 runner.SetExpectedThreadCount(kNumThreads); 129 130 // Release the hounds! 131 EXPECT_TRUE(runner.Run()); 132 EXPECT_EQ(kOperationsToRun * kNumThreads, runner.value()); 133 } 134 135 TEST(AtomicOpsTest, DISABLED_ON_MAC(Decrement)) { 136 // Create and start lots of threads. 137 AtomicOpRunner<DecrementOp> runner(kOperationsToRun * kNumThreads); 138 ScopedPtrCollection<Thread> threads; 139 StartThreads(&threads, &runner); 140 runner.SetExpectedThreadCount(kNumThreads); 141 142 // Release the hounds! 143 EXPECT_TRUE(runner.Run()); 144 EXPECT_EQ(0, runner.value()); 145 } 146 147 } // namespace rtc 148