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 
     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