blob: e280aa28a8818d0ba677e3ba12587dbb7fdb97d2 [file] [log] [blame]
henrike@webrtc.org0e118e72013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2011, 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 "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"
36
37namespace talk_base {
38
39static const uint32 kMsgRead = 0;
40static const uint32 kMsgWrite = 0;
41static const int kNoWaitThresholdInMs = 10;
42static const int kWaitThresholdInMs = 80;
43static const int kProcessTimeInMs = 100;
44static const int kProcessTimeoutInMs = 5000;
45
46class SharedExclusiveTask : public MessageHandler {
47 public:
48 SharedExclusiveTask(SharedExclusiveLock* shared_exclusive_lock,
49 int* value,
50 bool* done)
51 : shared_exclusive_lock_(shared_exclusive_lock),
52 waiting_time_in_ms_(0),
53 value_(value),
54 done_(done) {
55 worker_thread_.reset(new Thread());
56 worker_thread_->Start();
57 }
58
59 int waiting_time_in_ms() const { return waiting_time_in_ms_; }
60
61 protected:
62 scoped_ptr<Thread> worker_thread_;
63 SharedExclusiveLock* shared_exclusive_lock_;
64 int waiting_time_in_ms_;
65 int* value_;
66 bool* done_;
67};
68
69class ReadTask : public SharedExclusiveTask {
70 public:
71 ReadTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done)
72 : SharedExclusiveTask(shared_exclusive_lock, value, done) {
73 }
74
75 void PostRead(int* value) {
76 worker_thread_->Post(this, kMsgRead, new TypedMessageData<int*>(value));
77 }
78
79 private:
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);
84
85 TypedMessageData<int*>* message_data =
86 static_cast<TypedMessageData<int*>*>(message->pdata);
87
88 uint32 start_time = Time();
89 {
90 SharedScope ss(shared_exclusive_lock_);
91 waiting_time_in_ms_ = TimeDiff(Time(), start_time);
92
93 Thread::SleepMs(kProcessTimeInMs);
94 *message_data->data() = *value_;
95 *done_ = true;
96 }
97 delete message->pdata;
98 message->pdata = NULL;
99 }
100};
101
102class WriteTask : public SharedExclusiveTask {
103 public:
104 WriteTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done)
105 : SharedExclusiveTask(shared_exclusive_lock, value, done) {
106 }
107
108 void PostWrite(int value) {
109 worker_thread_->Post(this, kMsgWrite, new TypedMessageData<int>(value));
110 }
111
112 private:
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);
117
118 TypedMessageData<int>* message_data =
119 static_cast<TypedMessageData<int>*>(message->pdata);
120
121 uint32 start_time = Time();
122 {
123 ExclusiveScope es(shared_exclusive_lock_);
124 waiting_time_in_ms_ = TimeDiff(Time(), start_time);
125
126 Thread::SleepMs(kProcessTimeInMs);
127 *value_ = message_data->data();
128 *done_ = true;
129 }
130 delete message->pdata;
131 message->pdata = NULL;
132 }
133};
134
135// Unit test for SharedExclusiveLock.
136class SharedExclusiveLockTest
137 : public testing::Test {
138 public:
139 SharedExclusiveLockTest() : value_(0) {
140 }
141
142 virtual void SetUp() {
143 shared_exclusive_lock_.reset(new SharedExclusiveLock());
144 }
145
146 protected:
147 scoped_ptr<SharedExclusiveLock> shared_exclusive_lock_;
148 int value_;
149};
150
phoglund@webrtc.org95ed1962014-05-27 08:08:00 +0000151// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3318
152TEST_F(SharedExclusiveLockTest, DISABLED_TestSharedShared) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000153 int value0, value1;
154 bool done0, done1;
155 ReadTask reader0(shared_exclusive_lock_.get(), &value_, &done0);
156 ReadTask reader1(shared_exclusive_lock_.get(), &value_, &done1);
157
158 // Test shared locks can be shared without waiting.
159 {
160 SharedScope ss(shared_exclusive_lock_.get());
161 value_ = 1;
162 done0 = false;
163 done1 = false;
164 reader0.PostRead(&value0);
165 reader1.PostRead(&value1);
166 Thread::SleepMs(kProcessTimeInMs);
167 }
168
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);
175}
176
177TEST_F(SharedExclusiveLockTest, TestSharedExclusive) {
178 bool done;
179 WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
180
181 // Test exclusive lock needs to wait for shared lock.
182 {
183 SharedScope ss(shared_exclusive_lock_.get());
184 value_ = 1;
185 done = false;
186 writer.PostWrite(2);
187 Thread::SleepMs(kProcessTimeInMs);
188 EXPECT_EQ(1, value_);
189 }
190
191 EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs);
192 EXPECT_EQ(2, value_);
193 EXPECT_GE(writer.waiting_time_in_ms(), kWaitThresholdInMs);
194}
195
196TEST_F(SharedExclusiveLockTest, TestExclusiveShared) {
197 int value;
198 bool done;
199 ReadTask reader(shared_exclusive_lock_.get(), &value_, &done);
200
201 // Test shared lock needs to wait for exclusive lock.
202 {
203 ExclusiveScope es(shared_exclusive_lock_.get());
204 value_ = 1;
205 done = false;
206 reader.PostRead(&value);
207 Thread::SleepMs(kProcessTimeInMs);
208 value_ = 2;
209 }
210
211 EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs);
212 EXPECT_EQ(2, value);
213 EXPECT_GE(reader.waiting_time_in_ms(), kWaitThresholdInMs);
214}
215
216TEST_F(SharedExclusiveLockTest, TestExclusiveExclusive) {
217 bool done;
218 WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
219
220 // Test exclusive lock needs to wait for exclusive lock.
221 {
222 ExclusiveScope es(shared_exclusive_lock_.get());
223 value_ = 1;
224 done = false;
225 writer.PostWrite(2);
226 Thread::SleepMs(kProcessTimeInMs);
227 EXPECT_EQ(1, value_);
228 }
229
230 EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs);
231 EXPECT_EQ(2, value_);
232 EXPECT_GE(writer.waiting_time_in_ms(), kWaitThresholdInMs);
233}
234
235} // namespace talk_base