thread_watcher_unittest.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/basictypes.h" 6#include "base/logging.h" 7#include "base/message_loop.h" 8#include "base/message_loop_proxy.h" 9#include "base/scoped_ptr.h" 10#include "base/synchronization/condition_variable.h" 11#include "base/synchronization/lock.h" 12#include "base/threading/platform_thread.h" 13#include "base/time.h" 14#include "build/build_config.h" 15#include "chrome/browser/metrics/thread_watcher.h" 16#include "testing/gtest/include/gtest/gtest.h" 17#include "testing/platform_test.h" 18 19using base::TimeDelta; 20using base::TimeTicks; 21 22enum State { 23 INITIALIZED, // Created ThreadWatch object. 24 ACTIVATED, // Thread watching activated. 25 SENT_PING, // Sent ping message to watched thread. 26 RECEIVED_PONG, // Received Pong message. 27 DEACTIVATED, // Thread watching de-activated. 28}; 29 30enum WaitState { 31 UNINITIALIZED, 32 STARTED_WAITING, // Start waiting for state_ to change to expected_state. 33 STOPPED_WAITING, // Done with the waiting. 34 ALL_DONE, // Done with waiting for STOPPED_WAITING. 35}; 36 37enum CheckResponseState { 38 UNKNOWN, 39 SUCCESSFUL, // CheckResponse was successful. 40 FAILED, // CheckResponse has failed. 41}; 42 43class CustomThreadWatcher : public ThreadWatcher { 44 public: 45 base::Lock custom_lock_; 46 base::ConditionVariable state_changed_; 47 State thread_watcher_state_; 48 WaitState wait_state_; 49 CheckResponseState check_response_state_; 50 uint64 ping_sent_; 51 uint64 pong_received_; 52 uint64 success_response_; 53 uint64 failed_response_; 54 base::TimeTicks saved_ping_time_; 55 uint64 saved_ping_sequence_number_; 56 57 CustomThreadWatcher(const BrowserThread::ID thread_id, 58 const std::string thread_name, 59 const TimeDelta& sleep_time, 60 const TimeDelta& unresponsive_time) 61 : ThreadWatcher(thread_id, thread_name, sleep_time, unresponsive_time), 62 state_changed_(&custom_lock_), 63 thread_watcher_state_(INITIALIZED), 64 wait_state_(UNINITIALIZED), 65 check_response_state_(UNKNOWN), 66 ping_sent_(0), 67 pong_received_(0), 68 success_response_(0), 69 failed_response_(0), 70 saved_ping_time_(base::TimeTicks::Now()), 71 saved_ping_sequence_number_(0) { 72 } 73 74 State UpdateState(State new_state) { 75 State old_state; 76 { 77 base::AutoLock auto_lock(custom_lock_); 78 old_state = thread_watcher_state_; 79 if (old_state != DEACTIVATED) 80 thread_watcher_state_ = new_state; 81 if (new_state == SENT_PING) 82 ++ping_sent_; 83 if (new_state == RECEIVED_PONG) 84 ++pong_received_; 85 saved_ping_time_ = ping_time(); 86 saved_ping_sequence_number_ = ping_sequence_number(); 87 } 88 state_changed_.Broadcast(); 89 // LOG(INFO) << "UpdateState: thread_name_: " << thread_name_ << 90 // " thread_watcher_state_: " << new_state; 91 return old_state; 92 } 93 94 WaitState UpdateWaitState(WaitState new_state) { 95 WaitState old_state; 96 { 97 base::AutoLock auto_lock(custom_lock_); 98 old_state = wait_state_; 99 wait_state_ = new_state; 100 } 101 state_changed_.Broadcast(); 102 // LOG(INFO) << "UpdateWaitState: thread_name_: " << thread_name_ << 103 // " wait_state_: " << new_state; 104 return old_state; 105 } 106 107 void ActivateThreadWatching() { 108 State old_state = UpdateState(ACTIVATED); 109 EXPECT_EQ(old_state, INITIALIZED); 110 ThreadWatcher::ActivateThreadWatching(); 111 } 112 113 void DeActivateThreadWatching() { 114 State old_state = UpdateState(DEACTIVATED); 115 EXPECT_TRUE(old_state == ACTIVATED || old_state == SENT_PING || 116 old_state == RECEIVED_PONG); 117 ThreadWatcher::DeActivateThreadWatching(); 118 } 119 120 void PostPingMessage() { 121 State old_state = UpdateState(SENT_PING); 122 EXPECT_TRUE(old_state == ACTIVATED || old_state == RECEIVED_PONG); 123 ThreadWatcher::PostPingMessage(); 124 } 125 126 void OnPongMessage(uint64 ping_sequence_number) { 127 State old_state = UpdateState(RECEIVED_PONG); 128 EXPECT_TRUE(old_state == SENT_PING || old_state == DEACTIVATED); 129 ThreadWatcher::OnPongMessage(ping_sequence_number); 130 } 131 132 bool OnCheckResponsiveness(uint64 ping_sequence_number) { 133 bool responsive = 134 ThreadWatcher::OnCheckResponsiveness(ping_sequence_number); 135 // LOG(INFO) << "CheckResponse: thread_name_: " << thread_name_ << 136 // " ping_sequence_number_:" << ping_sequence_number_ << 137 // " ping_sequence_number:" << ping_sequence_number << 138 // " responsive: " << responsive; 139 { 140 base::AutoLock auto_lock(custom_lock_); 141 if (responsive) { 142 ++success_response_; 143 check_response_state_ = SUCCESSFUL; 144 } else { 145 ++failed_response_; 146 check_response_state_ = FAILED; 147 } 148 } 149 // Broadcast to indicate we have checked responsiveness of the thread that 150 // is watched. 151 state_changed_.Broadcast(); 152 return responsive; 153 } 154 155 void WaitForWaitStateChange(TimeDelta wait_time, WaitState expected_state) { 156 DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread()); 157 TimeTicks end_time = TimeTicks::Now() + wait_time; 158 { 159 base::AutoLock auto_lock(custom_lock_); 160 while (wait_state_ != expected_state && TimeTicks::Now() < end_time) 161 state_changed_.TimedWait(end_time - TimeTicks::Now()); 162 } 163 } 164 165 void VeryLongMethod(TimeDelta wait_time) { 166 DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread()); 167 WaitForWaitStateChange(wait_time, STOPPED_WAITING); 168 UpdateWaitState(ALL_DONE); 169 } 170 171 State WaitForStateChange(const TimeDelta& wait_time, State expected_state) { 172 DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread()); 173 UpdateWaitState(STARTED_WAITING); 174 175 State exit_state; 176 // Keep the thread that is running the tests waiting until ThreadWatcher 177 // object's state changes to the expected_state or until wait_time elapses. 178 for (int i = 0; i < 3; ++i) { 179 TimeTicks end_time = TimeTicks::Now() + wait_time; 180 { 181 base::AutoLock auto_lock(custom_lock_); 182 while (thread_watcher_state_ != expected_state && 183 TimeTicks::Now() < end_time) { 184 TimeDelta state_change_wait_time = end_time - TimeTicks::Now(); 185 // LOG(INFO) << "In WaitForStateChange: thread_name_: " << 186 // thread_name_ << " i:" << i << 187 // " wait: " << state_change_wait_time.InMilliseconds() << 188 // " thread_watcher_state_: " << thread_watcher_state_; 189 state_changed_.TimedWait(state_change_wait_time); 190 } 191 // Capture the thread_watcher_state_ before it changes and return it 192 // to the caller. 193 exit_state = thread_watcher_state_; 194 if (exit_state == expected_state) 195 break; 196 } 197 } 198 // LOG(INFO) << "In WaitForStateChange: thread_name_: " << thread_name_ << 199 // " expected_state: " << expected_state << 200 // " exit_state:" << exit_state; 201 UpdateWaitState(STOPPED_WAITING); 202 return exit_state; 203 } 204 205 CheckResponseState WaitForCheckResponse(const TimeDelta& wait_time, 206 CheckResponseState expected_state) { 207 DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread()); 208 UpdateWaitState(STARTED_WAITING); 209 210 CheckResponseState exit_state; 211 // Keep the thread that is running the tests waiting until ThreadWatcher 212 // object's check_response_state_ changes to the expected_state or until 213 // wait_time elapses. 214 for (int i = 0; i < 3; ++i) { 215 TimeTicks end_time = TimeTicks::Now() + wait_time; 216 { 217 base::AutoLock auto_lock(custom_lock_); 218 while (check_response_state_ != expected_state && 219 TimeTicks::Now() < end_time) { 220 TimeDelta state_change_wait_time = end_time - TimeTicks::Now(); 221 // LOG(INFO) << "In WaitForCheckResponse: " << 222 // " thread_name_: " << thread_name_ << " i:" << i << 223 // " wait:" << state_change_wait_time.InMilliseconds() << 224 // " check_response_state_:" << check_response_state_; 225 state_changed_.TimedWait(state_change_wait_time); 226 } 227 // Capture the check_response_state_ before it changes and return it 228 // to the caller. 229 exit_state = check_response_state_; 230 if (exit_state == expected_state) 231 break; 232 } 233 } 234 // LOG(INFO) << "In WaitForCheckResponse: thread_name_: " << thread_name_ << 235 // " expected_state: " << expected_state << 236 // " exit_state:" << exit_state; 237 UpdateWaitState(STOPPED_WAITING); 238 return exit_state; 239 } 240}; 241 242DISABLE_RUNNABLE_METHOD_REFCOUNT(CustomThreadWatcher); 243 244class ThreadWatcherTest : public ::testing::Test { 245 public: 246 static const TimeDelta kSleepTime; 247 static const TimeDelta kUnresponsiveTime; 248 static const BrowserThread::ID io_thread_id; 249 static const std::string io_thread_name; 250 static const BrowserThread::ID webkit_thread_id; 251 static const std::string webkit_thread_name; 252 CustomThreadWatcher* io_watcher_; 253 CustomThreadWatcher* webkit_watcher_; 254 255 ThreadWatcherTest() { 256 webkit_thread_.reset(new BrowserThread(BrowserThread::WEBKIT)); 257 io_thread_.reset(new BrowserThread(BrowserThread::IO)); 258 watchdog_thread_.reset(new WatchDogThread()); 259 webkit_thread_->Start(); 260 io_thread_->Start(); 261 watchdog_thread_->Start(); 262 263 // Setup the registry for thread watchers. 264 thread_watcher_list_ = new ThreadWatcherList(); 265 266 // Create thread watcher object for the IO thread. 267 io_watcher_ = new CustomThreadWatcher(io_thread_id, io_thread_name, 268 kSleepTime, kUnresponsiveTime); 269 270 // Create thread watcher object for the WEBKIT thread. 271 webkit_watcher_ = new CustomThreadWatcher( 272 webkit_thread_id, webkit_thread_name, kSleepTime, kUnresponsiveTime); 273 } 274 275 ~ThreadWatcherTest() { 276 ThreadWatcherList::StopWatchingAll(); 277 io_watcher_ = NULL; 278 webkit_watcher_ = NULL; 279 // io_thread_->Stop(); 280 // webkit_thread_->Stop(); 281 // watchdog_thread_->Stop(); 282 io_thread_.reset(); 283 webkit_thread_.reset(); 284 watchdog_thread_.reset(); 285 delete thread_watcher_list_; 286 } 287 288 private: 289 scoped_ptr<BrowserThread> webkit_thread_; 290 scoped_ptr<BrowserThread> io_thread_; 291 scoped_ptr<WatchDogThread> watchdog_thread_; 292 ThreadWatcherList* thread_watcher_list_; 293}; 294 295// Define static constants. 296const TimeDelta ThreadWatcherTest::kSleepTime = 297 TimeDelta::FromMilliseconds(50); 298const TimeDelta ThreadWatcherTest::kUnresponsiveTime = 299 TimeDelta::FromMilliseconds(500); 300const BrowserThread::ID ThreadWatcherTest::io_thread_id = BrowserThread::IO; 301const std::string ThreadWatcherTest::io_thread_name = "IO"; 302const BrowserThread::ID ThreadWatcherTest::webkit_thread_id = 303 BrowserThread::WEBKIT; 304const std::string ThreadWatcherTest::webkit_thread_name = "WEBKIT"; 305 306// Test registration. When thread_watcher_list_ goes out of scope after 307// TearDown, all thread watcher objects will be deleted. 308TEST_F(ThreadWatcherTest, Registration) { 309 EXPECT_EQ(io_watcher_, ThreadWatcherList::Find(io_thread_id)); 310 EXPECT_EQ(webkit_watcher_, ThreadWatcherList::Find(webkit_thread_id)); 311 312 // Check ThreadWatcher object has all correct parameters. 313 EXPECT_EQ(io_thread_id, io_watcher_->thread_id()); 314 EXPECT_EQ(io_thread_name, io_watcher_->thread_name()); 315 EXPECT_EQ(kSleepTime, io_watcher_->sleep_time()); 316 EXPECT_EQ(kUnresponsiveTime, io_watcher_->unresponsive_time()); 317 EXPECT_FALSE(io_watcher_->active()); 318 319 // Check ThreadWatcher object of watched WEBKIT thread has correct data. 320 EXPECT_EQ(webkit_thread_id, webkit_watcher_->thread_id()); 321 EXPECT_EQ(webkit_thread_name, webkit_watcher_->thread_name()); 322 EXPECT_EQ(kSleepTime, webkit_watcher_->sleep_time()); 323 EXPECT_EQ(kUnresponsiveTime, webkit_watcher_->unresponsive_time()); 324 EXPECT_FALSE(webkit_watcher_->active()); 325} 326 327// Test ActivateThreadWatching and DeActivateThreadWatching of IO thread. This 328// method also checks that pong message was sent by the watched thread and pong 329// message was received by the WatchDogThread. It also checks that 330// OnCheckResponsiveness has verified the ping-pong mechanism and the watched 331// thread is not hung. 332TEST_F(ThreadWatcherTest, ThreadResponding) { 333 TimeTicks time_before_ping = TimeTicks::Now(); 334 // Activate watching IO thread. 335 WatchDogThread::PostTask( 336 FROM_HERE, 337 NewRunnableMethod(io_watcher_, &ThreadWatcher::ActivateThreadWatching)); 338 339 // Activate would have started ping/pong messaging. Expect atleast one 340 // ping/pong messaging sequence to happen. 341 io_watcher_->WaitForStateChange(kSleepTime + TimeDelta::FromMinutes(1), 342 RECEIVED_PONG); 343 EXPECT_GT(io_watcher_->ping_sent_, static_cast<uint64>(0)); 344 EXPECT_GT(io_watcher_->pong_received_, static_cast<uint64>(0)); 345 EXPECT_TRUE(io_watcher_->active()); 346 EXPECT_GE(io_watcher_->saved_ping_time_, time_before_ping); 347 EXPECT_GE(io_watcher_->saved_ping_sequence_number_, static_cast<uint64>(0)); 348 349 // Verify watched thread is responding with ping/pong messaging. 350 io_watcher_->WaitForCheckResponse( 351 kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL); 352 EXPECT_GT(io_watcher_->success_response_, static_cast<uint64>(0)); 353 EXPECT_EQ(io_watcher_->failed_response_, static_cast<uint64>(0)); 354 355 // DeActivate thread watching for shutdown. 356 WatchDogThread::PostTask( 357 FROM_HERE, 358 NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching)); 359} 360 361// This test posts a task on watched thread that takes very long time (this is 362// to simulate hanging of watched thread). It then checks for 363// OnCheckResponsiveness raising an alert (OnCheckResponsiveness returns false 364// if the watched thread is not responding). 365TEST_F(ThreadWatcherTest, ThreadNotResponding) { 366 // Simulate hanging of watched thread by making the watched thread wait for a 367 // very long time by posting a task on watched thread that keeps it busy. 368 BrowserThread::PostTask( 369 io_thread_id, 370 FROM_HERE, 371 NewRunnableMethod( 372 io_watcher_, 373 &CustomThreadWatcher::VeryLongMethod, 374 kUnresponsiveTime * 10)); 375 376 // Activate thread watching. 377 WatchDogThread::PostTask( 378 FROM_HERE, 379 NewRunnableMethod(io_watcher_, &ThreadWatcher::ActivateThreadWatching)); 380 381 // Verify watched thread is not responding for ping messages. 382 io_watcher_->WaitForCheckResponse( 383 kUnresponsiveTime + TimeDelta::FromMinutes(1), FAILED); 384 EXPECT_EQ(io_watcher_->success_response_, static_cast<uint64>(0)); 385 EXPECT_GT(io_watcher_->failed_response_, static_cast<uint64>(0)); 386 387 // DeActivate thread watching for shutdown. 388 WatchDogThread::PostTask( 389 FROM_HERE, 390 NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching)); 391 392 // Wait for the io_watcher_'s VeryLongMethod to finish. 393 io_watcher_->WaitForWaitStateChange(kUnresponsiveTime * 10, ALL_DONE); 394} 395 396// Test watching of multiple threads with all threads not responding. 397TEST_F(ThreadWatcherTest, MultipleThreadsResponding) { 398 // Check for WEBKIT thread to perform ping/pong messaging. 399 WatchDogThread::PostTask( 400 FROM_HERE, 401 NewRunnableMethod( 402 webkit_watcher_, &ThreadWatcher::ActivateThreadWatching)); 403 404 // Check for IO thread to perform ping/pong messaging. 405 WatchDogThread::PostTask( 406 FROM_HERE, 407 NewRunnableMethod(io_watcher_, &ThreadWatcher::ActivateThreadWatching)); 408 409 // Verify WEBKIT thread is responding with ping/pong messaging. 410 webkit_watcher_->WaitForCheckResponse( 411 kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL); 412 EXPECT_GT(webkit_watcher_->ping_sent_, static_cast<uint64>(0)); 413 EXPECT_GT(webkit_watcher_->pong_received_, static_cast<uint64>(0)); 414 EXPECT_GE(webkit_watcher_->ping_sequence_number_, static_cast<uint64>(0)); 415 EXPECT_GT(webkit_watcher_->success_response_, static_cast<uint64>(0)); 416 EXPECT_EQ(webkit_watcher_->failed_response_, static_cast<uint64>(0)); 417 418 // Verify IO thread is responding with ping/pong messaging. 419 io_watcher_->WaitForCheckResponse( 420 kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL); 421 EXPECT_GT(io_watcher_->ping_sent_, static_cast<uint64>(0)); 422 EXPECT_GT(io_watcher_->pong_received_, static_cast<uint64>(0)); 423 EXPECT_GE(io_watcher_->ping_sequence_number_, static_cast<uint64>(0)); 424 EXPECT_GT(io_watcher_->success_response_, static_cast<uint64>(0)); 425 EXPECT_EQ(io_watcher_->failed_response_, static_cast<uint64>(0)); 426 427 // DeActivate thread watching for shutdown. 428 WatchDogThread::PostTask( 429 FROM_HERE, 430 NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching)); 431 432 WatchDogThread::PostTask( 433 FROM_HERE, 434 NewRunnableMethod( 435 webkit_watcher_, &ThreadWatcher::DeActivateThreadWatching)); 436} 437 438// Test watching of multiple threads with one of the threads not responding. 439TEST_F(ThreadWatcherTest, MultipleThreadsNotResponding) { 440 // Simulate hanging of watched thread by making the watched thread wait for a 441 // very long time by posting a task on watched thread that keeps it busy. 442 BrowserThread::PostTask( 443 io_thread_id, 444 FROM_HERE, 445 NewRunnableMethod( 446 io_watcher_, 447 &CustomThreadWatcher::VeryLongMethod, 448 kUnresponsiveTime * 10)); 449 450 // Activate watching of WEBKIT thread. 451 WatchDogThread::PostTask( 452 FROM_HERE, 453 NewRunnableMethod( 454 webkit_watcher_, &ThreadWatcher::ActivateThreadWatching)); 455 456 // Activate watching of IO thread. 457 WatchDogThread::PostTask( 458 FROM_HERE, 459 NewRunnableMethod(io_watcher_, &ThreadWatcher::ActivateThreadWatching)); 460 461 // Verify WEBKIT thread is responding with ping/pong messaging. 462 webkit_watcher_->WaitForCheckResponse( 463 kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL); 464 EXPECT_GT(webkit_watcher_->success_response_, static_cast<uint64>(0)); 465 EXPECT_EQ(webkit_watcher_->failed_response_, static_cast<uint64>(0)); 466 467 // Verify IO thread is not responding for ping messages. 468 io_watcher_->WaitForCheckResponse( 469 kUnresponsiveTime + TimeDelta::FromMinutes(1), FAILED); 470 EXPECT_EQ(io_watcher_->success_response_, static_cast<uint64>(0)); 471 EXPECT_GT(io_watcher_->failed_response_, static_cast<uint64>(0)); 472 473 // DeActivate thread watching for shutdown. 474 WatchDogThread::PostTask( 475 FROM_HERE, 476 NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching)); 477 WatchDogThread::PostTask( 478 FROM_HERE, 479 NewRunnableMethod( 480 webkit_watcher_, &ThreadWatcher::DeActivateThreadWatching)); 481 482 // Wait for the io_watcher_'s VeryLongMethod to finish. 483 io_watcher_->WaitForWaitStateChange(kUnresponsiveTime * 10, ALL_DONE); 484} 485