OLD | NEW |
| (Empty) |
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 <memory> | |
12 | |
13 #include "webrtc/base/checks.h" | |
14 #include "webrtc/base/gunit.h" | |
15 #include "webrtc/base/event.h" | |
16 #include "webrtc/base/messagehandler.h" | |
17 #include "webrtc/base/messagequeue.h" | |
18 #include "webrtc/base/sharedexclusivelock.h" | |
19 #include "webrtc/base/thread.h" | |
20 #include "webrtc/base/timeutils.h" | |
21 | |
22 namespace rtc { | |
23 | |
24 static const uint32_t kMsgRead = 0; | |
25 static const uint32_t kMsgWrite = 0; | |
26 static const int kNoWaitThresholdInMs = 10; | |
27 static const int kWaitThresholdInMs = 80; | |
28 static const int kProcessTimeInMs = 100; | |
29 static const int kProcessTimeoutInMs = 5000; | |
30 | |
31 class SharedExclusiveTask : public MessageHandler { | |
32 public: | |
33 SharedExclusiveTask(SharedExclusiveLock* shared_exclusive_lock, | |
34 int* value, | |
35 Event* done) | |
36 : shared_exclusive_lock_(shared_exclusive_lock), | |
37 value_(value), | |
38 done_(done) { | |
39 worker_thread_.reset(new Thread()); | |
40 worker_thread_->Start(); | |
41 } | |
42 | |
43 protected: | |
44 std::unique_ptr<Thread> worker_thread_; | |
45 SharedExclusiveLock* shared_exclusive_lock_; | |
46 int* value_; | |
47 Event* done_; | |
48 }; | |
49 | |
50 class ReadTask : public SharedExclusiveTask { | |
51 public: | |
52 ReadTask(SharedExclusiveLock* shared_exclusive_lock, int* value, Event* done) | |
53 : SharedExclusiveTask(shared_exclusive_lock, value, done) { | |
54 } | |
55 | |
56 void PostRead(int* value) { | |
57 worker_thread_->Post(RTC_FROM_HERE, this, kMsgRead, | |
58 new TypedMessageData<int*>(value)); | |
59 } | |
60 | |
61 private: | |
62 virtual void OnMessage(Message* message) { | |
63 RTC_CHECK(rtc::Thread::Current() == worker_thread_.get()); | |
64 RTC_CHECK(message != nullptr); | |
65 RTC_CHECK(message->message_id == kMsgRead); | |
66 | |
67 TypedMessageData<int*>* message_data = | |
68 static_cast<TypedMessageData<int*>*>(message->pdata); | |
69 | |
70 { | |
71 SharedScope ss(shared_exclusive_lock_); | |
72 *message_data->data() = *value_; | |
73 done_->Set(); | |
74 } | |
75 delete message->pdata; | |
76 message->pdata = nullptr; | |
77 } | |
78 }; | |
79 | |
80 class WriteTask : public SharedExclusiveTask { | |
81 public: | |
82 WriteTask(SharedExclusiveLock* shared_exclusive_lock, int* value, Event* done) | |
83 : SharedExclusiveTask(shared_exclusive_lock, value, done) { | |
84 } | |
85 | |
86 void PostWrite(int value) { | |
87 worker_thread_->Post(RTC_FROM_HERE, this, kMsgWrite, | |
88 new TypedMessageData<int>(value)); | |
89 } | |
90 | |
91 private: | |
92 virtual void OnMessage(Message* message) { | |
93 RTC_CHECK(rtc::Thread::Current() == worker_thread_.get()); | |
94 RTC_CHECK(message != nullptr); | |
95 RTC_CHECK(message->message_id == kMsgWrite); | |
96 | |
97 TypedMessageData<int>* message_data = | |
98 static_cast<TypedMessageData<int>*>(message->pdata); | |
99 | |
100 { | |
101 ExclusiveScope es(shared_exclusive_lock_); | |
102 *value_ = message_data->data(); | |
103 done_->Set(); | |
104 } | |
105 delete message->pdata; | |
106 message->pdata = nullptr; | |
107 } | |
108 }; | |
109 | |
110 // Unit test for SharedExclusiveLock. | |
111 class 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: | |
122 std::unique_ptr<SharedExclusiveLock> shared_exclusive_lock_; | |
123 int value_; | |
124 }; | |
125 | |
126 TEST_F(SharedExclusiveLockTest, TestSharedShared) { | |
127 int value0, value1; | |
128 Event done0(false, false), done1(false, false); | |
129 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; | |
136 reader0.PostRead(&value0); | |
137 reader1.PostRead(&value1); | |
138 | |
139 EXPECT_TRUE(done0.Wait(kProcessTimeoutInMs)); | |
140 EXPECT_TRUE(done1.Wait(kProcessTimeoutInMs)); | |
141 EXPECT_EQ(1, value0); | |
142 EXPECT_EQ(1, value1); | |
143 } | |
144 } | |
145 | |
146 TEST_F(SharedExclusiveLockTest, TestSharedExclusive) { | |
147 Event done(false, false); | |
148 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; | |
154 writer.PostWrite(2); | |
155 EXPECT_FALSE(done.Wait(kProcessTimeInMs)); | |
156 } | |
157 EXPECT_TRUE(done.Wait(kProcessTimeoutInMs)); | |
158 EXPECT_EQ(2, value_); | |
159 } | |
160 | |
161 TEST_F(SharedExclusiveLockTest, TestExclusiveShared) { | |
162 int value; | |
163 Event done(false, false); | |
164 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; | |
170 reader.PostRead(&value); | |
171 EXPECT_FALSE(done.Wait(kProcessTimeInMs)); | |
172 value_ = 2; | |
173 } | |
174 | |
175 EXPECT_TRUE(done.Wait(kProcessTimeoutInMs)); | |
176 EXPECT_EQ(2, value); | |
177 } | |
178 | |
179 TEST_F(SharedExclusiveLockTest, TestExclusiveExclusive) { | |
180 Event done(false, false); | |
181 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()); | |
186 // Start the writer task only after holding the lock, to ensure it need | |
187 value_ = 1; | |
188 writer.PostWrite(2); | |
189 EXPECT_FALSE(done.Wait(kProcessTimeInMs)); | |
190 EXPECT_EQ(1, value_); | |
191 } | |
192 | |
193 EXPECT_TRUE(done.Wait(kProcessTimeoutInMs)); | |
194 EXPECT_EQ(2, value_); | |
195 } | |
196 | |
197 } // namespace rtc | |
OLD | NEW |