Index: chrome/browser/metrics/thread_watcher.cc |
=================================================================== |
--- chrome/browser/metrics/thread_watcher.cc (revision 76170) |
+++ chrome/browser/metrics/thread_watcher.cc (working copy) |
@@ -2,14 +2,16 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#if 0 |
- |
#include "base/threading/thread_restrictions.h" |
#include "build/build_config.h" |
#include "chrome/browser/metrics/metrics_service.h" |
#include "chrome/browser/metrics/thread_watcher.h" |
#include "chrome/common/notification_service.h" |
+#if defined(OS_WIN) |
+#include <Objbase.h> |
+#endif |
+ |
// static |
const int ThreadWatcher::kPingCount = 3; |
@@ -42,19 +44,20 @@ |
DCHECK_GE(sleep_time.InMilliseconds(), 0); |
DCHECK_GE(unresponsive_time.InMilliseconds(), sleep_time.InMilliseconds()); |
- // If we are not on WATCHDOG thread, then post a task to call StartWatching on |
- // WATCHDOG thread. |
- if (!BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)) { |
- BrowserThread::PostTask( |
- BrowserThread::WATCHDOG, |
- FROM_HERE, |
- NewRunnableFunction( |
- &ThreadWatcher::StartWatching, |
- thread_id, thread_name, sleep_time, unresponsive_time)); |
+ // If we are not on WatchDogThread, then post a task to call StartWatching on |
+ // WatchDogThread. |
+ if (!WatchDogThread::CurrentlyOnWatchDogThread()) { |
+ MessageLoop* message_loop = WatchDogThread::CurrentMessageLoop(); |
+ if (message_loop) |
+ message_loop->PostTask( |
+ FROM_HERE, |
+ NewRunnableFunction( |
+ &ThreadWatcher::StartWatching, |
+ thread_id, thread_name, sleep_time, unresponsive_time)); |
return; |
} |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)); |
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
// Create a new thread watcher object for the given thread and activate it. |
ThreadWatcher* watcher = |
@@ -64,7 +67,7 @@ |
} |
void ThreadWatcher::ActivateThreadWatching() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)); |
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
if (active_) return; |
active_ = true; |
ping_count_ = kPingCount; |
@@ -74,14 +77,14 @@ |
} |
void ThreadWatcher::DeActivateThreadWatching() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)); |
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
active_ = false; |
ping_count_ = 0; |
method_factory_.RevokeAll(); |
} |
void ThreadWatcher::WakeUp() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)); |
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
// There is some user activity, PostPingMessage task of thread watcher if |
// needed. |
if (!active_) return; |
@@ -95,7 +98,7 @@ |
} |
void ThreadWatcher::PostPingMessage() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)); |
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
// If we have stopped watching or if the user is idle, then stop sending |
// ping messages. |
if (!active_ || ping_count_ <= 0) |
@@ -126,7 +129,7 @@ |
} |
void ThreadWatcher::OnPongMessage(uint64 ping_sequence_number) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)); |
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
// Record watched thread's response time. |
base::TimeDelta response_time = base::TimeTicks::Now() - ping_time_; |
histogram_->AddTime(response_time); |
@@ -152,7 +155,7 @@ |
} |
bool ThreadWatcher::OnCheckResponsiveness(uint64 ping_sequence_number) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)); |
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
// If we have stopped watching then consider thread as responding. |
if (!active_) |
return true; |
@@ -178,7 +181,11 @@ |
Task* callback_task) { |
// This method is called on watched thread. |
DCHECK(BrowserThread::CurrentlyOn(thread_id)); |
- BrowserThread::PostTask(BrowserThread::WATCHDOG, FROM_HERE, callback_task); |
+ MessageLoop* message_loop = WatchDogThread::CurrentMessageLoop(); |
+ if (message_loop) |
+ message_loop->PostTask(FROM_HERE, callback_task); |
+ else |
+ delete callback_task; |
} |
//------------------------------------------------------------------------------ |
@@ -191,22 +198,15 @@ |
: last_wakeup_time_(base::TimeTicks::Now()) { |
// Assert we are not running on WATCHDOG thread. Would be ideal to assert we |
// are on UI thread, but Unit tests are not running on UI thread. |
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)); |
- DCHECK(!global_); |
+ DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread()); |
+ CHECK(!global_); |
global_ = this; |
// Register Notifications observer. |
-#if defined(OS_WIN) |
MetricsService::SetupNotifications(®istrar_, this); |
-#endif |
} |
ThreadWatcherList::~ThreadWatcherList() { |
base::AutoLock auto_lock(lock_); |
- while (!registered_.empty()) { |
- RegistrationList::iterator it = registered_.begin(); |
- delete it->second; |
- registered_.erase(it->first); |
- } |
DCHECK(this == global_); |
global_ = NULL; |
} |
@@ -224,15 +224,16 @@ |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
if (!global_) |
return; |
- base::AutoLock auto_lock(global_->lock_); |
- for (RegistrationList::iterator it = global_->registered_.begin(); |
- global_->registered_.end() != it; |
- ++it) |
- BrowserThread::PostTask( |
- BrowserThread::WATCHDOG, |
+ |
+ // Remove all notifications for all watched threads. |
+ RemoveNotifications(); |
+ |
+ // Delete all thread watcher objects on WatchDogThread. |
+ MessageLoop* message_loop = WatchDogThread::CurrentMessageLoop(); |
+ if (message_loop) |
+ message_loop->PostTask( |
FROM_HERE, |
- NewRunnableMethod( |
- it->second, &ThreadWatcher::DeActivateThreadWatching)); |
+ NewRunnableMethod(global_, &ThreadWatcherList::DeleteAll)); |
} |
// static |
@@ -240,12 +241,20 @@ |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
if (!global_) |
return; |
-#if defined(OS_WIN) |
base::AutoLock auto_lock(global_->lock_); |
global_->registrar_.RemoveAll(); |
-#endif |
} |
+void ThreadWatcherList::DeleteAll() { |
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
+ base::AutoLock auto_lock(lock_); |
+ while (!registered_.empty()) { |
+ RegistrationList::iterator it = registered_.begin(); |
+ delete it->second; |
+ registered_.erase(it->first); |
+ } |
+} |
+ |
void ThreadWatcherList::Observe(NotificationType type, |
const NotificationSource& source, |
const NotificationDetails& details) { |
@@ -260,15 +269,17 @@ |
last_wakeup_time_ = now; |
} |
} |
- if (need_to_awaken) |
- BrowserThread::PostTask( |
- BrowserThread::WATCHDOG, |
- FROM_HERE, |
- NewRunnableMethod(this, &ThreadWatcherList::WakeUpAll)); |
+ if (need_to_awaken) { |
+ MessageLoop* message_loop = WatchDogThread::CurrentMessageLoop(); |
+ if (message_loop) |
+ message_loop->PostTask( |
+ FROM_HERE, |
+ NewRunnableMethod(this, &ThreadWatcherList::WakeUpAll)); |
+ } |
} |
void ThreadWatcherList::WakeUpAll() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)); |
+ DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
base::AutoLock auto_lock(lock_); |
for (RegistrationList::iterator it = global_->registered_.begin(); |
global_->registered_.end() != it; |
@@ -294,42 +305,81 @@ |
//------------------------------------------------------------------------------ |
// WatchDogThread methods and members. |
+// static |
+base::Lock WatchDogThread::lock_; |
+// static |
+WatchDogThread* WatchDogThread::watchdog_thread_ = NULL; |
+ |
// The WatchDogThread object must outlive any tasks posted to the IO thread |
// before the Quit task. |
DISABLE_RUNNABLE_METHOD_REFCOUNT(WatchDogThread); |
-WatchDogThread::WatchDogThread() |
- : BrowserProcessSubThread(BrowserThread::WATCHDOG) { |
+WatchDogThread::WatchDogThread() : Thread("WATCHDOG") { |
} |
WatchDogThread::~WatchDogThread() { |
- // Remove all notifications for all watched threads. |
- ThreadWatcherList::RemoveNotifications(); |
// We cannot rely on our base class to stop the thread since we want our |
// CleanUp function to run. |
Stop(); |
} |
+void WatchDogThread::StartWatchingAll() { |
+ const base::TimeDelta kSleepTime = base::TimeDelta::FromSeconds(5); |
+ const base::TimeDelta kUnresponsiveTime = base::TimeDelta::FromSeconds(10); |
+ if (BrowserThread::IsMessageLoopValid(BrowserThread::UI)) |
+ ThreadWatcher::StartWatching(BrowserThread::UI, "UI", kSleepTime, |
+ kUnresponsiveTime); |
+ if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) |
+ ThreadWatcher::StartWatching(BrowserThread::IO, "IO", kSleepTime, |
+ kUnresponsiveTime); |
+ if (BrowserThread::IsMessageLoopValid(BrowserThread::DB)) |
+ ThreadWatcher::StartWatching(BrowserThread::DB, "DB", kSleepTime, |
+ kUnresponsiveTime); |
+ if (BrowserThread::IsMessageLoopValid(BrowserThread::FILE)) |
+ ThreadWatcher::StartWatching(BrowserThread::FILE, "FILE", kSleepTime, |
+ kUnresponsiveTime); |
+ if (BrowserThread::IsMessageLoopValid(BrowserThread::CACHE)) |
+ ThreadWatcher::StartWatching(BrowserThread::CACHE, "CACHE", kSleepTime, |
+ kUnresponsiveTime); |
+} |
+ |
+// static |
+MessageLoop* WatchDogThread::CurrentMessageLoop() { |
+ base::AutoLock lock(lock_); |
+ MessageLoop* message_loop = watchdog_thread_ ? |
+ watchdog_thread_->message_loop() : NULL; |
+ return message_loop; |
+} |
+ |
+// static |
+bool WatchDogThread::CurrentlyOnWatchDogThread() { |
+ base::AutoLock lock(lock_); |
+ return watchdog_thread_ && |
+ watchdog_thread_->message_loop() == MessageLoop::current(); |
+} |
+ |
void WatchDogThread::Init() { |
// This thread shouldn't be allowed to perform any blocking disk I/O. |
base::ThreadRestrictions::SetIOAllowed(false); |
- BrowserProcessSubThread::Init(); |
+#if defined(OS_WIN) |
+ // Initializes the COM library on the current thread. |
+ CoInitialize(NULL); |
+#endif |
+ base::AutoLock lock(lock_); |
+ watchdog_thread_ = this; |
+} |
+ |
+void WatchDogThread::CleanUp() { |
+ base::AutoLock lock(lock_); |
+ watchdog_thread_ = NULL; |
+} |
+ |
+void WatchDogThread::CleanUpAfterMessageLoopDestruction() { |
#if defined(OS_WIN) |
- const base::TimeDelta kSleepTime = base::TimeDelta::FromSeconds(5); |
- const base::TimeDelta kUnresponsiveTime = base::TimeDelta::FromSeconds(10); |
- ThreadWatcher::StartWatching(BrowserThread::UI, "UI", kSleepTime, |
- kUnresponsiveTime); |
- ThreadWatcher::StartWatching(BrowserThread::IO, "IO", kSleepTime, |
- kUnresponsiveTime); |
- ThreadWatcher::StartWatching(BrowserThread::DB, "DB", kSleepTime, |
- kUnresponsiveTime); |
- ThreadWatcher::StartWatching(BrowserThread::FILE, "FILE", kSleepTime, |
- kUnresponsiveTime); |
- ThreadWatcher::StartWatching(BrowserThread::CACHE, "CACHE", kSleepTime, |
- kUnresponsiveTime); |
+ // Closes the COM library on the current thread. CoInitialize must |
+ // be balanced by a corresponding call to CoUninitialize. |
+ CoUninitialize(); |
#endif |
} |
- |
-#endif // 0 |