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"
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace {
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst int kLongTime = 10000;  // 10 seconds
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst int kNumThreads = 16;
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst int kOperationsToRun = 1000;
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgtemplate <class T>
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass AtomicOpRunner : public MessageHandler {
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public:
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  explicit AtomicOpRunner(int initial_value)
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      : value_(initial_value),
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        threads_active_(0),
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        start_event_(true, false),
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        done_event_(true, false) {}
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int value() const { return value_; }
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool Run() {
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Signal all threads to start.
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    start_event_.Set();
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Wait for all threads to finish.
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return done_event_.Wait(kLongTime);
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void SetExpectedThreadCount(int count) {
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    threads_active_ = count;
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual void OnMessage(Message* msg) {
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    std::vector<int> values;
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    values.reserve(kOperationsToRun);
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Wait to start.
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT_TRUE(start_event_.Wait(kLongTime));
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Generate a bunch of values by updating value_ atomically.
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    for (int i = 0; i < kOperationsToRun; ++i) {
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      values.push_back(T::AtomicOp(&value_));
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    { // Add them all to the set.
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CritScope cs(&all_values_crit_);
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      for (size_t i = 0; i < values.size(); ++i) {
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        std::pair<std::set<int>::iterator, bool> result =
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            all_values_.insert(values[i]);
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        // Each value should only be taken by one thread, so if this value
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        // has already been added, something went wrong.
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        EXPECT_TRUE(result.second)
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            << "Thread=" << Thread::Current() << " value=" << values[i];
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Signal that we're done.
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (AtomicOps::Decrement(&threads_active_) == 0) {
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      done_event_.Set();
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private:
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int value_;
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int threads_active_;
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CriticalSection all_values_crit_;
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  std::set<int> all_values_;
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Event start_event_;
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Event done_event_;
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstruct IncrementOp {
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  static int AtomicOp(int* i) { return AtomicOps::Increment(i); }
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstruct DecrementOp {
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  static int AtomicOp(int* i) { return AtomicOps::Decrement(i); }
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid StartThreads(ScopedPtrCollection<Thread>* threads,
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                  MessageHandler* handler) {
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  for (int i = 0; i < kNumThreads; ++i) {
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Thread* thread = new Thread();
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    thread->Start();
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    thread->Post(handler);
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    threads->PushBack(thread);
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgTEST(AtomicOpsTest, Simple) {
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int value = 0;
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(1, AtomicOps::Increment(&value));
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(1, value);
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(2, AtomicOps::Increment(&value));
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(2, value);
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(1, AtomicOps::Decrement(&value));
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(1, value);
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(0, AtomicOps::Decrement(&value));
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(0, value);
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgTEST(AtomicOpsTest, Increment) {
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Create and start lots of threads.
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  AtomicOpRunner<IncrementOp> runner(0);
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ScopedPtrCollection<Thread> threads;
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StartThreads(&threads, &runner);
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  runner.SetExpectedThreadCount(kNumThreads);
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Release the hounds!
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_TRUE(runner.Run());
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(kOperationsToRun * kNumThreads, runner.value());
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgTEST(AtomicOpsTest, Decrement) {
13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Create and start lots of threads.
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  AtomicOpRunner<DecrementOp> runner(kOperationsToRun * kNumThreads);
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ScopedPtrCollection<Thread> threads;
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StartThreads(&threads, &runner);
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  runner.SetExpectedThreadCount(kNumThreads);
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Release the hounds!
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_TRUE(runner.Run());
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EXPECT_EQ(0, runner.value());
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace rtc
147