OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <math.h> |
| 6 |
5 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
6 #include "base/logging.h" | 8 #include "base/logging.h" |
7 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
8 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
9 #include "base/message_loop_proxy.h" | 11 #include "base/message_loop_proxy.h" |
| 12 #include "base/string_tokenizer.h" |
10 #include "base/synchronization/condition_variable.h" | 13 #include "base/synchronization/condition_variable.h" |
11 #include "base/synchronization/lock.h" | 14 #include "base/synchronization/lock.h" |
12 #include "base/threading/platform_thread.h" | 15 #include "base/threading/platform_thread.h" |
13 #include "base/time.h" | 16 #include "base/time.h" |
14 #include "build/build_config.h" | 17 #include "build/build_config.h" |
15 #include "chrome/browser/metrics/thread_watcher.h" | 18 #include "chrome/browser/metrics/thread_watcher.h" |
| 19 #include "chrome/common/chrome_switches.h" |
16 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
17 #include "testing/platform_test.h" | 21 #include "testing/platform_test.h" |
18 | 22 |
19 using base::TimeDelta; | 23 using base::TimeDelta; |
20 using base::TimeTicks; | 24 using base::TimeTicks; |
21 | 25 |
22 enum State { | 26 enum State { |
23 INITIALIZED, // Created ThreadWatch object. | 27 INITIALIZED, // Created ThreadWatch object. |
24 ACTIVATED, // Thread watching activated. | 28 ACTIVATED, // Thread watching activated. |
25 SENT_PING, // Sent ping message to watched thread. | 29 SENT_PING, // Sent ping message to watched thread. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 uint64 pong_received_; | 61 uint64 pong_received_; |
58 uint64 success_response_; | 62 uint64 success_response_; |
59 uint64 failed_response_; | 63 uint64 failed_response_; |
60 base::TimeTicks saved_ping_time_; | 64 base::TimeTicks saved_ping_time_; |
61 uint64 saved_ping_sequence_number_; | 65 uint64 saved_ping_sequence_number_; |
62 | 66 |
63 CustomThreadWatcher(const BrowserThread::ID thread_id, | 67 CustomThreadWatcher(const BrowserThread::ID thread_id, |
64 const std::string thread_name, | 68 const std::string thread_name, |
65 const TimeDelta& sleep_time, | 69 const TimeDelta& sleep_time, |
66 const TimeDelta& unresponsive_time) | 70 const TimeDelta& unresponsive_time) |
67 : ThreadWatcher(thread_id, thread_name, sleep_time, unresponsive_time), | 71 : ThreadWatcher(thread_id, thread_name, sleep_time, unresponsive_time, |
| 72 ThreadWatcherList::kUnresponsiveCount, true, |
| 73 ThreadWatcherList::kLiveThreadsThreshold), |
68 state_changed_(&custom_lock_), | 74 state_changed_(&custom_lock_), |
69 thread_watcher_state_(INITIALIZED), | 75 thread_watcher_state_(INITIALIZED), |
70 wait_state_(UNINITIALIZED), | 76 wait_state_(UNINITIALIZED), |
71 check_response_state_(UNKNOWN), | 77 check_response_state_(UNKNOWN), |
72 ping_sent_(0), | 78 ping_sent_(0), |
73 pong_received_(0), | 79 pong_received_(0), |
74 success_response_(0), | 80 success_response_(0), |
75 failed_response_(0), | 81 failed_response_(0), |
76 saved_ping_time_(base::TimeTicks::Now()), | 82 saved_ping_time_(base::TimeTicks::Now()), |
77 saved_ping_sequence_number_(0) { | 83 saved_ping_sequence_number_(0) { |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 DISABLE_RUNNABLE_METHOD_REFCOUNT(CustomThreadWatcher); | 232 DISABLE_RUNNABLE_METHOD_REFCOUNT(CustomThreadWatcher); |
227 | 233 |
228 class ThreadWatcherTest : public ::testing::Test { | 234 class ThreadWatcherTest : public ::testing::Test { |
229 public: | 235 public: |
230 static const TimeDelta kSleepTime; | 236 static const TimeDelta kSleepTime; |
231 static const TimeDelta kUnresponsiveTime; | 237 static const TimeDelta kUnresponsiveTime; |
232 static const BrowserThread::ID io_thread_id; | 238 static const BrowserThread::ID io_thread_id; |
233 static const std::string io_thread_name; | 239 static const std::string io_thread_name; |
234 static const BrowserThread::ID webkit_thread_id; | 240 static const BrowserThread::ID webkit_thread_id; |
235 static const std::string webkit_thread_name; | 241 static const std::string webkit_thread_name; |
| 242 static const std::string crash_on_hang_seconds; |
| 243 static const std::string crash_on_hang_threads; |
| 244 static const std::string crash_on_live; |
236 CustomThreadWatcher* io_watcher_; | 245 CustomThreadWatcher* io_watcher_; |
237 CustomThreadWatcher* webkit_watcher_; | 246 CustomThreadWatcher* webkit_watcher_; |
| 247 ThreadWatcherList* thread_watcher_list_; |
238 | 248 |
239 ThreadWatcherTest() { | 249 ThreadWatcherTest() |
| 250 : setup_complete_(&lock_), |
| 251 initialized_(false) { |
240 webkit_thread_.reset(new BrowserThread(BrowserThread::WEBKIT)); | 252 webkit_thread_.reset(new BrowserThread(BrowserThread::WEBKIT)); |
241 io_thread_.reset(new BrowserThread(BrowserThread::IO)); | 253 io_thread_.reset(new BrowserThread(BrowserThread::IO)); |
242 watchdog_thread_.reset(new WatchDogThread()); | 254 watchdog_thread_.reset(new WatchDogThread()); |
243 webkit_thread_->Start(); | 255 webkit_thread_->Start(); |
244 io_thread_->Start(); | 256 io_thread_->Start(); |
245 watchdog_thread_->Start(); | 257 watchdog_thread_->Start(); |
246 | 258 |
| 259 WatchDogThread::PostTask( |
| 260 FROM_HERE, |
| 261 NewRunnableMethod(this, &ThreadWatcherTest::SetUpObjects)); |
| 262 |
| 263 WaitForSetUp(TimeDelta::FromMinutes(1)); |
| 264 } |
| 265 |
| 266 void SetUpObjects() { |
| 267 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
| 268 |
247 // Setup the registry for thread watchers. | 269 // Setup the registry for thread watchers. |
248 thread_watcher_list_ = new ThreadWatcherList(); | 270 thread_watcher_list_ = new ThreadWatcherList(); |
249 | 271 |
250 // Create thread watcher object for the IO thread. | 272 // Create thread watcher object for the IO thread. |
251 io_watcher_ = new CustomThreadWatcher(io_thread_id, io_thread_name, | 273 io_watcher_ = new CustomThreadWatcher(io_thread_id, io_thread_name, |
252 kSleepTime, kUnresponsiveTime); | 274 kSleepTime, kUnresponsiveTime); |
| 275 EXPECT_EQ(io_watcher_, thread_watcher_list_->Find(io_thread_id)); |
253 | 276 |
254 // Create thread watcher object for the WEBKIT thread. | 277 // Create thread watcher object for the WEBKIT thread. |
255 webkit_watcher_ = new CustomThreadWatcher( | 278 webkit_watcher_ = new CustomThreadWatcher( |
256 webkit_thread_id, webkit_thread_name, kSleepTime, kUnresponsiveTime); | 279 webkit_thread_id, webkit_thread_name, kSleepTime, kUnresponsiveTime); |
| 280 EXPECT_EQ(webkit_watcher_, thread_watcher_list_->Find(webkit_thread_id)); |
| 281 |
| 282 { |
| 283 base::AutoLock lock(lock_); |
| 284 initialized_ = true; |
| 285 } |
| 286 setup_complete_.Signal(); |
| 287 } |
| 288 |
| 289 void WaitForSetUp(TimeDelta wait_time) { |
| 290 DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread()); |
| 291 TimeTicks end_time = TimeTicks::Now() + wait_time; |
| 292 { |
| 293 base::AutoLock auto_lock(lock_); |
| 294 while (!initialized_ && TimeTicks::Now() < end_time) |
| 295 setup_complete_.TimedWait(end_time - TimeTicks::Now()); |
| 296 } |
257 } | 297 } |
258 | 298 |
259 ~ThreadWatcherTest() { | 299 ~ThreadWatcherTest() { |
260 ThreadWatcherList::StopWatchingAll(); | 300 ThreadWatcherList::DeleteAll(); |
261 io_watcher_ = NULL; | 301 io_watcher_ = NULL; |
262 webkit_watcher_ = NULL; | 302 webkit_watcher_ = NULL; |
263 io_thread_.reset(); | 303 io_thread_.reset(); |
264 webkit_thread_.reset(); | 304 webkit_thread_.reset(); |
265 watchdog_thread_.reset(); | 305 watchdog_thread_.reset(); |
266 delete thread_watcher_list_; | 306 thread_watcher_list_ = NULL; |
267 } | 307 } |
268 | 308 |
269 private: | 309 private: |
| 310 base::Lock lock_; |
| 311 base::ConditionVariable setup_complete_; |
| 312 bool initialized_; |
270 scoped_ptr<BrowserThread> webkit_thread_; | 313 scoped_ptr<BrowserThread> webkit_thread_; |
271 scoped_ptr<BrowserThread> io_thread_; | 314 scoped_ptr<BrowserThread> io_thread_; |
272 scoped_ptr<WatchDogThread> watchdog_thread_; | 315 scoped_ptr<WatchDogThread> watchdog_thread_; |
273 ThreadWatcherList* thread_watcher_list_; | |
274 }; | 316 }; |
275 | 317 |
| 318 // DISABLE_RUNNABLE_METHOD_REFCOUNT is a convenience macro for disabling |
| 319 // refcounting of ThreadWatcherTest classes. |
| 320 DISABLE_RUNNABLE_METHOD_REFCOUNT(ThreadWatcherTest); |
| 321 |
276 // Define static constants. | 322 // Define static constants. |
277 const TimeDelta ThreadWatcherTest::kSleepTime = | 323 const TimeDelta ThreadWatcherTest::kSleepTime = |
278 TimeDelta::FromMilliseconds(50); | 324 TimeDelta::FromMilliseconds(50); |
279 const TimeDelta ThreadWatcherTest::kUnresponsiveTime = | 325 const TimeDelta ThreadWatcherTest::kUnresponsiveTime = |
280 TimeDelta::FromMilliseconds(500); | 326 TimeDelta::FromMilliseconds(500); |
281 const BrowserThread::ID ThreadWatcherTest::io_thread_id = BrowserThread::IO; | 327 const BrowserThread::ID ThreadWatcherTest::io_thread_id = BrowserThread::IO; |
282 const std::string ThreadWatcherTest::io_thread_name = "IO"; | 328 const std::string ThreadWatcherTest::io_thread_name = "IO"; |
283 const BrowserThread::ID ThreadWatcherTest::webkit_thread_id = | 329 const BrowserThread::ID ThreadWatcherTest::webkit_thread_id = |
284 BrowserThread::WEBKIT; | 330 BrowserThread::WEBKIT; |
285 const std::string ThreadWatcherTest::webkit_thread_name = "WEBKIT"; | 331 const std::string ThreadWatcherTest::webkit_thread_name = "WEBKIT"; |
| 332 const std::string ThreadWatcherTest::crash_on_hang_seconds = "24"; |
| 333 const std::string ThreadWatcherTest::crash_on_hang_threads = "IO,UI"; |
| 334 const std::string ThreadWatcherTest::crash_on_live = "3"; |
| 335 |
| 336 TEST_F(ThreadWatcherTest, CommandLineArgs) { |
| 337 // Setup command_line arguments. |
| 338 CommandLine command_line(CommandLine::NO_PROGRAM); |
| 339 command_line.AppendSwitchASCII(switches::kCrashOnHangSeconds, |
| 340 crash_on_hang_seconds); |
| 341 command_line.AppendSwitchASCII(switches::kCrashOnHangThreads, |
| 342 crash_on_hang_threads); |
| 343 command_line.AppendSwitchASCII(switches::kCrashOnLive, |
| 344 crash_on_live); |
| 345 |
| 346 // Parse command_line arguments. |
| 347 uint32 unresponsive_threshold; |
| 348 std::set<std::string> crash_on_hang_thread_names; |
| 349 uint32 live_threads_threshold; |
| 350 ThreadWatcherList::ParseCommandLine(command_line, |
| 351 &unresponsive_threshold, |
| 352 &crash_on_hang_thread_names, |
| 353 &live_threads_threshold); |
| 354 |
| 355 // Verify the data. |
| 356 uint32 crash_on_unresponsive_seconds = |
| 357 ThreadWatcherList::kUnresponsiveSeconds * unresponsive_threshold; |
| 358 EXPECT_EQ(static_cast<int>(crash_on_unresponsive_seconds), |
| 359 atoi(crash_on_hang_seconds.c_str())); |
| 360 |
| 361 // Check ThreadWatcherTestList has the right crash_on_hang_threads. |
| 362 StringTokenizer tokens(crash_on_hang_threads, ","); |
| 363 while (tokens.GetNext()) { |
| 364 std::string thread_name = tokens.token(); |
| 365 std::set<std::string>::iterator it = |
| 366 crash_on_hang_thread_names.find(thread_name); |
| 367 bool crash_on_hang = (it != crash_on_hang_thread_names.end()); |
| 368 EXPECT_TRUE(crash_on_hang); |
| 369 } |
| 370 |
| 371 EXPECT_EQ(static_cast<int>(live_threads_threshold), |
| 372 atoi(crash_on_live.c_str())); |
| 373 } |
286 | 374 |
287 // Test registration. When thread_watcher_list_ goes out of scope after | 375 // Test registration. When thread_watcher_list_ goes out of scope after |
288 // TearDown, all thread watcher objects will be deleted. | 376 // TearDown, all thread watcher objects will be deleted. |
289 TEST_F(ThreadWatcherTest, Registration) { | 377 TEST_F(ThreadWatcherTest, Registration) { |
290 EXPECT_EQ(io_watcher_, ThreadWatcherList::Find(io_thread_id)); | |
291 EXPECT_EQ(webkit_watcher_, ThreadWatcherList::Find(webkit_thread_id)); | |
292 | |
293 // Check ThreadWatcher object has all correct parameters. | 378 // Check ThreadWatcher object has all correct parameters. |
294 EXPECT_EQ(io_thread_id, io_watcher_->thread_id()); | 379 EXPECT_EQ(io_thread_id, io_watcher_->thread_id()); |
295 EXPECT_EQ(io_thread_name, io_watcher_->thread_name()); | 380 EXPECT_EQ(io_thread_name, io_watcher_->thread_name()); |
296 EXPECT_EQ(kSleepTime, io_watcher_->sleep_time()); | 381 EXPECT_EQ(kSleepTime, io_watcher_->sleep_time()); |
297 EXPECT_EQ(kUnresponsiveTime, io_watcher_->unresponsive_time()); | 382 EXPECT_EQ(kUnresponsiveTime, io_watcher_->unresponsive_time()); |
298 EXPECT_FALSE(io_watcher_->active()); | 383 EXPECT_FALSE(io_watcher_->active()); |
299 | 384 |
300 // Check ThreadWatcher object of watched WEBKIT thread has correct data. | 385 // Check ThreadWatcher object of watched WEBKIT thread has correct data. |
301 EXPECT_EQ(webkit_thread_id, webkit_watcher_->thread_id()); | 386 EXPECT_EQ(webkit_thread_id, webkit_watcher_->thread_id()); |
302 EXPECT_EQ(webkit_thread_name, webkit_watcher_->thread_name()); | 387 EXPECT_EQ(webkit_thread_name, webkit_watcher_->thread_name()); |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 FROM_HERE, | 541 FROM_HERE, |
457 NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching)); | 542 NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching)); |
458 WatchDogThread::PostTask( | 543 WatchDogThread::PostTask( |
459 FROM_HERE, | 544 FROM_HERE, |
460 NewRunnableMethod( | 545 NewRunnableMethod( |
461 webkit_watcher_, &ThreadWatcher::DeActivateThreadWatching)); | 546 webkit_watcher_, &ThreadWatcher::DeActivateThreadWatching)); |
462 | 547 |
463 // Wait for the io_watcher_'s VeryLongMethod to finish. | 548 // Wait for the io_watcher_'s VeryLongMethod to finish. |
464 io_watcher_->WaitForWaitStateChange(kUnresponsiveTime * 10, ALL_DONE); | 549 io_watcher_->WaitForWaitStateChange(kUnresponsiveTime * 10, ALL_DONE); |
465 } | 550 } |
OLD | NEW |