| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/browser_watcher/window_hang_monitor_win.h" | 5 #include "components/browser_watcher/window_hang_monitor_win.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 HangMonitorThread() | 50 HangMonitorThread() |
| 51 : event_(WindowHangMonitor::WINDOW_NOT_FOUND), | 51 : event_(WindowHangMonitor::WINDOW_NOT_FOUND), |
| 52 event_received_(false, false), | 52 event_received_(false, false), |
| 53 thread_("HangMonitorThread") {} | 53 thread_("HangMonitorThread") {} |
| 54 | 54 |
| 55 ~HangMonitorThread() { | 55 ~HangMonitorThread() { |
| 56 if (hang_monitor_.get()) | 56 if (hang_monitor_.get()) |
| 57 DestroyWatcher(); | 57 DestroyWatcher(); |
| 58 } | 58 } |
| 59 | 59 |
| 60 // Starts the background thread and the monitor to observe the window named | 60 // Starts the background thread and the monitor to observe Chrome message |
| 61 // |window_name| in |process|. Blocks until the monitor has been initialized. | 61 // window for |process|. Blocks until the monitor has been initialized. |
| 62 bool Start(base::Process process, const base::string16& window_name) { | 62 bool Start(base::Process process) { |
| 63 if (!thread_.StartWithOptions( | 63 if (!thread_.StartWithOptions( |
| 64 base::Thread::Options(base::MessageLoop::TYPE_UI, 0))) { | 64 base::Thread::Options(base::MessageLoop::TYPE_UI, 0))) { |
| 65 return false; | 65 return false; |
| 66 } | 66 } |
| 67 | 67 |
| 68 base::WaitableEvent complete(false, false); | 68 base::WaitableEvent complete(false, false); |
| 69 if (!thread_.task_runner()->PostTask( | 69 if (!thread_.task_runner()->PostTask( |
| 70 FROM_HERE, base::Bind(&HangMonitorThread::StartupOnThread, | 70 FROM_HERE, |
| 71 base::Unretained(this), window_name, | 71 base::Bind(&HangMonitorThread::StartupOnThread, |
| 72 base::Passed(process.Pass()), | 72 base::Unretained(this), base::Passed(std::move(process)), |
| 73 base::Unretained(&complete)))) { | 73 base::Unretained(&complete)))) { |
| 74 return false; | 74 return false; |
| 75 } | 75 } |
| 76 | 76 |
| 77 complete.Wait(); | 77 complete.Wait(); |
| 78 | 78 |
| 79 return true; | 79 return true; |
| 80 } | 80 } |
| 81 | 81 |
| 82 // Returns true if a window event is detected within |timeout|. | 82 // Returns true if a window event is detected within |timeout|. |
| 83 bool TimedWaitForEvent(base::TimeDelta timeout) { | 83 bool TimedWaitForEvent(base::TimeDelta timeout) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 103 private: | 103 private: |
| 104 // Invoked when the monitor signals an event. Unblocks a call to | 104 // Invoked when the monitor signals an event. Unblocks a call to |
| 105 // TimedWaitForEvent or WaitForEvent. | 105 // TimedWaitForEvent or WaitForEvent. |
| 106 void EventCallback(WindowHangMonitor::WindowEvent event) { | 106 void EventCallback(WindowHangMonitor::WindowEvent event) { |
| 107 if (event_received_.IsSignaled()) | 107 if (event_received_.IsSignaled()) |
| 108 ADD_FAILURE() << "Multiple calls to EventCallback."; | 108 ADD_FAILURE() << "Multiple calls to EventCallback."; |
| 109 event_ = event; | 109 event_ = event; |
| 110 event_received_.Signal(); | 110 event_received_.Signal(); |
| 111 } | 111 } |
| 112 | 112 |
| 113 // Initializes the WindowHangMonitor to observe the window named |window_name| | 113 // Initializes the WindowHangMonitor to observe the Chrome message window for |
| 114 // in |process|. Signals |complete| when done. | 114 // |process|. Signals |complete| when done. |
| 115 void StartupOnThread(const base::string16& window_name, | 115 void StartupOnThread(base::Process process, base::WaitableEvent* complete) { |
| 116 base::Process process, | |
| 117 base::WaitableEvent* complete) { | |
| 118 hang_monitor_.reset(new WindowHangMonitor( | 116 hang_monitor_.reset(new WindowHangMonitor( |
| 119 base::TimeDelta::FromMilliseconds(100), | 117 base::TimeDelta::FromMilliseconds(100), |
| 120 base::TimeDelta::FromMilliseconds(100), | 118 base::TimeDelta::FromMilliseconds(100), |
| 121 base::Bind(&HangMonitorThread::EventCallback, base::Unretained(this)))); | 119 base::Bind(&HangMonitorThread::EventCallback, base::Unretained(this)))); |
| 122 hang_monitor_->Initialize(process.Pass(), window_name); | 120 hang_monitor_->Initialize(std::move(process)); |
| 123 complete->Signal(); | 121 complete->Signal(); |
| 124 } | 122 } |
| 125 | 123 |
| 126 // Destroys the WindowHangMonitor. | 124 // Destroys the WindowHangMonitor. |
| 127 void ShutdownOnThread() { hang_monitor_.reset(); } | 125 void ShutdownOnThread() { hang_monitor_.reset(); } |
| 128 | 126 |
| 129 // The detected event. Invalid if |event_received_| has not been signaled. | 127 // The detected event. Invalid if |event_received_| has not been signaled. |
| 130 WindowHangMonitor::WindowEvent event_; | 128 WindowHangMonitor::WindowEvent event_; |
| 131 // Indicates that |event_| has been assigned in response to a callback from | 129 // Indicates that |event_| has been assigned in response to a callback from |
| 132 // the WindowHangMonitor. | 130 // the WindowHangMonitor. |
| 133 base::WaitableEvent event_received_; | 131 base::WaitableEvent event_received_; |
| 134 // The WindowHangMonitor under test. | 132 // The WindowHangMonitor under test. |
| 135 scoped_ptr<WindowHangMonitor> hang_monitor_; | 133 scoped_ptr<WindowHangMonitor> hang_monitor_; |
| 136 // The background thread. | 134 // The background thread. |
| 137 base::Thread thread_; | 135 base::Thread thread_; |
| 138 | 136 |
| 139 DISALLOW_COPY_AND_ASSIGN(HangMonitorThread); | 137 DISALLOW_COPY_AND_ASSIGN(HangMonitorThread); |
| 140 }; | 138 }; |
| 141 | 139 |
| 142 class WindowHangMonitorTest : public testing::Test { | 140 class WindowHangMonitorTest : public testing::Test { |
| 143 public: | 141 public: |
| 144 WindowHangMonitorTest() | 142 WindowHangMonitorTest() |
| 145 : ping_event_(false, false), | 143 : ping_event_(false, false), |
| 146 pings_(0), | 144 pings_(0), |
| 147 window_thread_("WindowHangMonitorTest window_thread") {} | 145 window_thread_("WindowHangMonitorTest window_thread") {} |
| 148 | 146 |
| 149 void SetUp() override { | 147 void SetUp() override { |
| 150 // Pick a window name unique to this process. | |
| 151 window_name_ = base::StringPrintf(L"WindowHanMonitorTest-%d", | |
| 152 base::GetCurrentProcId()); | |
| 153 ASSERT_TRUE(window_thread_.StartWithOptions( | 148 ASSERT_TRUE(window_thread_.StartWithOptions( |
| 154 base::Thread::Options(base::MessageLoop::TYPE_UI, 0))); | 149 base::Thread::Options(base::MessageLoop::TYPE_UI, 0))); |
| 155 } | 150 } |
| 156 | 151 |
| 157 void TearDown() override { | 152 void TearDown() override { |
| 158 DeleteMessageWindow(); | 153 DeleteMessageWindow(); |
| 159 window_thread_.Stop(); | 154 window_thread_.Stop(); |
| 160 } | 155 } |
| 161 | 156 |
| 162 void CreateMessageWindow() { | 157 void CreateMessageWindow() { |
| 163 bool succeeded = false; | 158 bool succeeded = false; |
| 164 base::WaitableEvent created(true, false); | 159 base::WaitableEvent created(true, false); |
| 165 ASSERT_TRUE(window_thread_.task_runner()->PostTask( | 160 ASSERT_TRUE(window_thread_.task_runner()->PostTask( |
| 166 FROM_HERE, | 161 FROM_HERE, |
| 167 base::Bind(&WindowHangMonitorTest::CreateMessageWindowInWorkerThread, | 162 base::Bind(&WindowHangMonitorTest::CreateMessageWindowInWorkerThread, |
| 168 base::Unretained(this), window_name_, &succeeded, | 163 base::Unretained(this), &succeeded, &created))); |
| 169 &created))); | |
| 170 created.Wait(); | 164 created.Wait(); |
| 171 ASSERT_TRUE(succeeded); | 165 ASSERT_TRUE(succeeded); |
| 172 } | 166 } |
| 173 | 167 |
| 174 void DeleteMessageWindow() { | 168 void DeleteMessageWindow() { |
| 175 base::WaitableEvent deleted(true, false); | 169 base::WaitableEvent deleted(true, false); |
| 176 window_thread_.task_runner()->PostTask( | 170 window_thread_.task_runner()->PostTask( |
| 177 FROM_HERE, | 171 FROM_HERE, |
| 178 base::Bind(&WindowHangMonitorTest::DeleteMessageWindowInWorkerThread, | 172 base::Bind(&WindowHangMonitorTest::DeleteMessageWindowInWorkerThread, |
| 179 base::Unretained(this), &deleted)); | 173 base::Unretained(this), &deleted)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 193 ping_event_.Wait(); | 187 ping_event_.Wait(); |
| 194 } | 188 } |
| 195 } | 189 } |
| 196 | 190 |
| 197 HangMonitorThread& monitor_thread() { return monitor_thread_; } | 191 HangMonitorThread& monitor_thread() { return monitor_thread_; } |
| 198 | 192 |
| 199 const base::win::MessageWindow* message_window() const { | 193 const base::win::MessageWindow* message_window() const { |
| 200 return message_window_.get(); | 194 return message_window_.get(); |
| 201 } | 195 } |
| 202 | 196 |
| 203 const base::string16& window_name() const { return window_name_; } | |
| 204 | |
| 205 base::Thread* window_thread() { return &window_thread_; } | 197 base::Thread* window_thread() { return &window_thread_; } |
| 206 | 198 |
| 207 private: | 199 private: |
| 208 bool MessageCallback(UINT message, | 200 bool MessageCallback(UINT message, |
| 209 WPARAM wparam, | 201 WPARAM wparam, |
| 210 LPARAM lparam, | 202 LPARAM lparam, |
| 211 LRESULT* result) { | 203 LRESULT* result) { |
| 212 EXPECT_EQ(window_thread_.message_loop(), base::MessageLoop::current()); | 204 EXPECT_EQ(window_thread_.message_loop(), base::MessageLoop::current()); |
| 213 if (message == WM_NULL) { | 205 if (message == WM_NULL) { |
| 214 base::AutoLock auto_lock(ping_lock_); | 206 base::AutoLock auto_lock(ping_lock_); |
| 215 ++pings_; | 207 ++pings_; |
| 216 ping_event_.Signal(); | 208 ping_event_.Signal(); |
| 217 } | 209 } |
| 218 | 210 |
| 219 return false; // Pass through to DefWindowProc. | 211 return false; // Pass through to DefWindowProc. |
| 220 } | 212 } |
| 221 | 213 |
| 222 void CreateMessageWindowInWorkerThread(const base::string16& name, | 214 void CreateMessageWindowInWorkerThread(bool* success, |
| 223 bool* success, | |
| 224 base::WaitableEvent* created) { | 215 base::WaitableEvent* created) { |
| 225 message_window_.reset(new base::win::MessageWindow); | 216 message_window_.reset(new base::win::MessageWindow); |
| 226 *success = message_window_->CreateNamed( | 217 *success = message_window_->CreateNamed( |
| 227 base::Bind(&WindowHangMonitorTest::MessageCallback, | 218 base::Bind(&WindowHangMonitorTest::MessageCallback, |
| 228 base::Unretained(this)), | 219 base::Unretained(this)), |
| 229 name); | 220 L"BogusMessageWindowName"); |
| 230 created->Signal(); | 221 created->Signal(); |
| 231 } | 222 } |
| 232 | 223 |
| 233 void DeleteMessageWindowInWorkerThread(base::WaitableEvent* deleted) { | 224 void DeleteMessageWindowInWorkerThread(base::WaitableEvent* deleted) { |
| 234 message_window_.reset(); | 225 message_window_.reset(); |
| 235 if (deleted) | 226 if (deleted) |
| 236 deleted->Signal(); | 227 deleted->Signal(); |
| 237 } | 228 } |
| 238 | 229 |
| 239 HangMonitorThread monitor_thread_; | 230 HangMonitorThread monitor_thread_; |
| 240 scoped_ptr<base::win::MessageWindow> message_window_; | 231 scoped_ptr<base::win::MessageWindow> message_window_; |
| 241 base::string16 window_name_; | |
| 242 base::Lock ping_lock_; | 232 base::Lock ping_lock_; |
| 243 base::WaitableEvent ping_event_; | 233 base::WaitableEvent ping_event_; |
| 244 size_t pings_; | 234 size_t pings_; |
| 245 base::Thread window_thread_; | 235 base::Thread window_thread_; |
| 246 | 236 |
| 247 DISALLOW_COPY_AND_ASSIGN(WindowHangMonitorTest); | 237 DISALLOW_COPY_AND_ASSIGN(WindowHangMonitorTest); |
| 248 }; | 238 }; |
| 249 | 239 |
| 250 } // namespace | 240 } // namespace |
| 251 | 241 |
| 252 TEST_F(WindowHangMonitorTest, NoWindow) { | 242 TEST_F(WindowHangMonitorTest, NoWindow) { |
| 253 base::CommandLine child_command_line = | 243 base::CommandLine child_command_line = |
| 254 base::GetMultiProcessTestChildBaseCommandLine(); | 244 base::GetMultiProcessTestChildBaseCommandLine(); |
| 255 child_command_line.AppendSwitchASCII(switches::kTestChildProcess, | 245 child_command_line.AppendSwitchASCII(switches::kTestChildProcess, |
| 256 "NoWindowChild"); | 246 "NoWindowChild"); |
| 257 base::Process process = | 247 base::Process process = |
| 258 base::LaunchProcess(child_command_line, base::LaunchOptions()); | 248 base::LaunchProcess(child_command_line, base::LaunchOptions()); |
| 259 ASSERT_TRUE(process.IsValid()); | 249 ASSERT_TRUE(process.IsValid()); |
| 260 | 250 |
| 261 base::ScopedClosureRunner terminate_process_runner( | 251 base::ScopedClosureRunner terminate_process_runner( |
| 262 base::Bind(base::IgnoreResult(&base::Process::Terminate), | 252 base::Bind(base::IgnoreResult(&base::Process::Terminate), |
| 263 base::Unretained(&process), 1, true)); | 253 base::Unretained(&process), 1, true)); |
| 264 | 254 |
| 265 monitor_thread().Start(process.Duplicate(), window_name()); | 255 monitor_thread().Start(process.Duplicate()); |
| 266 | 256 |
| 267 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 257 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 268 base::TimeDelta::FromMilliseconds(150))); | 258 base::TimeDelta::FromMilliseconds(150))); |
| 269 | 259 |
| 270 terminate_process_runner.Reset(); | 260 terminate_process_runner.Reset(); |
| 271 | 261 |
| 272 ASSERT_EQ(WindowHangMonitor::WINDOW_NOT_FOUND, | 262 ASSERT_EQ(WindowHangMonitor::WINDOW_NOT_FOUND, |
| 273 monitor_thread().WaitForEvent()); | 263 monitor_thread().WaitForEvent()); |
| 274 | 264 |
| 275 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 265 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 276 base::TimeDelta::FromMilliseconds(150))); | 266 base::TimeDelta::FromMilliseconds(150))); |
| 277 } | 267 } |
| 278 | 268 |
| 279 TEST_F(WindowHangMonitorTest, WindowBeforeWatcher) { | 269 TEST_F(WindowHangMonitorTest, WindowBeforeWatcher) { |
| 280 CreateMessageWindow(); | 270 CreateMessageWindow(); |
| 281 | 271 |
| 282 monitor_thread().Start(base::Process::Current(), window_name()); | 272 monitor_thread().Start(base::Process::Current()); |
| 283 | 273 |
| 284 WaitForPing(); | 274 WaitForPing(); |
| 285 | 275 |
| 286 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 276 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 287 base::TimeDelta::FromMilliseconds(150))); | 277 base::TimeDelta::FromMilliseconds(150))); |
| 288 } | 278 } |
| 289 | 279 |
| 290 TEST_F(WindowHangMonitorTest, WindowBeforeDestroy) { | 280 TEST_F(WindowHangMonitorTest, WindowBeforeDestroy) { |
| 291 CreateMessageWindow(); | 281 CreateMessageWindow(); |
| 292 | 282 |
| 293 monitor_thread().Start(base::Process::Current(), window_name()); | 283 monitor_thread().Start(base::Process::Current()); |
| 294 | 284 |
| 295 WaitForPing(); | 285 WaitForPing(); |
| 296 | 286 |
| 297 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 287 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 298 base::TimeDelta::FromMilliseconds(150))); | 288 base::TimeDelta::FromMilliseconds(150))); |
| 299 | 289 |
| 300 monitor_thread().DestroyWatcher(); | 290 monitor_thread().DestroyWatcher(); |
| 301 | 291 |
| 302 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(base::TimeDelta())); | 292 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(base::TimeDelta())); |
| 303 } | 293 } |
| 304 | 294 |
| 305 TEST_F(WindowHangMonitorTest, NoWindowBeforeDestroy) { | 295 TEST_F(WindowHangMonitorTest, NoWindowBeforeDestroy) { |
| 306 monitor_thread().Start(base::Process::Current(), window_name()); | 296 monitor_thread().Start(base::Process::Current()); |
| 307 | 297 |
| 308 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 298 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 309 base::TimeDelta::FromMilliseconds(150))); | 299 base::TimeDelta::FromMilliseconds(150))); |
| 310 monitor_thread().DestroyWatcher(); | 300 monitor_thread().DestroyWatcher(); |
| 311 | 301 |
| 312 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(base::TimeDelta())); | 302 ASSERT_FALSE(monitor_thread().TimedWaitForEvent(base::TimeDelta())); |
| 313 } | 303 } |
| 314 | 304 |
| 315 TEST_F(WindowHangMonitorTest, WatcherBeforeWindow) { | 305 TEST_F(WindowHangMonitorTest, WatcherBeforeWindow) { |
| 316 monitor_thread().Start(base::Process::Current(), window_name()); | 306 monitor_thread().Start(base::Process::Current()); |
| 317 | 307 |
| 318 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 308 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 319 base::TimeDelta::FromMilliseconds(150))); | 309 base::TimeDelta::FromMilliseconds(150))); |
| 320 | 310 |
| 321 CreateMessageWindow(); | 311 CreateMessageWindow(); |
| 322 | 312 |
| 323 WaitForPing(); | 313 WaitForPing(); |
| 324 | 314 |
| 325 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 315 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 326 base::TimeDelta::FromMilliseconds(150))); | 316 base::TimeDelta::FromMilliseconds(150))); |
| 327 } | 317 } |
| 328 | 318 |
| 329 TEST_F(WindowHangMonitorTest, DetectsWindowDisappearance) { | 319 TEST_F(WindowHangMonitorTest, DetectsWindowDisappearance) { |
| 330 CreateMessageWindow(); | 320 CreateMessageWindow(); |
| 331 | 321 |
| 332 monitor_thread().Start(base::Process::Current(), window_name()); | 322 monitor_thread().Start(base::Process::Current()); |
| 333 | 323 |
| 334 WaitForPing(); | 324 WaitForPing(); |
| 335 | 325 |
| 336 DeleteMessageWindow(); | 326 DeleteMessageWindow(); |
| 337 | 327 |
| 338 ASSERT_EQ(WindowHangMonitor::WINDOW_VANISHED, | 328 ASSERT_EQ(WindowHangMonitor::WINDOW_VANISHED, |
| 339 monitor_thread().WaitForEvent()); | 329 monitor_thread().WaitForEvent()); |
| 340 | 330 |
| 341 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 331 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 342 base::TimeDelta::FromMilliseconds(150))); | 332 base::TimeDelta::FromMilliseconds(150))); |
| 343 } | 333 } |
| 344 | 334 |
| 345 TEST_F(WindowHangMonitorTest, DetectsWindowNameChange) { | |
| 346 // This test changes the title of the message window as a proxy for what | |
| 347 // happens if the window handle is reused for a different purpose. The latter | |
| 348 // is impossible to test in a deterministic fashion. | |
| 349 CreateMessageWindow(); | |
| 350 | |
| 351 monitor_thread().Start(base::Process::Current(), window_name()); | |
| 352 | |
| 353 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | |
| 354 base::TimeDelta::FromMilliseconds(150))); | |
| 355 | |
| 356 ASSERT_TRUE(::SetWindowText(message_window()->hwnd(), L"Gonsky")); | |
| 357 | |
| 358 ASSERT_EQ(WindowHangMonitor::WINDOW_VANISHED, | |
| 359 monitor_thread().WaitForEvent()); | |
| 360 } | |
| 361 | |
| 362 TEST_F(WindowHangMonitorTest, DetectsWindowHang) { | 335 TEST_F(WindowHangMonitorTest, DetectsWindowHang) { |
| 363 CreateMessageWindow(); | 336 CreateMessageWindow(); |
| 364 | 337 |
| 365 monitor_thread().Start(base::Process::Current(), window_name()); | 338 monitor_thread().Start(base::Process::Current()); |
| 366 | 339 |
| 367 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 340 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 368 base::TimeDelta::FromMilliseconds(150))); | 341 base::TimeDelta::FromMilliseconds(150))); |
| 369 | 342 |
| 370 // Block the worker thread. | 343 // Block the worker thread. |
| 371 base::WaitableEvent hang(true, false); | 344 base::WaitableEvent hang(true, false); |
| 372 | 345 |
| 373 window_thread()->task_runner()->PostTask( | 346 window_thread()->task_runner()->PostTask( |
| 374 FROM_HERE, | 347 FROM_HERE, |
| 375 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&hang))); | 348 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&hang))); |
| 376 | 349 |
| 377 EXPECT_EQ(WindowHangMonitor::WINDOW_HUNG, | 350 EXPECT_EQ(WindowHangMonitor::WINDOW_HUNG, |
| 378 monitor_thread().WaitForEvent()); | 351 monitor_thread().WaitForEvent()); |
| 379 | 352 |
| 380 // Unblock the worker thread. | 353 // Unblock the worker thread. |
| 381 hang.Signal(); | 354 hang.Signal(); |
| 382 | 355 |
| 383 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( | 356 ASSERT_FALSE(monitor_thread().TimedWaitForEvent( |
| 384 base::TimeDelta::FromMilliseconds(150))); | 357 base::TimeDelta::FromMilliseconds(150))); |
| 385 } | 358 } |
| 386 | 359 |
| 387 } // namespace browser_watcher | 360 } // namespace browser_watcher |
| OLD | NEW |