Home | History | Annotate | Download | only in base
      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