blob: 9b64ed760afa89b2551d47355a46cc0e8299cac1 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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
20namespace rtc {
21
Peter Boström0c4e06b2015-10-07 12:23:21 +020022static const uint32_t kMsgRead = 0;
23static const uint32_t kMsgWrite = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000024static const int kNoWaitThresholdInMs = 10;
25static const int kWaitThresholdInMs = 80;
26static const int kProcessTimeInMs = 100;
27static const int kProcessTimeoutInMs = 5000;
28
29class SharedExclusiveTask : public MessageHandler {
30 public:
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
42 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
52class ReadTask : public SharedExclusiveTask {
53 public:
54 ReadTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done)
55 : SharedExclusiveTask(shared_exclusive_lock, value, done) {
56 }
57
58 void PostRead(int* value) {
59 worker_thread_->Post(this, kMsgRead, new TypedMessageData<int*>(value));
60 }
61
62 private:
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
Peter Boström0c4e06b2015-10-07 12:23:21 +020071 uint32_t start_time = Time();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000072 {
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
85class WriteTask : public SharedExclusiveTask {
86 public:
87 WriteTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done)
88 : SharedExclusiveTask(shared_exclusive_lock, value, done) {
89 }
90
91 void PostWrite(int value) {
92 worker_thread_->Post(this, kMsgWrite, new TypedMessageData<int>(value));
93 }
94
95 private:
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
Peter Boström0c4e06b2015-10-07 12:23:21 +0200104 uint32_t start_time = Time();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000105 {
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.
119class SharedExclusiveLockTest
120 : public testing::Test {
121 public:
122 SharedExclusiveLockTest() : value_(0) {
123 }
124
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
henrike@webrtc.orgcaa01b12014-05-29 15:53:39 +0000134// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3318
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000135TEST_F(SharedExclusiveLockTest, TestSharedShared) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000136 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
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000160TEST_F(SharedExclusiveLockTest, TestSharedExclusive) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000161 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
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000179TEST_F(SharedExclusiveLockTest, TestExclusiveShared) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000180 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
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000199TEST_F(SharedExclusiveLockTest, TestExclusiveExclusive) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000200 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