1/*
2 *  Copyright 2011 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 "webrtc/base/common.h"
12#include "webrtc/base/gunit.h"
13#include "webrtc/base/messagehandler.h"
14#include "webrtc/base/messagequeue.h"
15#include "webrtc/base/scoped_ptr.h"
16#include "webrtc/base/sharedexclusivelock.h"
17#include "webrtc/base/thread.h"
18#include "webrtc/base/timeutils.h"
19#include "webrtc/test/testsupport/gtest_disable.h"
20
21namespace rtc {
22
23static const uint32 kMsgRead = 0;
24static const uint32 kMsgWrite = 0;
25static const int kNoWaitThresholdInMs = 10;
26static const int kWaitThresholdInMs = 80;
27static const int kProcessTimeInMs = 100;
28static const int kProcessTimeoutInMs = 5000;
29
30class SharedExclusiveTask : public MessageHandler {
31 public:
32  SharedExclusiveTask(SharedExclusiveLock* shared_exclusive_lock,
33                      int* value,
34                      bool* done)
35      : shared_exclusive_lock_(shared_exclusive_lock),
36        waiting_time_in_ms_(0),
37        value_(value),
38        done_(done) {
39    worker_thread_.reset(new Thread());
40    worker_thread_->Start();
41  }
42
43  int waiting_time_in_ms() const { return waiting_time_in_ms_; }
44
45 protected:
46  scoped_ptr<Thread> worker_thread_;
47  SharedExclusiveLock* shared_exclusive_lock_;
48  int waiting_time_in_ms_;
49  int* value_;
50  bool* done_;
51};
52
53class ReadTask : public SharedExclusiveTask {
54 public:
55  ReadTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done)
56      : SharedExclusiveTask(shared_exclusive_lock, value, done) {
57  }
58
59  void PostRead(int* value) {
60    worker_thread_->Post(this, kMsgRead, new TypedMessageData<int*>(value));
61  }
62
63 private:
64  virtual void OnMessage(Message* message) {
65    ASSERT(rtc::Thread::Current() == worker_thread_.get());
66    ASSERT(message != NULL);
67    ASSERT(message->message_id == kMsgRead);
68
69    TypedMessageData<int*>* message_data =
70        static_cast<TypedMessageData<int*>*>(message->pdata);
71
72    uint32 start_time = Time();
73    {
74      SharedScope ss(shared_exclusive_lock_);
75      waiting_time_in_ms_ = TimeDiff(Time(), start_time);
76
77      Thread::SleepMs(kProcessTimeInMs);
78      *message_data->data() = *value_;
79      *done_ = true;
80    }
81    delete message->pdata;
82    message->pdata = NULL;
83  }
84};
85
86class WriteTask : public SharedExclusiveTask {
87 public:
88  WriteTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done)
89      : SharedExclusiveTask(shared_exclusive_lock, value, done) {
90  }
91
92  void PostWrite(int value) {
93    worker_thread_->Post(this, kMsgWrite, new TypedMessageData<int>(value));
94  }
95
96 private:
97  virtual void OnMessage(Message* message) {
98    ASSERT(rtc::Thread::Current() == worker_thread_.get());
99    ASSERT(message != NULL);
100    ASSERT(message->message_id == kMsgWrite);
101
102    TypedMessageData<int>* message_data =
103        static_cast<TypedMessageData<int>*>(message->pdata);
104
105    uint32 start_time = Time();
106    {
107      ExclusiveScope es(shared_exclusive_lock_);
108      waiting_time_in_ms_ = TimeDiff(Time(), start_time);
109
110      Thread::SleepMs(kProcessTimeInMs);
111      *value_ = message_data->data();
112      *done_ = true;
113    }
114    delete message->pdata;
115    message->pdata = NULL;
116  }
117};
118
119// Unit test for SharedExclusiveLock.
120class SharedExclusiveLockTest
121    : public testing::Test {
122 public:
123  SharedExclusiveLockTest() : value_(0) {
124  }
125
126  virtual void SetUp() {
127    shared_exclusive_lock_.reset(new SharedExclusiveLock());
128  }
129
130 protected:
131  scoped_ptr<SharedExclusiveLock> shared_exclusive_lock_;
132  int value_;
133};
134
135// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3318
136TEST_F(SharedExclusiveLockTest, DISABLED_TestSharedShared) {
137  int value0, value1;
138  bool done0, done1;
139  ReadTask reader0(shared_exclusive_lock_.get(), &value_, &done0);
140  ReadTask reader1(shared_exclusive_lock_.get(), &value_, &done1);
141
142  // Test shared locks can be shared without waiting.
143  {
144    SharedScope ss(shared_exclusive_lock_.get());
145    value_ = 1;
146    done0 = false;
147    done1 = false;
148    reader0.PostRead(&value0);
149    reader1.PostRead(&value1);
150    Thread::SleepMs(kProcessTimeInMs);
151  }
152
153  EXPECT_TRUE_WAIT(done0, kProcessTimeoutInMs);
154  EXPECT_EQ(1, value0);
155  EXPECT_LE(reader0.waiting_time_in_ms(), kNoWaitThresholdInMs);
156  EXPECT_TRUE_WAIT(done1, kProcessTimeoutInMs);
157  EXPECT_EQ(1, value1);
158  EXPECT_LE(reader1.waiting_time_in_ms(), kNoWaitThresholdInMs);
159}
160
161TEST_F(SharedExclusiveLockTest, DISABLED_ON_MAC(TestSharedExclusive)) {
162  bool done;
163  WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
164
165  // Test exclusive lock needs to wait for shared lock.
166  {
167    SharedScope ss(shared_exclusive_lock_.get());
168    value_ = 1;
169    done = false;
170    writer.PostWrite(2);
171    Thread::SleepMs(kProcessTimeInMs);
172    EXPECT_EQ(1, value_);
173  }
174
175  EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs);
176  EXPECT_EQ(2, value_);
177  EXPECT_GE(writer.waiting_time_in_ms(), kWaitThresholdInMs);
178}
179
180TEST_F(SharedExclusiveLockTest, DISABLED_ON_MAC(TestExclusiveShared)) {
181  int value;
182  bool done;
183  ReadTask reader(shared_exclusive_lock_.get(), &value_, &done);
184
185  // Test shared lock needs to wait for exclusive lock.
186  {
187    ExclusiveScope es(shared_exclusive_lock_.get());
188    value_ = 1;
189    done = false;
190    reader.PostRead(&value);
191    Thread::SleepMs(kProcessTimeInMs);
192    value_ = 2;
193  }
194
195  EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs);
196  EXPECT_EQ(2, value);
197  EXPECT_GE(reader.waiting_time_in_ms(), kWaitThresholdInMs);
198}
199
200TEST_F(SharedExclusiveLockTest, DISABLED_ON_MAC(TestExclusiveExclusive)) {
201  bool done;
202  WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
203
204  // Test exclusive lock needs to wait for exclusive lock.
205  {
206    ExclusiveScope es(shared_exclusive_lock_.get());
207    value_ = 1;
208    done = false;
209    writer.PostWrite(2);
210    Thread::SleepMs(kProcessTimeInMs);
211    EXPECT_EQ(1, value_);
212  }
213
214  EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs);
215  EXPECT_EQ(2, value_);
216  EXPECT_GE(writer.waiting_time_in_ms(), kWaitThresholdInMs);
217}
218
219}  // namespace rtc
220