1a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin/* 2a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin * 4a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin * Use of this source code is governed by a BSD-style license 5a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin * that can be found in the LICENSE file in the root of the source 6a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin * tree. An additional intellectual property rights grant can be found 7a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin * in the file PATENTS. All contributing project authors may 8a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin * be found in the AUTHORS file in the root of the source tree. 9a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin */ 10a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 11a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#ifdef _WIN32 12a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin// For Sleep() 13a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#include <windows.h> 14a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#else 15a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin// For nanosleep() 16a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#include <time.h> 17a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#endif 18a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 19a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#include "system_wrappers/interface/critical_section_wrapper.h" 20a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 21a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#include "gtest/gtest.h" 22a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#include "system_wrappers/interface/sleep.h" 23a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#include "system_wrappers/interface/thread_wrapper.h" 24a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#include "system_wrappers/interface/trace.h" 25a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#include "system_wrappers/source/unittest_utilities.h" 26a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 27a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkinnamespace webrtc { 28a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 29a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkinnamespace { 30a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 31a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkinconst bool kLogTrace = false; // Set to true to enable debug logging to stdout. 32a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 33a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin#define LOG(...) WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, __VA_ARGS__); 34a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 35a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin// Cause a process switch. Needed to avoid depending on 36a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin// busy-wait in tests. 37a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkinstatic void SwitchProcess() { 38a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // Note - sched_yield has been tried as process switch. This does 39a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // not cause a process switch enough of the time for reliability. 40a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin SleepMs(1); 41a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin} 42a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 43a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkinclass ProtectedCount { 44a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin public: 45a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin explicit ProtectedCount(CriticalSectionWrapper* crit_sect) 46a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin : crit_sect_(crit_sect), 47a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin count_(0) { 48a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin } 49a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 50a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin void Increment() { 51a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin CriticalSectionScoped cs(crit_sect_); 52a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ++count_; 53a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin LOG("Inc to %d", count_); 54a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin } 55a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 56a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin int Count() const { 57a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin CriticalSectionScoped cs(crit_sect_); 58a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin return count_; 59a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin } 60a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 61a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin private: 62a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin CriticalSectionWrapper* crit_sect_; 63a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin int count_; 64a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin}; 65a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 66a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkinclass CritSectTest : public ::testing::Test { 67a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin public: 68a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin CritSectTest() : trace_(kLogTrace) { 69a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin } 70a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 71a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // Waits a number of cycles for the count to reach a given value. 72a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // Returns true if the target is reached or passed. 73a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin bool WaitForCount(int target, ProtectedCount* count) { 74a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin int loop_counter = 0; 75a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // On Posix, this SwitchProcess() needs to be in a loop to make the 76a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // test both fast and non-flaky. 77a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // With 1 us wait as the switch, up to 7 rounds have been observed. 78a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin while (count->Count() < target && loop_counter < 100*target) { 79a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ++loop_counter; 80a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin SwitchProcess(); 81a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin } 82a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin LOG("Test looped %d times\n", loop_counter); 83a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin return (count->Count() >= target); 84a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin } 85a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 86a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin private: 87a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ScopedTracing trace_; 88a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin}; 89a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 90a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkinbool LockUnlockThenStopRunFunction(void* obj) { 91a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin LOG("Wait starting"); 92a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ProtectedCount* the_count = static_cast<ProtectedCount*> (obj); 93a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin LOG("Wait incrementing"); 94a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin the_count->Increment(); 95a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin LOG("Wait returning"); 96a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin return false; 97a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin} 98a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 99a6451827d543eb00824bc95097e47d0aac51ae93Alexander GutkinTEST_F(CritSectTest, ThreadWakesOnce) { 100a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin CriticalSectionWrapper* crit_sect 101a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin = CriticalSectionWrapper::CreateCriticalSection(); 102a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ProtectedCount count(crit_sect); 103a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ThreadWrapper* thread = ThreadWrapper::CreateThread( 104a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin &LockUnlockThenStopRunFunction, &count); 105a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin unsigned int id = 42; 106a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin crit_sect->Enter(); 107a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ASSERT_TRUE(thread->Start(id)); 108a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin SwitchProcess(); 109a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // The critical section is of reentrant mode, so this should not release 110a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // the lock, even though count.Count() locks and unlocks the critical section 111a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // again. 112a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // Thus, the thread should not be able to increment the count 113a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ASSERT_EQ(0, count.Count()); 114a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin crit_sect->Leave(); // This frees the thread to act. 115a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin EXPECT_TRUE(WaitForCount(1, &count)); 116a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin EXPECT_TRUE(thread->Stop()); 117a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin delete thread; 118a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin delete crit_sect; 119a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin} 120a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 121a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkinbool LockUnlockRunFunction(void* obj) { 122a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin LOG("Wait starting"); 123a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ProtectedCount* the_count = static_cast<ProtectedCount*> (obj); 124a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin LOG("Wait incrementing"); 125a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin the_count->Increment(); 126a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin SwitchProcess(); 127a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin LOG("Wait returning"); 128a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin return true; 129a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin} 130a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 131a6451827d543eb00824bc95097e47d0aac51ae93Alexander GutkinTEST_F(CritSectTest, ThreadWakesTwice) { 132a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin CriticalSectionWrapper* crit_sect 133a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin = CriticalSectionWrapper::CreateCriticalSection(); 134a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ProtectedCount count(crit_sect); 135a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ThreadWrapper* thread = ThreadWrapper::CreateThread(&LockUnlockRunFunction, 136a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin &count); 137a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin unsigned int id = 42; 138a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin crit_sect->Enter(); // Make sure counter stays 0 until we wait for it. 139a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin ASSERT_TRUE(thread->Start(id)); 140a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin crit_sect->Leave(); 141a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 142a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // The thread is capable of grabbing the lock multiple times, 143a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // incrementing counter once each time. 144a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // It's possible for the count to be incremented by more than 2. 145a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin EXPECT_TRUE(WaitForCount(2, &count)); 146a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin EXPECT_LE(2, count.Count()); 147a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 148a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin // The thread does not increment while lock is held. 149a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin crit_sect->Enter(); 150a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin int count_before = count.Count(); 151a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin for (int i = 0; i < 10; i++) { 152a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin SwitchProcess(); 153a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin } 154a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin EXPECT_EQ(count_before, count.Count()); 155a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin crit_sect->Leave(); 156a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 157a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin thread->SetNotAlive(); // Tell thread to exit once run function finishes. 158a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin SwitchProcess(); 159a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin EXPECT_LT(count_before, count.Count()); 160a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin EXPECT_TRUE(thread->Stop()); 161a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin delete thread; 162a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin delete crit_sect; 163a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin} 164a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 165a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin} // anonymous namespace 166a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin 167a6451827d543eb00824bc95097e47d0aac51ae93Alexander Gutkin} // namespace webrtc 168