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 "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 20 namespace rtc { 21 22 static const uint32_t kMsgRead = 0; 23 static const uint32_t kMsgWrite = 0; 24 static const int kNoWaitThresholdInMs = 10; 25 static const int kWaitThresholdInMs = 80; 26 static const int kProcessTimeInMs = 100; 27 static const int kProcessTimeoutInMs = 5000; 28 29 class 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 52 class 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 71 uint32_t start_time = Time(); 72 { 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 85 class 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 104 uint32_t start_time = Time(); 105 { 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. 119 class 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 134 // Flaky: https://code.google.com/p/webrtc/issues/detail?id=3318 135 TEST_F(SharedExclusiveLockTest, TestSharedShared) { 136 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 160 TEST_F(SharedExclusiveLockTest, TestSharedExclusive) { 161 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 179 TEST_F(SharedExclusiveLockTest, TestExclusiveShared) { 180 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 199 TEST_F(SharedExclusiveLockTest, TestExclusiveExclusive) { 200 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 219