Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / base / criticalsection_unittest.cc
1 /*
2  * libjingle
3  * Copyright 2014, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <set>
29 #include <vector>
30
31 #include "talk/base/criticalsection.h"
32 #include "talk/base/event.h"
33 #include "talk/base/gunit.h"
34 #include "talk/base/scopedptrcollection.h"
35 #include "talk/base/thread.h"
36
37 namespace talk_base {
38
39 namespace {
40
41 const int kLongTime = 10000;  // 10 seconds
42 const int kNumThreads = 16;
43 const int kOperationsToRun = 1000;
44
45 template <class T>
46 class AtomicOpRunner : public MessageHandler {
47  public:
48   explicit AtomicOpRunner(int initial_value)
49       : value_(initial_value),
50         threads_active_(0),
51         start_event_(true, false),
52         done_event_(true, false) {}
53
54   int value() const { return value_; }
55
56   bool Run() {
57     // Signal all threads to start.
58     start_event_.Set();
59
60     // Wait for all threads to finish.
61     return done_event_.Wait(kLongTime);
62   }
63
64   void SetExpectedThreadCount(int count) {
65     threads_active_ = count;
66   }
67
68   virtual void OnMessage(Message* msg) {
69     std::vector<int> values;
70     values.reserve(kOperationsToRun);
71
72     // Wait to start.
73     ASSERT_TRUE(start_event_.Wait(kLongTime));
74
75     // Generate a bunch of values by updating value_ atomically.
76     for (int i = 0; i < kOperationsToRun; ++i) {
77       values.push_back(T::AtomicOp(&value_));
78     }
79
80     { // Add them all to the set.
81       CritScope cs(&all_values_crit_);
82       for (size_t i = 0; i < values.size(); ++i) {
83         std::pair<std::set<int>::iterator, bool> result =
84             all_values_.insert(values[i]);
85         // Each value should only be taken by one thread, so if this value
86         // has already been added, something went wrong.
87         EXPECT_TRUE(result.second)
88             << "Thread=" << Thread::Current() << " value=" << values[i];
89       }
90     }
91
92     // Signal that we're done.
93     if (AtomicOps::Decrement(&threads_active_) == 0) {
94       done_event_.Set();
95     }
96   }
97
98  private:
99   int value_;
100   int threads_active_;
101   CriticalSection all_values_crit_;
102   std::set<int> all_values_;
103   Event start_event_;
104   Event done_event_;
105 };
106
107 struct IncrementOp {
108   static int AtomicOp(int* i) { return AtomicOps::Increment(i); }
109 };
110
111 struct DecrementOp {
112   static int AtomicOp(int* i) { return AtomicOps::Decrement(i); }
113 };
114
115 void StartThreads(ScopedPtrCollection<Thread>* threads,
116                   MessageHandler* handler) {
117   for (int i = 0; i < kNumThreads; ++i) {
118     Thread* thread = new Thread();
119     thread->Start();
120     thread->Post(handler);
121     threads->PushBack(thread);
122   }
123 }
124
125 }  // namespace
126
127 TEST(AtomicOpsTest, Simple) {
128   int value = 0;
129   EXPECT_EQ(1, AtomicOps::Increment(&value));
130   EXPECT_EQ(1, value);
131   EXPECT_EQ(2, AtomicOps::Increment(&value));
132   EXPECT_EQ(2, value);
133   EXPECT_EQ(1, AtomicOps::Decrement(&value));
134   EXPECT_EQ(1, value);
135   EXPECT_EQ(0, AtomicOps::Decrement(&value));
136   EXPECT_EQ(0, value);
137 }
138
139 TEST(AtomicOpsTest, Increment) {
140   // Create and start lots of threads.
141   AtomicOpRunner<IncrementOp> runner(0);
142   ScopedPtrCollection<Thread> threads;
143   StartThreads(&threads, &runner);
144   runner.SetExpectedThreadCount(kNumThreads);
145
146   // Release the hounds!
147   EXPECT_TRUE(runner.Run());
148   EXPECT_EQ(kOperationsToRun * kNumThreads, runner.value());
149 }
150
151 TEST(AtomicOpsTest, Decrement) {
152   // Create and start lots of threads.
153   AtomicOpRunner<DecrementOp> runner(kOperationsToRun * kNumThreads);
154   ScopedPtrCollection<Thread> threads;
155   StartThreads(&threads, &runner);
156   runner.SetExpectedThreadCount(kNumThreads);
157
158   // Release the hounds!
159   EXPECT_TRUE(runner.Run());
160   EXPECT_EQ(0, runner.value());
161 }
162
163 }  // namespace talk_base