1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/* 2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Use of this source code is governed by a BSD-style license 5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * that can be found in the LICENSE file in the root of the source 6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * tree. An additional intellectual property rights grant can be found 7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * in the file PATENTS. All contributing project authors may 8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * be found in the AUTHORS file in the root of the source tree. 9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 11328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 12328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org 13c6d6fed3c0a82bb7a09095381b974e8e5eebcb35pbos@webrtc.org#include "testing/gtest/include/gtest/gtest.h" 14328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org#include "webrtc/system_wrappers/interface/sleep.h" 15328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org#include "webrtc/system_wrappers/interface/thread_wrapper.h" 16328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org#include "webrtc/system_wrappers/interface/trace.h" 17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc { 19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace { 21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Cause a process switch. Needed to avoid depending on 23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// busy-wait in tests. 24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstatic void SwitchProcess() { 25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Note - sched_yield has been tried as process switch. This does 26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // not cause a process switch enough of the time for reliability. 27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SleepMs(1); 28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgclass ProtectedCount { 31328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.orgpublic: 32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org explicit ProtectedCount(CriticalSectionWrapper* crit_sect) 33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org : crit_sect_(crit_sect), 34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org count_(0) { 35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org void Increment() { 38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped cs(crit_sect_); 39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ++count_; 40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int Count() const { 43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped cs(crit_sect_); 44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return count_; 45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 47328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.orgprivate: 48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionWrapper* crit_sect_; 49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int count_; 50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}; 51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgclass CritSectTest : public ::testing::Test { 53328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.orgpublic: 543c98b828b11dd1f8c4902dfb4dabc0ea7d3a99e8andresp@webrtc.org CritSectTest() {} 55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Waits a number of cycles for the count to reach a given value. 57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Returns true if the target is reached or passed. 58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool WaitForCount(int target, ProtectedCount* count) { 59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int loop_counter = 0; 60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // On Posix, this SwitchProcess() needs to be in a loop to make the 61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // test both fast and non-flaky. 62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // With 1 us wait as the switch, up to 7 rounds have been observed. 63328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org while (count->Count() < target && loop_counter < 100 * target) { 64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ++loop_counter; 65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SwitchProcess(); 66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (count->Count() >= target); 68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}; 70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool LockUnlockThenStopRunFunction(void* obj) { 72328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org ProtectedCount* the_count = static_cast<ProtectedCount*>(obj); 73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org the_count->Increment(); 74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return false; 75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 77c9faf10f99da606e2d58b0b4a79c03c232b7c50fandresp@webrtc.orgTEST_F(CritSectTest, ThreadWakesOnce) NO_THREAD_SAFETY_ANALYSIS { 78328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org CriticalSectionWrapper* crit_sect = 79328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org CriticalSectionWrapper::CreateCriticalSection(); 80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ProtectedCount count(crit_sect); 81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ThreadWrapper* thread = ThreadWrapper::CreateThread( 82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &LockUnlockThenStopRunFunction, &count); 83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org unsigned int id = 42; 84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org crit_sect->Enter(); 85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ASSERT_TRUE(thread->Start(id)); 86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SwitchProcess(); 87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // The critical section is of reentrant mode, so this should not release 88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // the lock, even though count.Count() locks and unlocks the critical section 89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // again. 90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Thus, the thread should not be able to increment the count 91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ASSERT_EQ(0, count.Count()); 92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org crit_sect->Leave(); // This frees the thread to act. 93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org EXPECT_TRUE(WaitForCount(1, &count)); 94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org EXPECT_TRUE(thread->Stop()); 95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete thread; 96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete crit_sect; 97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool LockUnlockRunFunction(void* obj) { 100328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org ProtectedCount* the_count = static_cast<ProtectedCount*>(obj); 101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org the_count->Increment(); 102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SwitchProcess(); 103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return true; 104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 106c9faf10f99da606e2d58b0b4a79c03c232b7c50fandresp@webrtc.orgTEST_F(CritSectTest, ThreadWakesTwice) NO_THREAD_SAFETY_ANALYSIS { 107328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org CriticalSectionWrapper* crit_sect = 108328820fff5a529c1ba7767debce6c396d5063499phoglund@webrtc.org CriticalSectionWrapper::CreateCriticalSection(); 109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ProtectedCount count(crit_sect); 110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ThreadWrapper* thread = ThreadWrapper::CreateThread(&LockUnlockRunFunction, 111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &count); 112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org unsigned int id = 42; 113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org crit_sect->Enter(); // Make sure counter stays 0 until we wait for it. 114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ASSERT_TRUE(thread->Start(id)); 115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org crit_sect->Leave(); 116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // The thread is capable of grabbing the lock multiple times, 118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // incrementing counter once each time. 119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // It's possible for the count to be incremented by more than 2. 120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org EXPECT_TRUE(WaitForCount(2, &count)); 121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org EXPECT_LE(2, count.Count()); 122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // The thread does not increment while lock is held. 124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org crit_sect->Enter(); 125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int count_before = count.Count(); 126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org for (int i = 0; i < 10; i++) { 127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SwitchProcess(); 128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org EXPECT_EQ(count_before, count.Count()); 130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org crit_sect->Leave(); 131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org thread->SetNotAlive(); // Tell thread to exit once run function finishes. 133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SwitchProcess(); 1345d9a1bce7875ac9deb71e0fd2f35b71bf79e9d11hta@webrtc.org EXPECT_TRUE(WaitForCount(count_before + 1, &count)); 135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org EXPECT_TRUE(thread->Stop()); 136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete thread; 137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete crit_sect; 138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} // anonymous namespace 141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} // namespace webrtc 143