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