Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2012 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/system_wrappers/interface/critical_section_wrapper.h"
     12 
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "webrtc/system_wrappers/interface/sleep.h"
     15 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
     16 #include "webrtc/system_wrappers/interface/trace.h"
     17 
     18 namespace webrtc {
     19 
     20 namespace {
     21 
     22 // Cause a process switch. Needed to avoid depending on
     23 // busy-wait in tests.
     24 static void SwitchProcess() {
     25   // Note - sched_yield has been tried as process switch. This does
     26   // not cause a process switch enough of the time for reliability.
     27   SleepMs(1);
     28 }
     29 
     30 class ProtectedCount {
     31 public:
     32   explicit ProtectedCount(CriticalSectionWrapper* crit_sect)
     33     : crit_sect_(crit_sect),
     34       count_(0) {
     35   }
     36 
     37   void Increment() {
     38     CriticalSectionScoped cs(crit_sect_);
     39     ++count_;
     40   }
     41 
     42   int Count() const {
     43     CriticalSectionScoped cs(crit_sect_);
     44     return count_;
     45   }
     46 
     47 private:
     48   CriticalSectionWrapper* crit_sect_;
     49   int count_;
     50 };
     51 
     52 class CritSectTest : public ::testing::Test {
     53 public:
     54   CritSectTest() {}
     55 
     56   // Waits a number of cycles for the count to reach a given value.
     57   // Returns true if the target is reached or passed.
     58   bool WaitForCount(int target, ProtectedCount* count) {
     59     int loop_counter = 0;
     60     // On Posix, this SwitchProcess() needs to be in a loop to make the
     61     // test both fast and non-flaky.
     62     // With 1 us wait as the switch, up to 7 rounds have been observed.
     63     while (count->Count() < target && loop_counter < 100 * target) {
     64       ++loop_counter;
     65       SwitchProcess();
     66     }
     67     return (count->Count() >= target);
     68   }
     69 };
     70 
     71 bool LockUnlockThenStopRunFunction(void* obj) {
     72   ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
     73   the_count->Increment();
     74   return false;
     75 }
     76 
     77 TEST_F(CritSectTest, ThreadWakesOnce) NO_THREAD_SAFETY_ANALYSIS {
     78   CriticalSectionWrapper* crit_sect =
     79       CriticalSectionWrapper::CreateCriticalSection();
     80   ProtectedCount count(crit_sect);
     81   ThreadWrapper* thread = ThreadWrapper::CreateThread(
     82       &LockUnlockThenStopRunFunction, &count);
     83   unsigned int id = 42;
     84   crit_sect->Enter();
     85   ASSERT_TRUE(thread->Start(id));
     86   SwitchProcess();
     87   // The critical section is of reentrant mode, so this should not release
     88   // the lock, even though count.Count() locks and unlocks the critical section
     89   // again.
     90   // Thus, the thread should not be able to increment the count
     91   ASSERT_EQ(0, count.Count());
     92   crit_sect->Leave();  // This frees the thread to act.
     93   EXPECT_TRUE(WaitForCount(1, &count));
     94   EXPECT_TRUE(thread->Stop());
     95   delete thread;
     96   delete crit_sect;
     97 }
     98 
     99 bool LockUnlockRunFunction(void* obj) {
    100   ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
    101   the_count->Increment();
    102   SwitchProcess();
    103   return true;
    104 }
    105 
    106 TEST_F(CritSectTest, ThreadWakesTwice) NO_THREAD_SAFETY_ANALYSIS {
    107   CriticalSectionWrapper* crit_sect =
    108       CriticalSectionWrapper::CreateCriticalSection();
    109   ProtectedCount count(crit_sect);
    110   ThreadWrapper* thread = ThreadWrapper::CreateThread(&LockUnlockRunFunction,
    111                                                       &count);
    112   unsigned int id = 42;
    113   crit_sect->Enter();  // Make sure counter stays 0 until we wait for it.
    114   ASSERT_TRUE(thread->Start(id));
    115   crit_sect->Leave();
    116 
    117   // The thread is capable of grabbing the lock multiple times,
    118   // incrementing counter once each time.
    119   // It's possible for the count to be incremented by more than 2.
    120   EXPECT_TRUE(WaitForCount(2, &count));
    121   EXPECT_LE(2, count.Count());
    122 
    123   // The thread does not increment while lock is held.
    124   crit_sect->Enter();
    125   int count_before = count.Count();
    126   for (int i = 0; i < 10; i++) {
    127     SwitchProcess();
    128   }
    129   EXPECT_EQ(count_before, count.Count());
    130   crit_sect->Leave();
    131 
    132   thread->SetNotAlive();  // Tell thread to exit once run function finishes.
    133   SwitchProcess();
    134   EXPECT_TRUE(WaitForCount(count_before + 1, &count));
    135   EXPECT_TRUE(thread->Stop());
    136   delete thread;
    137   delete crit_sect;
    138 }
    139 
    140 }  // anonymous namespace
    141 
    142 }  // namespace webrtc
    143