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 #include "webrtc/test/testsupport/gtest_disable.h" 20 21 namespace rtc { 22 23 static const uint32 kMsgRead = 0; 24 static const uint32 kMsgWrite = 0; 25 static const int kNoWaitThresholdInMs = 10; 26 static const int kWaitThresholdInMs = 80; 27 static const int kProcessTimeInMs = 100; 28 static const int kProcessTimeoutInMs = 5000; 29 30 class SharedExclusiveTask : public MessageHandler { 31 public: 32 SharedExclusiveTask(SharedExclusiveLock* shared_exclusive_lock, 33 int* value, 34 bool* done) 35 : shared_exclusive_lock_(shared_exclusive_lock), 36 waiting_time_in_ms_(0), 37 value_(value), 38 done_(done) { 39 worker_thread_.reset(new Thread()); 40 worker_thread_->Start(); 41 } 42 43 int waiting_time_in_ms() const { return waiting_time_in_ms_; } 44 45 protected: 46 scoped_ptr<Thread> worker_thread_; 47 SharedExclusiveLock* shared_exclusive_lock_; 48 int waiting_time_in_ms_; 49 int* value_; 50 bool* done_; 51 }; 52 53 class ReadTask : public SharedExclusiveTask { 54 public: 55 ReadTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done) 56 : SharedExclusiveTask(shared_exclusive_lock, value, done) { 57 } 58 59 void PostRead(int* value) { 60 worker_thread_->Post(this, kMsgRead, new TypedMessageData<int*>(value)); 61 } 62 63 private: 64 virtual void OnMessage(Message* message) { 65 ASSERT(rtc::Thread::Current() == worker_thread_.get()); 66 ASSERT(message != NULL); 67 ASSERT(message->message_id == kMsgRead); 68 69 TypedMessageData<int*>* message_data = 70 static_cast<TypedMessageData<int*>*>(message->pdata); 71 72 uint32 start_time = Time(); 73 { 74 SharedScope ss(shared_exclusive_lock_); 75 waiting_time_in_ms_ = TimeDiff(Time(), start_time); 76 77 Thread::SleepMs(kProcessTimeInMs); 78 *message_data->data() = *value_; 79 *done_ = true; 80 } 81 delete message->pdata; 82 message->pdata = NULL; 83 } 84 }; 85 86 class WriteTask : public SharedExclusiveTask { 87 public: 88 WriteTask(SharedExclusiveLock* shared_exclusive_lock, int* value, bool* done) 89 : SharedExclusiveTask(shared_exclusive_lock, value, done) { 90 } 91 92 void PostWrite(int value) { 93 worker_thread_->Post(this, kMsgWrite, new TypedMessageData<int>(value)); 94 } 95 96 private: 97 virtual void OnMessage(Message* message) { 98 ASSERT(rtc::Thread::Current() == worker_thread_.get()); 99 ASSERT(message != NULL); 100 ASSERT(message->message_id == kMsgWrite); 101 102 TypedMessageData<int>* message_data = 103 static_cast<TypedMessageData<int>*>(message->pdata); 104 105 uint32 start_time = Time(); 106 { 107 ExclusiveScope es(shared_exclusive_lock_); 108 waiting_time_in_ms_ = TimeDiff(Time(), start_time); 109 110 Thread::SleepMs(kProcessTimeInMs); 111 *value_ = message_data->data(); 112 *done_ = true; 113 } 114 delete message->pdata; 115 message->pdata = NULL; 116 } 117 }; 118 119 // Unit test for SharedExclusiveLock. 120 class SharedExclusiveLockTest 121 : public testing::Test { 122 public: 123 SharedExclusiveLockTest() : value_(0) { 124 } 125 126 virtual void SetUp() { 127 shared_exclusive_lock_.reset(new SharedExclusiveLock()); 128 } 129 130 protected: 131 scoped_ptr<SharedExclusiveLock> shared_exclusive_lock_; 132 int value_; 133 }; 134 135 // Flaky: https://code.google.com/p/webrtc/issues/detail?id=3318 136 TEST_F(SharedExclusiveLockTest, DISABLED_TestSharedShared) { 137 int value0, value1; 138 bool done0, done1; 139 ReadTask reader0(shared_exclusive_lock_.get(), &value_, &done0); 140 ReadTask reader1(shared_exclusive_lock_.get(), &value_, &done1); 141 142 // Test shared locks can be shared without waiting. 143 { 144 SharedScope ss(shared_exclusive_lock_.get()); 145 value_ = 1; 146 done0 = false; 147 done1 = false; 148 reader0.PostRead(&value0); 149 reader1.PostRead(&value1); 150 Thread::SleepMs(kProcessTimeInMs); 151 } 152 153 EXPECT_TRUE_WAIT(done0, kProcessTimeoutInMs); 154 EXPECT_EQ(1, value0); 155 EXPECT_LE(reader0.waiting_time_in_ms(), kNoWaitThresholdInMs); 156 EXPECT_TRUE_WAIT(done1, kProcessTimeoutInMs); 157 EXPECT_EQ(1, value1); 158 EXPECT_LE(reader1.waiting_time_in_ms(), kNoWaitThresholdInMs); 159 } 160 161 TEST_F(SharedExclusiveLockTest, DISABLED_ON_MAC(TestSharedExclusive)) { 162 bool done; 163 WriteTask writer(shared_exclusive_lock_.get(), &value_, &done); 164 165 // Test exclusive lock needs to wait for shared lock. 166 { 167 SharedScope ss(shared_exclusive_lock_.get()); 168 value_ = 1; 169 done = false; 170 writer.PostWrite(2); 171 Thread::SleepMs(kProcessTimeInMs); 172 EXPECT_EQ(1, value_); 173 } 174 175 EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs); 176 EXPECT_EQ(2, value_); 177 EXPECT_GE(writer.waiting_time_in_ms(), kWaitThresholdInMs); 178 } 179 180 TEST_F(SharedExclusiveLockTest, DISABLED_ON_MAC(TestExclusiveShared)) { 181 int value; 182 bool done; 183 ReadTask reader(shared_exclusive_lock_.get(), &value_, &done); 184 185 // Test shared lock needs to wait for exclusive lock. 186 { 187 ExclusiveScope es(shared_exclusive_lock_.get()); 188 value_ = 1; 189 done = false; 190 reader.PostRead(&value); 191 Thread::SleepMs(kProcessTimeInMs); 192 value_ = 2; 193 } 194 195 EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs); 196 EXPECT_EQ(2, value); 197 EXPECT_GE(reader.waiting_time_in_ms(), kWaitThresholdInMs); 198 } 199 200 TEST_F(SharedExclusiveLockTest, DISABLED_ON_MAC(TestExclusiveExclusive)) { 201 bool done; 202 WriteTask writer(shared_exclusive_lock_.get(), &value_, &done); 203 204 // Test exclusive lock needs to wait for exclusive lock. 205 { 206 ExclusiveScope es(shared_exclusive_lock_.get()); 207 value_ = 1; 208 done = false; 209 writer.PostWrite(2); 210 Thread::SleepMs(kProcessTimeInMs); 211 EXPECT_EQ(1, value_); 212 } 213 214 EXPECT_TRUE_WAIT(done, kProcessTimeoutInMs); 215 EXPECT_EQ(2, value_); 216 EXPECT_GE(writer.waiting_time_in_ms(), kWaitThresholdInMs); 217 } 218 219 } // namespace rtc 220