Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(285)

Side by Side Diff: webrtc/system_wrappers/source/event_timer_posix_unittest.cc

Issue 1812533002: Fix race condition in EventTimerPosix (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fixed race in test code Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2016 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/source/event_timer_posix.h"
12
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "webrtc/base/event.h"
15 #include "webrtc/base/criticalsection.h"
16
17 namespace webrtc {
18
19 enum class ThreadState {
20 kNotStarted,
21 kWaiting,
22 kRequestProcessCall,
23 kCallingProcess,
24 kProcessDone,
25 kContinue,
26 kExiting,
27 kDead
28 };
29
30 class EventTimerPosixTest : public testing::Test, public EventTimerPosix {
31 public:
32 EventTimerPosixTest()
33 : thread_state_(ThreadState::kNotStarted),
34 process_event_(false, true),
35 main_event_(false, true),
36 process_thread_id_(0),
37 process_thread_(nullptr) {}
38 virtual ~EventTimerPosixTest() {}
39
40 rtc::PlatformThread* CreateThread() override {
41 EXPECT_TRUE(process_thread_ == nullptr);
42 process_thread_ =
43 new rtc::PlatformThread(Run, this, "EventTimerPosixTestThread");
44 return process_thread_;
45 }
46
47 static bool Run(void* obj) {
48 return static_cast<EventTimerPosixTest*>(obj)->Process();
49 }
50
51 bool Process() {
52 {
53 rtc::CritScope cs(&lock_);
54 process_thread_id_ = rtc::CurrentThreadId();
55 }
56
57 if (!SetThreadState(ThreadState::kWaiting))
58 return false;
59
60 if (!AwaitThreadState(ThreadState::kRequestProcessCall,
61 rtc::Event::kForever)) {
62 SetThreadState(ThreadState::kDead);
63 return false;
64 }
65
66 if (!SetThreadState(ThreadState::kCallingProcess))
67 return false;
68
69 EventTimerPosix::Process();
70
71 if (!SetThreadState(ThreadState::kProcessDone))
72 return false;
73
74 if (!AwaitThreadState(ThreadState::kContinue, rtc::Event::kForever)) {
75 SetThreadState(ThreadState::kDead);
76 return false;
77 }
78
79 return true;
80 }
81
82 bool IsProcessThread() {
83 rtc::CritScope cs(&lock_);
84 return process_thread_id_ == rtc::CurrentThreadId();
85 }
86
87 bool SetThreadState(ThreadState state) {
88 rtc::CritScope cs(&lock_);
89 if (thread_state_ == ThreadState::kDead)
90 return false;
91 thread_state_ = state;
92 if (IsProcessThread()) {
93 main_event_.Set();
94 } else {
95 process_event_.Set();
96 }
97 return true;
98 }
99
100 bool AwaitThreadState(ThreadState state, int timeout) {
101 rtc::Event* event = IsProcessThread() ? &process_event_ : &main_event_;
102 do {
103 rtc::CritScope cs(&lock_);
104 if (state != ThreadState::kDead && thread_state_ == ThreadState::kExiting)
105 return false;
106 if (thread_state_ == state)
107 return true;
108 } while (event->Wait(timeout));
109 return false;
110 }
111
112 bool CallProcess(int timeout_ms) {
113 return AwaitThreadState(ThreadState::kWaiting, timeout_ms) &&
114 SetThreadState(ThreadState::kRequestProcessCall);
115 }
116
117 bool AwaitProcessDone(int timeout_ms) {
118 return AwaitThreadState(ThreadState::kProcessDone, timeout_ms) &&
119 SetThreadState(ThreadState::kContinue);
120 }
121
122 void TearDown() override {
123 if (process_thread_) {
124 SetThreadState(ThreadState::kExiting);
125 AwaitThreadState(ThreadState::kDead, 5000);
126 }
127 }
128
129 ThreadState thread_state_;
130 rtc::CriticalSection lock_;
131 rtc::Event process_event_;
132 rtc::Event main_event_;
133 rtc::PlatformThreadId process_thread_id_;
134 rtc::PlatformThread* process_thread_;
135 };
136
137 TEST_F(EventTimerPosixTest, WaiterBlocksUntilTimeout) {
138 const int kTimerIntervalMs = 100;
139 const int kTimeoutMs = 5000;
140 ASSERT_TRUE(StartTimer(false, kTimerIntervalMs));
141 ASSERT_TRUE(CallProcess(kTimeoutMs));
142 EventTypeWrapper res = Wait(kTimeoutMs);
143 EXPECT_EQ(kEventSignaled, res);
144 ASSERT_TRUE(AwaitProcessDone(kTimeoutMs));
145 }
146
147 TEST_F(EventTimerPosixTest, WaiterWakesImmediatelyAfterTimeout) {
148 const int kTimerIntervalMs = 100;
149 const int kTimeoutMs = 5000;
150 ASSERT_TRUE(StartTimer(false, kTimerIntervalMs));
151 ASSERT_TRUE(CallProcess(kTimeoutMs));
152 ASSERT_TRUE(AwaitProcessDone(kTimeoutMs));
153 EventTypeWrapper res = Wait(0);
154 EXPECT_EQ(kEventSignaled, res);
155 }
156
157 TEST_F(EventTimerPosixTest, WaiterBlocksUntilTimeoutProcessInactiveOnStart) {
158 const int kTimerIntervalMs = 100;
159 const int kTimeoutMs = 5000;
160 // First call to StartTimer initializes thread.
161 ASSERT_TRUE(StartTimer(false, kTimerIntervalMs));
162
163 // Process thread currently _not_ blocking on Process() call.
164 ASSERT_TRUE(AwaitThreadState(ThreadState::kWaiting, kTimeoutMs));
165
166 // Start new one-off timer, then call Process().
167 ASSERT_TRUE(StartTimer(false, kTimerIntervalMs));
168 ASSERT_TRUE(CallProcess(kTimeoutMs));
169
170 EventTypeWrapper res = Wait(kTimeoutMs);
171 EXPECT_EQ(kEventSignaled, res);
172
173 ASSERT_TRUE(AwaitProcessDone(kTimeoutMs));
174 }
175
176 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698