3 * Copyright 2011, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 #include "talk/base/common.h"
29 #include "talk/base/gunit.h"
30 #include "talk/base/messagehandler.h"
31 #include "talk/base/messagequeue.h"
32 #include "talk/base/scoped_ptr.h"
33 #include "talk/base/sharedexclusivelock.h"
34 #include "talk/base/thread.h"
35 #include "talk/base/timeutils.h"
39 static const uint32 kMsgRead = 0;
40 static const uint32 kMsgWrite = 0;
41 static const int kNoWaitThresholdInMs = 10;
42 static const int kWaitThresholdInMs = 80;
43 static const int kProcessTimeInMs = 100;
44 static const int kProcessTimeoutInMs = 5000;
46 class SharedExclusiveTask : public MessageHandler {
48 SharedExclusiveTask(SharedExclusiveLock* shared_exclusive_lock,
51 : shared_exclusive_lock_(shared_exclusive_lock),
52 waiting_time_in_ms_(0),
55 worker_thread_.reset(new Thread());
56 worker_thread_->Start();
59 int waiting_time_in_ms() const { return waiting_time_in_ms_; }
62 scoped_ptr<Thread> worker_thread_;
63 SharedExclusiveLock* shared_exclusive_lock_;
64 int waiting_time_in_ms_;
69 class ReadTask : public SharedExclusiveTask {
71 ReadTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done)
72 : SharedExclusiveTask(shared_exclusive_lock, value, done) {
75 void PostRead(int* value) {
76 worker_thread_->Post(this, kMsgRead, new TypedMessageData<int*>(value));
80 virtual void OnMessage(Message* message) {
81 ASSERT(talk_base::Thread::Current() == worker_thread_.get());
82 ASSERT(message != NULL);
83 ASSERT(message->message_id == kMsgRead);
85 TypedMessageData<int*>* message_data =
86 static_cast<TypedMessageData<int*>*>(message->pdata);
88 uint32 start_time = Time();
90 SharedScope ss(shared_exclusive_lock_);
91 waiting_time_in_ms_ = TimeDiff(Time(), start_time);
93 Thread::SleepMs(kProcessTimeInMs);
94 *message_data->data() = *value_;
97 delete message->pdata;
98 message->pdata = NULL;
102 class WriteTask : public SharedExclusiveTask {
104 WriteTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done)
105 : SharedExclusiveTask(shared_exclusive_lock, value, done) {
108 void PostWrite(int value) {
109 worker_thread_->Post(this, kMsgWrite, new TypedMessageData<int>(value));
113 virtual void OnMessage(Message* message) {
114 ASSERT(talk_base::Thread::Current() == worker_thread_.get());
115 ASSERT(message != NULL);
116 ASSERT(message->message_id == kMsgWrite);
118 TypedMessageData<int>* message_data =
119 static_cast<TypedMessageData<int>*>(message->pdata);
121 uint32 start_time = Time();
123 ExclusiveScope es(shared_exclusive_lock_);
124 waiting_time_in_ms_ = TimeDiff(Time(), start_time);
126 Thread::SleepMs(kProcessTimeInMs);
127 *value_ = message_data->data();
130 delete message->pdata;
131 message->pdata = NULL;
135 // Unit test for SharedExclusiveLock.
136 class SharedExclusiveLockTest
137 : public testing::Test {
139 SharedExclusiveLockTest() : value_(0) {
142 virtual void SetUp() {
143 shared_exclusive_lock_.reset(new SharedExclusiveLock());
147 scoped_ptr<SharedExclusiveLock> shared_exclusive_lock_;
151 // Flaky: https://code.google.com/p/webrtc/issues/detail?id=3318
152 TEST_F(SharedExclusiveLockTest, DISABLED_TestSharedShared) {
155 ReadTask reader0(shared_exclusive_lock_.get(), &value_, &done0);
156 ReadTask reader1(shared_exclusive_lock_.get(), &value_, &done1);
158 // Test shared locks can be shared without waiting.
160 SharedScope ss(shared_exclusive_lock_.get());
164 reader0.PostRead(&value0);
165 reader1.PostRead(&value1);
166 Thread::SleepMs(kProcessTimeInMs);
169 EXPECT_TRUE_WAIT(done0, kProcessTimeoutInMs);
170 EXPECT_EQ(1, value0);
171 EXPECT_LE(reader0.waiting_time_in_ms(), kNoWaitThresholdInMs);
172 EXPECT_TRUE_WAIT(done1, kProcessTimeoutInMs);
173 EXPECT_EQ(1, value1);
174 EXPECT_LE(reader1.waiting_time_in_ms(), kNoWaitThresholdInMs);
177 TEST_F(SharedExclusiveLockTest, TestSharedExclusive) {
179 WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
181 // Test exclusive lock needs to wait for shared lock.
183 SharedScope ss(shared_exclusive_lock_.get());
187 Thread::SleepMs(kProcessTimeInMs);
188 EXPECT_EQ(1, value_);
191 EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs);
192 EXPECT_EQ(2, value_);
193 EXPECT_GE(writer.waiting_time_in_ms(), kWaitThresholdInMs);
196 TEST_F(SharedExclusiveLockTest, TestExclusiveShared) {
199 ReadTask reader(shared_exclusive_lock_.get(), &value_, &done);
201 // Test shared lock needs to wait for exclusive lock.
203 ExclusiveScope es(shared_exclusive_lock_.get());
206 reader.PostRead(&value);
207 Thread::SleepMs(kProcessTimeInMs);
211 EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs);
213 EXPECT_GE(reader.waiting_time_in_ms(), kWaitThresholdInMs);
216 TEST_F(SharedExclusiveLockTest, TestExclusiveExclusive) {
218 WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
220 // Test exclusive lock needs to wait for exclusive lock.
222 ExclusiveScope es(shared_exclusive_lock_.get());
226 Thread::SleepMs(kProcessTimeInMs);
227 EXPECT_EQ(1, value_);
230 EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs);
231 EXPECT_EQ(2, value_);
232 EXPECT_GE(writer.waiting_time_in_ms(), kWaitThresholdInMs);
235 } // namespace talk_base