147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2014 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <set>
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <vector>
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/criticalsection.h"
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/event.h"
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/gunit.h"
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/scopedptrcollection.h"
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/thread.h"
19a127c9555d5bc8d9404562840ebfd5281c670600henrike@webrtc.org#include "webrtc/test/testsupport/gtest_disable.h"
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace {
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst int kLongTime = 10000;  // 10 seconds
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst int kNumThreads = 16;
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst int kOperationsToRun = 1000;
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgtemplate <class T>
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass AtomicOpRunner : public MessageHandler {
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public:
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  explicit AtomicOpRunner(int initial_value)
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      : value_(initial_value),
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        threads_active_(0),
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        start_event_(true, false),
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        done_event_(true, false) {}
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int value() const { return value_; }
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool Run() {
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Signal all threads to start.
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    start_event_.Set();
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Wait for all threads to finish.
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return done_event_.Wait(kLongTime);
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void SetExpectedThreadCount(int count) {
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    threads_active_ = count;
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual void OnMessage(Message* msg) {
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    std::vector<int> values;
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    values.reserve(kOperationsToRun);
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Wait to start.
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT_TRUE(start_event_.Wait(kLongTime));
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Generate a bunch of values by updating value_ atomically.
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    for (int i = 0; i < kOperationsToRun; ++i) {
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      values.push_back(T::AtomicOp(&value_));
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    { // Add them all to the set.
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CritScope cs(&all_values_crit_);
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      for (size_t i = 0; i < values.size(); ++i) {
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        std::pair<std::set<int>::iterator, bool> result =
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            all_values_.insert(values[i]);
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        // Each value should only be taken by one thread, so if this value
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        // has already been added, something went wrong.
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        EXPECT_TRUE(result.second)
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            << "Thread=" << Thread::Current() << " value=" << values[i];
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Signal that we're done.
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (AtomicOps::Decrement(&threads_active_) == 0) {
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      done_event_.Set();
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private:
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int value_;
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int threads_active_;
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CriticalSection all_values_crit_;
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  std::set<int> all_values_;
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Event start_event_;
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Event done_event_;
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstruct IncrementOp {
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  static int AtomicOp(int* i) { return AtomicOps::Increment(i); }
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstruct DecrementOp {
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  static int AtomicOp(int* i) { return AtomicOps::Decrement(i); }
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid StartThreads(ScopedPtrCollection<Thread>* threads,
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                  MessageHandler* handler) {
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  for (int i = 0; i < kNumThreads; ++i) {
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Thread* thread = new Thread();
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    thread->Start();
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    thread->Post(handler);
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    threads->PushBack(thread);
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgTEST(AtomicOpsTest, Simple) {
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int value = 0;
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(1, AtomicOps::Increment(&value));
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(1, value);
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(2, AtomicOps::Increment(&value));
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(2, value);
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(1, AtomicOps::Decrement(&value));
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(1, value);
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(0, AtomicOps::Decrement(&value));
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(0, value);
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
123a127c9555d5bc8d9404562840ebfd5281c670600henrike@webrtc.orgTEST(AtomicOpsTest, DISABLED_ON_MAC(Increment)) {
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Create and start lots of threads.
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  AtomicOpRunner<IncrementOp> runner(0);
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ScopedPtrCollection<Thread> threads;
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StartThreads(&threads, &runner);
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  runner.SetExpectedThreadCount(kNumThreads);
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Release the hounds!
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_TRUE(runner.Run());
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(kOperationsToRun * kNumThreads, runner.value());
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
135a127c9555d5bc8d9404562840ebfd5281c670600henrike@webrtc.orgTEST(AtomicOpsTest, DISABLED_ON_MAC(Decrement)) {
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Create and start lots of threads.
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  AtomicOpRunner<DecrementOp> runner(kOperationsToRun * kNumThreads);
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ScopedPtrCollection<Thread> threads;
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StartThreads(&threads, &runner);
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  runner.SetExpectedThreadCount(kNumThreads);
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Release the hounds!
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_TRUE(runner.Run());
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(0, runner.value());
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace rtc
148