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

Side by Side Diff: chrome/browser/metrics/thread_watcher.cc

Issue 7134007: Added command line switches "crash-on-hang-threads" and "crash-on-hang-seconds" (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 6 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 | Annotate | Revision Log
OLDNEW
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> // ceil
6
7 #include "base/string_tokenizer.h"
5 #include "base/threading/thread_restrictions.h" 8 #include "base/threading/thread_restrictions.h"
6 #include "build/build_config.h" 9 #include "build/build_config.h"
7 #include "chrome/browser/metrics/metrics_service.h" 10 #include "chrome/browser/metrics/metrics_service.h"
8 #include "chrome/browser/metrics/thread_watcher.h" 11 #include "chrome/browser/metrics/thread_watcher.h"
12 #include "chrome/common/chrome_switches.h"
9 #include "content/common/notification_service.h" 13 #include "content/common/notification_service.h"
10 14
11 #if defined(OS_WIN) 15 #if defined(OS_WIN)
12 #include <Objbase.h> 16 #include <Objbase.h>
13 #endif 17 #endif
14 18
15 // static 19 // static
16 const int ThreadWatcher::kPingCount = 6; 20 const int ThreadWatcher::kPingCount = 6;
17 21
18 // static
19 const int ThreadWatcher::kUnresponsiveCount = 6;
20
21 // ThreadWatcher methods and members. 22 // ThreadWatcher methods and members.
22 ThreadWatcher::ThreadWatcher(const BrowserThread::ID& thread_id, 23 ThreadWatcher::ThreadWatcher(const BrowserThread::ID& thread_id,
23 const std::string& thread_name, 24 const std::string& thread_name,
24 const base::TimeDelta& sleep_time, 25 const base::TimeDelta& sleep_time,
25 const base::TimeDelta& unresponsive_time) 26 const base::TimeDelta& unresponsive_time,
27 uint32 unresponsive_threshold,
28 bool crash_on_hang,
29 uint32 live_threads_threshold)
26 : thread_id_(thread_id), 30 : thread_id_(thread_id),
27 thread_name_(thread_name), 31 thread_name_(thread_name),
28 sleep_time_(sleep_time), 32 sleep_time_(sleep_time),
29 unresponsive_time_(unresponsive_time), 33 unresponsive_time_(unresponsive_time),
30 ping_time_(base::TimeTicks::Now()), 34 ping_time_(base::TimeTicks::Now()),
31 pong_time_(ping_time_), 35 pong_time_(ping_time_),
32 ping_sequence_number_(0), 36 ping_sequence_number_(0),
33 active_(false), 37 active_(false),
34 ping_count_(kPingCount), 38 ping_count_(kPingCount),
35 response_time_histogram_(NULL), 39 response_time_histogram_(NULL),
36 unresponsive_time_histogram_(NULL), 40 unresponsive_time_histogram_(NULL),
37 unresponsive_count_(0), 41 unresponsive_count_(0),
38 hung_processing_complete_(false), 42 hung_processing_complete_(false),
43 unresponsive_threshold_(unresponsive_threshold),
44 crash_on_hang_(crash_on_hang),
45 live_threads_threshold_(live_threads_threshold),
39 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 46 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
47 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
40 Initialize(); 48 Initialize();
41 } 49 }
42 50
43 ThreadWatcher::~ThreadWatcher() {} 51 ThreadWatcher::~ThreadWatcher() {}
44 52
45 // static 53 // static
46 void ThreadWatcher::StartWatching(const BrowserThread::ID& thread_id, 54 void ThreadWatcher::StartWatching(const BrowserThread::ID& thread_id,
47 const std::string& thread_name, 55 const std::string& thread_name,
48 const base::TimeDelta& sleep_time, 56 const base::TimeDelta& sleep_time,
49 const base::TimeDelta& unresponsive_time) { 57 const base::TimeDelta& unresponsive_time,
58 uint32 unresponsive_threshold,
59 bool crash_on_hang,
60 uint32 live_threads_threshold) {
50 DCHECK_GE(sleep_time.InMilliseconds(), 0); 61 DCHECK_GE(sleep_time.InMilliseconds(), 0);
51 DCHECK_GE(unresponsive_time.InMilliseconds(), sleep_time.InMilliseconds()); 62 DCHECK_GE(unresponsive_time.InMilliseconds(), sleep_time.InMilliseconds());
52 63
53 // If we are not on WatchDogThread, then post a task to call StartWatching on 64 // If we are not on WatchDogThread, then post a task to call StartWatching on
54 // WatchDogThread. 65 // WatchDogThread.
55 if (!WatchDogThread::CurrentlyOnWatchDogThread()) { 66 if (!WatchDogThread::CurrentlyOnWatchDogThread()) {
56 WatchDogThread::PostTask( 67 WatchDogThread::PostTask(
57 FROM_HERE, 68 FROM_HERE,
58 NewRunnableFunction( 69 NewRunnableFunction(&ThreadWatcher::StartWatching,
59 &ThreadWatcher::StartWatching, 70 thread_id,
60 thread_id, thread_name, sleep_time, unresponsive_time)); 71 thread_name,
72 sleep_time,
73 unresponsive_time,
74 unresponsive_threshold,
75 crash_on_hang,
76 live_threads_threshold));
61 return; 77 return;
62 } 78 }
63 79
64 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); 80 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
65 81
66 // Create a new thread watcher object for the given thread and activate it. 82 // Create a new thread watcher object for the given thread and activate it.
67 ThreadWatcher* watcher = 83 ThreadWatcher* watcher = new ThreadWatcher(thread_id,
68 new ThreadWatcher(thread_id, thread_name, sleep_time, unresponsive_time); 84 thread_name,
85 sleep_time,
86 unresponsive_time,
87 unresponsive_threshold,
88 crash_on_hang,
89 live_threads_threshold);
69 DCHECK(watcher); 90 DCHECK(watcher);
70 // If we couldn't register the thread watcher object, we are shutting down, 91 // If we couldn't register the thread watcher object, we are shutting down,
71 // then don't activate thread watching. 92 // then don't activate thread watching.
72 if (!ThreadWatcherList::IsRegistered(thread_id)) 93 if (!ThreadWatcherList::IsRegistered(thread_id))
73 return; 94 return;
74 watcher->ActivateThreadWatching(); 95 watcher->ActivateThreadWatching();
75 } 96 }
76 97
77 void ThreadWatcher::ActivateThreadWatching() { 98 void ThreadWatcher::ActivateThreadWatching() {
78 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); 99 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 // Post a task to check the responsiveness of watched thread. 210 // Post a task to check the responsiveness of watched thread.
190 MessageLoop::current()->PostDelayedTask( 211 MessageLoop::current()->PostDelayedTask(
191 FROM_HERE, 212 FROM_HERE,
192 method_factory_.NewRunnableMethod( 213 method_factory_.NewRunnableMethod(
193 &ThreadWatcher::OnCheckResponsiveness, ping_sequence_number_), 214 &ThreadWatcher::OnCheckResponsiveness, ping_sequence_number_),
194 unresponsive_time_.InMilliseconds()); 215 unresponsive_time_.InMilliseconds());
195 return false; 216 return false;
196 } 217 }
197 218
198 void ThreadWatcher::Initialize() { 219 void ThreadWatcher::Initialize() {
220 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
199 ThreadWatcherList::Register(this); 221 ThreadWatcherList::Register(this);
200 222
201 const std::string response_time_histogram_name = 223 const std::string response_time_histogram_name =
202 "ThreadWatcher.ResponseTime." + thread_name_; 224 "ThreadWatcher.ResponseTime." + thread_name_;
203 response_time_histogram_ = base::Histogram::FactoryTimeGet( 225 response_time_histogram_ = base::Histogram::FactoryTimeGet(
204 response_time_histogram_name, 226 response_time_histogram_name,
205 base::TimeDelta::FromMilliseconds(1), 227 base::TimeDelta::FromMilliseconds(1),
206 base::TimeDelta::FromSeconds(100), 50, 228 base::TimeDelta::FromSeconds(100), 50,
207 base::Histogram::kUmaTargetedHistogramFlag); 229 base::Histogram::kUmaTargetedHistogramFlag);
208 230
(...skipping 28 matching lines...) Expand all
237 259
238 void ThreadWatcher::ResetHangCounters() { 260 void ThreadWatcher::ResetHangCounters() {
239 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); 261 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
240 unresponsive_count_ = 0; 262 unresponsive_count_ = 0;
241 hung_processing_complete_ = false; 263 hung_processing_complete_ = false;
242 } 264 }
243 265
244 void ThreadWatcher::GotNoResponse() { 266 void ThreadWatcher::GotNoResponse() {
245 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); 267 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
246 268
247 // Record how other threads are responding when we don't get a response for 269 ++unresponsive_count_;
248 // ping message atleast kUnresponsiveCount times. 270 if (!IsVeryUnresponsive())
249 if (++unresponsive_count_ < kUnresponsiveCount)
250 return; 271 return;
251 272
252 // Record total unresponsive_time since last pong message. 273 // Record total unresponsive_time since last pong message.
253 base::TimeDelta unresponse_time = base::TimeTicks::Now() - pong_time_; 274 base::TimeDelta unresponse_time = base::TimeTicks::Now() - pong_time_;
254 unresponsive_time_histogram_->AddTime(unresponse_time); 275 unresponsive_time_histogram_->AddTime(unresponse_time);
255 276
256 // We have already collected stats for the non-responding watched thread. 277 // We have already collected stats for the non-responding watched thread.
257 if (hung_processing_complete_) 278 if (hung_processing_complete_)
258 return; 279 return;
259 280
260 int no_of_responding_threads = 0; 281 // Record how other threads are responding.
261 int no_of_unresponding_threads = 0; 282 uint32 responding_thread_count = 0;
262 ThreadWatcherList::GetStatusOfThreads(&no_of_responding_threads, 283 uint32 unresponding_thread_count = 0;
263 &no_of_unresponding_threads); 284 ThreadWatcherList::GetStatusOfThreads(&responding_thread_count,
285 &unresponding_thread_count);
264 286
265 // Record how many watched threads are responding. 287 // Record how many watched threads are responding.
266 responsive_count_histogram_->Add(no_of_responding_threads); 288 responsive_count_histogram_->Add(responding_thread_count);
267 289
268 // Record how many watched threads are not responding. 290 // Record how many watched threads are not responding.
269 unresponsive_count_histogram_->Add(no_of_unresponding_threads); 291 unresponsive_count_histogram_->Add(unresponding_thread_count);
270 292
271 // Crash the browser if IO thread hasn't responded atleast kUnresponsiveCount 293 // Crash the browser if the watched thread is to be crashed on hang and if the
272 // times and if the number of other threads is equal to 1. We picked 1 to 294 // number of other threads responding is equal to live_threads_threshold_.
273 // reduce the number of crashes and to get some sample data. 295 if (crash_on_hang_ && responding_thread_count == live_threads_threshold_) {
274 if (thread_id_ == BrowserThread::IO && no_of_responding_threads == 1) {
275 int* crash = NULL; 296 int* crash = NULL;
276 CHECK(crash++); 297 CHECK(crash + thread_id_);
277 } 298 }
278 299
279 hung_processing_complete_ = true; 300 hung_processing_complete_ = true;
280 } 301 }
281 302
303 bool ThreadWatcher::IsVeryUnresponsive() {
304 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
305 return unresponsive_count_ >= unresponsive_threshold_;
306 }
307
282 // ThreadWatcherList methods and members. 308 // ThreadWatcherList methods and members.
283 // 309 //
284 // static 310 // static
285 ThreadWatcherList* ThreadWatcherList::global_ = NULL; 311 ThreadWatcherList* ThreadWatcherList::g_thread_watcher_list_ = NULL;
286 // static 312 // static
287 const int ThreadWatcherList::kSleepSeconds = 1; 313 const int ThreadWatcherList::kSleepSeconds = 1;
288 // static 314 // static
289 const int ThreadWatcherList::kUnresponsiveSeconds = 2; 315 const int ThreadWatcherList::kUnresponsiveSeconds = 2;
290 316 // static
291 ThreadWatcherList::ThreadWatcherList() 317 const int ThreadWatcherList::kUnresponsiveCount = 6;
292 : last_wakeup_time_(base::TimeTicks::Now()) { 318 // static
293 // Assert we are not running on WATCHDOG thread. Would be ideal to assert we 319 const int ThreadWatcherList::kLiveThreadsThreshold = 1;
294 // are on UI thread, but Unit tests are not running on UI thread. 320
295 DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread()); 321 // static
296 CHECK(!global_); 322 void ThreadWatcherList::StartWatchingAll(const CommandLine& command_line) {
297 global_ = this; 323 ThreadWatcherObserver::SetupNotifications(
298 // Register Notifications observer. 324 base::TimeDelta::FromSeconds(kSleepSeconds * ThreadWatcher::kPingCount));
299 MetricsService::SetUpNotifications(&registrar_, this); 325
326 uint32 unresponsive_threshold;
327 std::set<std::string> crash_on_hang_thread_names;
328 uint32 live_threads_threshold;
329 ParseCommandLine(command_line,
330 &unresponsive_threshold,
331 &crash_on_hang_thread_names,
332 &live_threads_threshold);
333
334 WatchDogThread::PostDelayedTask(
335 FROM_HERE,
336 NewRunnableFunction(&ThreadWatcherList::InitializeAndStartWatching,
337 unresponsive_threshold,
338 crash_on_hang_thread_names,
339 live_threads_threshold),
340 base::TimeDelta::FromSeconds(120).InMilliseconds());
341 }
342
343 // static
344 void ThreadWatcherList::StopWatchingAll() {
345 ThreadWatcherObserver::RemoveNotifications();
346 DeleteAll();
347 }
348
349 // static
350 void ThreadWatcherList::Register(ThreadWatcher* watcher) {
351 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
352 if (!g_thread_watcher_list_)
353 return;
354 DCHECK(!g_thread_watcher_list_->Find(watcher->thread_id()));
355 g_thread_watcher_list_->registered_[watcher->thread_id()] = watcher;
356 }
357
358 // static
359 bool ThreadWatcherList::IsRegistered(const BrowserThread::ID thread_id) {
360 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
361 return NULL != ThreadWatcherList::Find(thread_id);
362 }
363
364 // static
365 void ThreadWatcherList::GetStatusOfThreads(uint32* responding_thread_count,
366 uint32* unresponding_thread_count) {
367 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
368 *responding_thread_count = 0;
369 *unresponding_thread_count = 0;
370 if (!g_thread_watcher_list_)
371 return;
372
373 for (RegistrationList::iterator it =
374 g_thread_watcher_list_->registered_.begin();
375 g_thread_watcher_list_->registered_.end() != it;
376 ++it) {
377 if (it->second->IsVeryUnresponsive())
378 ++(*unresponding_thread_count);
379 else
380 ++(*responding_thread_count);
381 }
382 }
383
384 // static
385 void ThreadWatcherList::WakeUpAll() {
386 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
387 if (!g_thread_watcher_list_)
388 return;
389
390 for (RegistrationList::iterator it =
391 g_thread_watcher_list_->registered_.begin();
392 g_thread_watcher_list_->registered_.end() != it;
393 ++it)
394 it->second->WakeUp();
395 }
396
397 ThreadWatcherList::ThreadWatcherList() {
398 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
399 CHECK(!g_thread_watcher_list_);
400 g_thread_watcher_list_ = this;
300 } 401 }
301 402
302 ThreadWatcherList::~ThreadWatcherList() { 403 ThreadWatcherList::~ThreadWatcherList() {
303 base::AutoLock auto_lock(lock_); 404 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
304 DCHECK(this == global_); 405 DCHECK(this == g_thread_watcher_list_);
305 global_ = NULL; 406 g_thread_watcher_list_ = NULL;
306 } 407 }
307 408
308 // static 409 // static
309 void ThreadWatcherList::Register(ThreadWatcher* watcher) { 410 void ThreadWatcherList::ParseCommandLine(
310 if (!global_) 411 const CommandLine& command_line,
311 return; 412 uint32* unresponsive_threshold,
312 base::AutoLock auto_lock(global_->lock_); 413 std::set<std::string>* crash_on_hang_thread_names,
313 DCHECK(!global_->PreLockedFind(watcher->thread_id())); 414 uint32* live_threads_threshold) {
314 global_->registered_[watcher->thread_id()] = watcher; 415 // Determine |unresponsive_threshold| based on switches::kCrashOnHangSeconds.
315 } 416 *unresponsive_threshold = kUnresponsiveCount;
316 417 std::string crash_on_hang_seconds =
317 // static 418 command_line.GetSwitchValueASCII(switches::kCrashOnHangSeconds);
318 bool ThreadWatcherList::IsRegistered(const BrowserThread::ID thread_id) { 419 if (!crash_on_hang_seconds.empty()) {
319 return NULL != ThreadWatcherList::Find(thread_id); 420 int crash_seconds = atoi(crash_on_hang_seconds.c_str());
320 } 421 if (crash_seconds > 0) {
321 422 *unresponsive_threshold = static_cast<uint32>(
322 // static 423 ceil(static_cast<float>(crash_seconds) / kUnresponsiveSeconds));
323 void ThreadWatcherList::StartWatchingAll() { 424 }
324 if (!WatchDogThread::CurrentlyOnWatchDogThread()) { 425 }
325 WatchDogThread::PostDelayedTask( 426
326 FROM_HERE, 427 // Default to crashing the browser if UI or IO threads are not responsive.
327 NewRunnableFunction(&ThreadWatcherList::StartWatchingAll), 428 std::string crash_on_hang_threads = "UI,IO";
328 base::TimeDelta::FromSeconds(120).InMilliseconds()); 429 if (command_line.HasSwitch(switches::kCrashOnHangThreads)) {
329 return; 430 crash_on_hang_threads =
330 } 431 command_line.GetSwitchValueASCII(switches::kCrashOnHangThreads);
331 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); 432 }
433 StringTokenizer tokens(crash_on_hang_threads, ",");
434 while (tokens.GetNext())
435 crash_on_hang_thread_names->insert(tokens.token());
436
437 // Determine |live_threads_threshold| based on switches::kCrashOnLive.
438 *live_threads_threshold = kLiveThreadsThreshold;
439 if (command_line.HasSwitch(switches::kCrashOnLive)) {
440 std::string live_threads =
441 command_line.GetSwitchValueASCII(switches::kCrashOnLive);
442 *live_threads_threshold = static_cast<uint32>(atoi(live_threads.c_str()));
443 }
444 }
445
446 // static
447 void ThreadWatcherList::InitializeAndStartWatching(
448 uint32 unresponsive_threshold,
449 const std::set<std::string>& crash_on_hang_thread_names,
450 uint32 live_threads_threshold) {
451 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
452
453 ThreadWatcherList* thread_watcher_list = new ThreadWatcherList();
454 CHECK(thread_watcher_list);
455
332 const base::TimeDelta kSleepTime = 456 const base::TimeDelta kSleepTime =
333 base::TimeDelta::FromSeconds(kSleepSeconds); 457 base::TimeDelta::FromSeconds(kSleepSeconds);
334 const base::TimeDelta kUnresponsiveTime = 458 const base::TimeDelta kUnresponsiveTime =
335 base::TimeDelta::FromSeconds(kUnresponsiveSeconds); 459 base::TimeDelta::FromSeconds(kUnresponsiveSeconds);
336 if (BrowserThread::IsMessageLoopValid(BrowserThread::UI)) { 460
337 ThreadWatcher::StartWatching(BrowserThread::UI, "UI", kSleepTime, 461 StartWatching(BrowserThread::UI, "UI", kSleepTime, kUnresponsiveTime,
338 kUnresponsiveTime); 462 unresponsive_threshold, crash_on_hang_thread_names,
339 } 463 live_threads_threshold);
340 if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { 464 StartWatching(BrowserThread::IO, "IO", kSleepTime, kUnresponsiveTime,
341 ThreadWatcher::StartWatching(BrowserThread::IO, "IO", kSleepTime, 465 unresponsive_threshold, crash_on_hang_thread_names,
342 kUnresponsiveTime); 466 live_threads_threshold);
343 } 467 StartWatching(BrowserThread::DB, "DB", kSleepTime, kUnresponsiveTime,
344 if (BrowserThread::IsMessageLoopValid(BrowserThread::DB)) { 468 unresponsive_threshold, crash_on_hang_thread_names,
345 ThreadWatcher::StartWatching(BrowserThread::DB, "DB", kSleepTime, 469 live_threads_threshold);
346 kUnresponsiveTime); 470 StartWatching(BrowserThread::FILE, "FILE", kSleepTime, kUnresponsiveTime,
347 } 471 unresponsive_threshold, crash_on_hang_thread_names,
348 if (BrowserThread::IsMessageLoopValid(BrowserThread::FILE)) { 472 live_threads_threshold);
349 ThreadWatcher::StartWatching(BrowserThread::FILE, "FILE", kSleepTime, 473 StartWatching(BrowserThread::CACHE, "CACHE", kSleepTime, kUnresponsiveTime,
350 kUnresponsiveTime); 474 unresponsive_threshold, crash_on_hang_thread_names,
351 } 475 live_threads_threshold);
352 if (BrowserThread::IsMessageLoopValid(BrowserThread::CACHE)) { 476 }
353 ThreadWatcher::StartWatching(BrowserThread::CACHE, "CACHE", kSleepTime, 477
354 kUnresponsiveTime); 478 // static
355 } 479 void ThreadWatcherList::StartWatching(
356 } 480 const BrowserThread::ID& thread_id,
357 481 const std::string& thread_name,
358 // static 482 const base::TimeDelta& sleep_time,
359 void ThreadWatcherList::StopWatchingAll() { 483 const base::TimeDelta& unresponsive_time,
360 // Assert we are not running on WATCHDOG thread. Would be ideal to assert we 484 uint32 unresponsive_threshold,
361 // are on UI thread, but Unit tests are not running on UI thread. 485 const std::set<std::string>& crash_on_hang_thread_names,
362 DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread()); 486 uint32 live_threads_threshold) {
363 if (!global_) 487 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
364 return; 488
365 489 if (!BrowserThread::IsMessageLoopValid(thread_id))
366 // Remove all notifications for all watched threads. 490 return;
367 RemoveNotifications(); 491
368 492 std::set<std::string>::const_iterator it =
369 // Delete all thread watcher objects on WatchDogThread. 493 crash_on_hang_thread_names.find(thread_name);
494 bool crash_on_hang = (it != crash_on_hang_thread_names.end());
495
496 ThreadWatcher::StartWatching(thread_id,
497 thread_name,
498 sleep_time,
499 unresponsive_time,
500 unresponsive_threshold,
501 crash_on_hang,
502 live_threads_threshold);
503 }
504
505 // static
506 void ThreadWatcherList::DeleteAll() {
507 if (!WatchDogThread::CurrentlyOnWatchDogThread()) {
508 WatchDogThread::PostTask(
509 FROM_HERE,
510 NewRunnableFunction(&ThreadWatcherList::DeleteAll));
511 return;
512 }
513
514 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
515 if (!g_thread_watcher_list_)
516 return;
517
518 // Delete all thread watcher objects.
519 while (!g_thread_watcher_list_->registered_.empty()) {
520 RegistrationList::iterator it = g_thread_watcher_list_->registered_.begin();
521 delete it->second;
522 g_thread_watcher_list_->registered_.erase(it);
523 }
524
525 delete g_thread_watcher_list_;
526 }
527
528 // static
529 ThreadWatcher* ThreadWatcherList::Find(const BrowserThread::ID& thread_id) {
530 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
531 if (!g_thread_watcher_list_)
532 return NULL;
533 RegistrationList::iterator it =
534 g_thread_watcher_list_->registered_.find(thread_id);
535 if (g_thread_watcher_list_->registered_.end() == it)
536 return NULL;
537 return it->second;
538 }
539
540 // ThreadWatcherObserver methods and members.
541 //
542 // static
543 ThreadWatcherObserver* ThreadWatcherObserver::g_thread_watcher_observer_ = NULL;
544
545 ThreadWatcherObserver::ThreadWatcherObserver(
546 const base::TimeDelta& wakeup_interval)
547 : last_wakeup_time_(base::TimeTicks::Now()),
548 wakeup_interval_(wakeup_interval) {
549 CHECK(!g_thread_watcher_observer_);
550 g_thread_watcher_observer_ = this;
551 }
552
553 ThreadWatcherObserver::~ThreadWatcherObserver() {
554 DCHECK(this == g_thread_watcher_observer_);
555 g_thread_watcher_observer_ = NULL;
556 }
557
558 // static
559 void ThreadWatcherObserver::SetupNotifications(
560 const base::TimeDelta& wakeup_interval) {
561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562 ThreadWatcherObserver* observer = new ThreadWatcherObserver(wakeup_interval);
563 MetricsService::SetUpNotifications(&observer->registrar_, observer);
564 }
565
566 // static
567 void ThreadWatcherObserver::RemoveNotifications() {
568 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
569 if (!g_thread_watcher_observer_)
570 return;
571 g_thread_watcher_observer_->registrar_.RemoveAll();
572 delete g_thread_watcher_observer_;
573 }
574
575 void ThreadWatcherObserver::Observe(NotificationType type,
576 const NotificationSource& source,
577 const NotificationDetails& details) {
578 // There is some user activity, see if thread watchers are to be awakened.
579 base::TimeTicks now = base::TimeTicks::Now();
580 if ((now - last_wakeup_time_) < wakeup_interval_)
581 return;
582 last_wakeup_time_ = now;
370 WatchDogThread::PostTask( 583 WatchDogThread::PostTask(
371 FROM_HERE, 584 FROM_HERE,
372 NewRunnableMethod(global_, &ThreadWatcherList::DeleteAll)); 585 NewRunnableFunction(&ThreadWatcherList::WakeUpAll));
373 }
374
375 // static
376 void ThreadWatcherList::RemoveNotifications() {
377 // Assert we are not running on WATCHDOG thread. Would be ideal to assert we
378 // are on UI thread, but Unit tests are not running on UI thread.
379 DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread());
380 if (!global_)
381 return;
382 base::AutoLock auto_lock(global_->lock_);
383 global_->registrar_.RemoveAll();
384 }
385
386 // static
387 void ThreadWatcherList::GetStatusOfThreads(int* no_of_responding_threads,
388 int* no_of_unresponding_threads) {
389 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
390 *no_of_responding_threads = 0;
391 *no_of_unresponding_threads = 0;
392 if (!global_)
393 return;
394
395 base::AutoLock auto_lock(global_->lock_);
396 for (RegistrationList::iterator it = global_->registered_.begin();
397 global_->registered_.end() != it;
398 ++it) {
399 if (it->second->unresponsive_count_ < ThreadWatcher::kUnresponsiveCount)
400 ++(*no_of_responding_threads);
401 else
402 ++(*no_of_unresponding_threads);
403 }
404 }
405
406 void ThreadWatcherList::DeleteAll() {
407 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
408 base::AutoLock auto_lock(lock_);
409 while (!registered_.empty()) {
410 RegistrationList::iterator it = registered_.begin();
411 delete it->second;
412 registered_.erase(it->first);
413 }
414 }
415
416 void ThreadWatcherList::Observe(NotificationType type,
417 const NotificationSource& source,
418 const NotificationDetails& details) {
419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
420 // There is some user activity, see if thread watchers are to be awakened.
421 bool need_to_awaken = false;
422 base::TimeTicks now = base::TimeTicks::Now();
423 {
424 base::AutoLock lock(lock_);
425 if (now - last_wakeup_time_ > base::TimeDelta::FromSeconds(kSleepSeconds)) {
426 need_to_awaken = true;
427 last_wakeup_time_ = now;
428 }
429 }
430 if (need_to_awaken) {
431 WatchDogThread::PostTask(
432 FROM_HERE,
433 NewRunnableMethod(this, &ThreadWatcherList::WakeUpAll));
434 }
435 }
436
437 void ThreadWatcherList::WakeUpAll() {
438 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
439 if (!global_)
440 return;
441 base::AutoLock auto_lock(lock_);
442 for (RegistrationList::iterator it = global_->registered_.begin();
443 global_->registered_.end() != it;
444 ++it)
445 it->second->WakeUp();
446 }
447
448 // static
449 ThreadWatcher* ThreadWatcherList::Find(const BrowserThread::ID& thread_id) {
450 if (!global_)
451 return NULL;
452 base::AutoLock auto_lock(global_->lock_);
453 return global_->PreLockedFind(thread_id);
454 }
455
456 ThreadWatcher* ThreadWatcherList::PreLockedFind(
457 const BrowserThread::ID& thread_id) {
458 RegistrationList::iterator it = registered_.find(thread_id);
459 if (registered_.end() == it)
460 return NULL;
461 return it->second;
462 } 586 }
463 587
464 // WatchDogThread methods and members. 588 // WatchDogThread methods and members.
465 // 589 //
466 // static 590 // static
467 base::Lock WatchDogThread::lock_; 591 base::Lock WatchDogThread::lock_;
468 // static 592 // static
469 WatchDogThread* WatchDogThread::watchdog_thread_ = NULL; 593 WatchDogThread* WatchDogThread::watchdog_thread_ = NULL;
470 594
471 // The WatchDogThread object must outlive any tasks posted to the IO thread 595 // The WatchDogThread object must outlive any tasks posted to the IO thread
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 watchdog_thread_ = this; 660 watchdog_thread_ = this;
537 } 661 }
538 662
539 void WatchDogThread::CleanUp() { 663 void WatchDogThread::CleanUp() {
540 base::AutoLock lock(lock_); 664 base::AutoLock lock(lock_);
541 watchdog_thread_ = NULL; 665 watchdog_thread_ = NULL;
542 } 666 }
543 667
544 void WatchDogThread::CleanUpAfterMessageLoopDestruction() { 668 void WatchDogThread::CleanUpAfterMessageLoopDestruction() {
545 #if defined(OS_WIN) 669 #if defined(OS_WIN)
546 // Closes the COM library on the current thread. CoInitialize must 670 // Closes the COM library on the current thread. CoInitialize must be balanced
547 // be balanced by a corresponding call to CoUninitialize. 671 // by a corresponding call to CoUninitialize.
548 CoUninitialize(); 672 CoUninitialize();
549 #endif 673 #endif
550 } 674 }
OLDNEW
« no previous file with comments | « chrome/browser/metrics/thread_watcher.h ('k') | chrome/browser/metrics/thread_watcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698