blob: 3886fb27ab1a0771f7f091cc6777ae407b7fb36d [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
jbauch555604a2016-04-26 03:13:22 -070011#include <memory>
12
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013#include "webrtc/base/common.h"
14#include "webrtc/base/gunit.h"
skvladefc5ae92016-10-05 15:58:12 -070015#include "webrtc/base/event.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016#include "webrtc/base/messagehandler.h"
17#include "webrtc/base/messagequeue.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018#include "webrtc/base/sharedexclusivelock.h"
19#include "webrtc/base/thread.h"
20#include "webrtc/base/timeutils.h"
21
22namespace rtc {
23
Peter Boström0c4e06b2015-10-07 12:23:21 +020024static const uint32_t kMsgRead = 0;
25static const uint32_t kMsgWrite = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026static const int kNoWaitThresholdInMs = 10;
27static const int kWaitThresholdInMs = 80;
28static const int kProcessTimeInMs = 100;
29static const int kProcessTimeoutInMs = 5000;
30
31class SharedExclusiveTask : public MessageHandler {
32 public:
33 SharedExclusiveTask(SharedExclusiveLock* shared_exclusive_lock,
34 int* value,
skvladefc5ae92016-10-05 15:58:12 -070035 Event* done)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036 : shared_exclusive_lock_(shared_exclusive_lock),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000037 value_(value),
38 done_(done) {
39 worker_thread_.reset(new Thread());
40 worker_thread_->Start();
41 }
42
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000043 protected:
jbauch555604a2016-04-26 03:13:22 -070044 std::unique_ptr<Thread> worker_thread_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000045 SharedExclusiveLock* shared_exclusive_lock_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000046 int* value_;
skvladefc5ae92016-10-05 15:58:12 -070047 Event* done_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000048};
49
50class ReadTask : public SharedExclusiveTask {
51 public:
skvladefc5ae92016-10-05 15:58:12 -070052 ReadTask(SharedExclusiveLock* shared_exclusive_lock, int* value, Event* done)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000053 : SharedExclusiveTask(shared_exclusive_lock, value, done) {
54 }
55
56 void PostRead(int* value) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070057 worker_thread_->Post(RTC_FROM_HERE, this, kMsgRead,
58 new TypedMessageData<int*>(value));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059 }
60
61 private:
62 virtual void OnMessage(Message* message) {
63 ASSERT(rtc::Thread::Current() == worker_thread_.get());
64 ASSERT(message != NULL);
65 ASSERT(message->message_id == kMsgRead);
66
67 TypedMessageData<int*>* message_data =
68 static_cast<TypedMessageData<int*>*>(message->pdata);
69
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000070 {
71 SharedScope ss(shared_exclusive_lock_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000072 *message_data->data() = *value_;
skvladefc5ae92016-10-05 15:58:12 -070073 done_->Set();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000074 }
75 delete message->pdata;
76 message->pdata = NULL;
77 }
78};
79
80class WriteTask : public SharedExclusiveTask {
81 public:
skvladefc5ae92016-10-05 15:58:12 -070082 WriteTask(SharedExclusiveLock* shared_exclusive_lock, int* value, Event* done)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083 : SharedExclusiveTask(shared_exclusive_lock, value, done) {
84 }
85
86 void PostWrite(int value) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070087 worker_thread_->Post(RTC_FROM_HERE, this, kMsgWrite,
88 new TypedMessageData<int>(value));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000089 }
90
91 private:
92 virtual void OnMessage(Message* message) {
93 ASSERT(rtc::Thread::Current() == worker_thread_.get());
94 ASSERT(message != NULL);
95 ASSERT(message->message_id == kMsgWrite);
96
97 TypedMessageData<int>* message_data =
98 static_cast<TypedMessageData<int>*>(message->pdata);
99
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000100 {
101 ExclusiveScope es(shared_exclusive_lock_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000102 *value_ = message_data->data();
skvladefc5ae92016-10-05 15:58:12 -0700103 done_->Set();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000104 }
105 delete message->pdata;
106 message->pdata = NULL;
107 }
108};
109
110// Unit test for SharedExclusiveLock.
111class SharedExclusiveLockTest
112 : public testing::Test {
113 public:
114 SharedExclusiveLockTest() : value_(0) {
115 }
116
117 virtual void SetUp() {
118 shared_exclusive_lock_.reset(new SharedExclusiveLock());
119 }
120
121 protected:
jbauch555604a2016-04-26 03:13:22 -0700122 std::unique_ptr<SharedExclusiveLock> shared_exclusive_lock_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000123 int value_;
124};
125
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000126TEST_F(SharedExclusiveLockTest, TestSharedShared) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000127 int value0, value1;
skvladefc5ae92016-10-05 15:58:12 -0700128 Event done0(false, false), done1(false, false);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000129 ReadTask reader0(shared_exclusive_lock_.get(), &value_, &done0);
130 ReadTask reader1(shared_exclusive_lock_.get(), &value_, &done1);
131
132 // Test shared locks can be shared without waiting.
133 {
134 SharedScope ss(shared_exclusive_lock_.get());
135 value_ = 1;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000136 reader0.PostRead(&value0);
137 reader1.PostRead(&value1);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000138
skvladefc5ae92016-10-05 15:58:12 -0700139 EXPECT_TRUE(done0.Wait(kProcessTimeoutInMs));
140 EXPECT_TRUE(done1.Wait(kProcessTimeoutInMs));
141 EXPECT_EQ(1, value0);
142 EXPECT_EQ(1, value1);
143 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144}
145
skvladefc5ae92016-10-05 15:58:12 -0700146TEST_F(SharedExclusiveLockTest, TestSharedExclusive) {
147 Event done(false, false);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000148 WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
149
150 // Test exclusive lock needs to wait for shared lock.
151 {
152 SharedScope ss(shared_exclusive_lock_.get());
153 value_ = 1;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154 writer.PostWrite(2);
skvladefc5ae92016-10-05 15:58:12 -0700155 EXPECT_FALSE(done.Wait(kProcessTimeInMs));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000156 }
skvladefc5ae92016-10-05 15:58:12 -0700157 EXPECT_TRUE(done.Wait(kProcessTimeoutInMs));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 EXPECT_EQ(2, value_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000159}
160
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000161TEST_F(SharedExclusiveLockTest, TestExclusiveShared) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000162 int value;
skvladefc5ae92016-10-05 15:58:12 -0700163 Event done(false, false);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000164 ReadTask reader(shared_exclusive_lock_.get(), &value_, &done);
165
166 // Test shared lock needs to wait for exclusive lock.
167 {
168 ExclusiveScope es(shared_exclusive_lock_.get());
169 value_ = 1;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000170 reader.PostRead(&value);
skvladefc5ae92016-10-05 15:58:12 -0700171 EXPECT_FALSE(done.Wait(kProcessTimeInMs));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000172 value_ = 2;
173 }
174
skvladefc5ae92016-10-05 15:58:12 -0700175 EXPECT_TRUE(done.Wait(kProcessTimeoutInMs));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000176 EXPECT_EQ(2, value);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000177}
178
skvladefc5ae92016-10-05 15:58:12 -0700179TEST_F(SharedExclusiveLockTest, TestExclusiveExclusive) {
180 Event done(false, false);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000181 WriteTask writer(shared_exclusive_lock_.get(), &value_, &done);
182
183 // Test exclusive lock needs to wait for exclusive lock.
184 {
185 ExclusiveScope es(shared_exclusive_lock_.get());
skvladefc5ae92016-10-05 15:58:12 -0700186 // Start the writer task only after holding the lock, to ensure it need
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000187 value_ = 1;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000188 writer.PostWrite(2);
skvladefc5ae92016-10-05 15:58:12 -0700189 EXPECT_FALSE(done.Wait(kProcessTimeInMs));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000190 EXPECT_EQ(1, value_);
191 }
192
skvladefc5ae92016-10-05 15:58:12 -0700193 EXPECT_TRUE(done.Wait(kProcessTimeoutInMs));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000194 EXPECT_EQ(2, value_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000195}
196
197} // namespace rtc