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