diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/hang_monitor | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/hang_monitor')
-rw-r--r-- | chrome/browser/hang_monitor/hung_plugin_action.cc | 185 | ||||
-rw-r--r-- | chrome/browser/hang_monitor/hung_plugin_action.h | 71 | ||||
-rw-r--r-- | chrome/browser/hang_monitor/hung_window_detector.cc | 201 | ||||
-rw-r--r-- | chrome/browser/hang_monitor/hung_window_detector.h | 116 |
4 files changed, 573 insertions, 0 deletions
diff --git a/chrome/browser/hang_monitor/hung_plugin_action.cc b/chrome/browser/hang_monitor/hung_plugin_action.cc new file mode 100644 index 0000000..34781bb --- /dev/null +++ b/chrome/browser/hang_monitor/hung_plugin_action.cc @@ -0,0 +1,185 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <windows.h> + +#include "chrome/browser/hang_monitor/hung_plugin_action.h" + +#include "base/win_util.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/logging_chrome.h" +#include "chrome/common/win_util.h" +#include "webkit/glue/plugins/webplugin_delegate_impl.h" + +#include "generated_resources.h" + +HungPluginAction::HungPluginAction() : current_hung_plugin_window_(NULL) { +} + +HungPluginAction::~HungPluginAction() { +} + +bool HungPluginAction::OnHungWindowDetected(HWND hung_window, + HWND top_level_window, + ActionOnHungWindow* action) { + if (NULL == action) { + return false; + } + if (!IsWindow(hung_window)) { + return false; + } + + bool continue_hang_detection = true; + + if (WebPluginDelegateImpl::IsDummyActivationWindow(hung_window)) { + return continue_hang_detection; + } + + DWORD hung_window_process_id = 0; + DWORD top_level_window_process_id = 0; + GetWindowThreadProcessId(hung_window, &hung_window_process_id); + GetWindowThreadProcessId(top_level_window, &top_level_window_process_id); + + *action = HungWindowNotification::HUNG_WINDOW_IGNORE; + if (top_level_window_process_id != hung_window_process_id) { + if (logging::DialogsAreSuppressed()) { + NOTREACHED() << "Terminated a hung plugin process."; + *action = HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS; + } else { + std::wstring plugin_name; + GetPluginName(hung_window, + top_level_window_process_id, + &plugin_name); + if (plugin_name.empty()) { + plugin_name = l10n_util::GetString(IDS_UNKNOWN_PLUGIN_NAME); + } + std::wstring msg = l10n_util::GetStringF(IDS_BROWSER_HANGMONITOR, + plugin_name); + std::wstring title = l10n_util::GetString(IDS_BROWSER_HANGMONITOR_TITLE); + // Before displaying the message box,invoke SendMessageCallback on the + // hung window. If the callback ever hits,the window is not hung anymore + // and we can dismiss the message box. + SendMessageCallback(hung_window, + WM_NULL, + 0, + 0, + HungWindowResponseCallback, + reinterpret_cast<ULONG_PTR>(this)); + current_hung_plugin_window_ = hung_window; + const UINT mb_flags = MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND; + if (IDYES == win_util::MessageBox(NULL, msg, title, mb_flags)) { + *action = HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS; + } else { + // If the user choses to ignore the hung window warning, the + // message timeout for this window should be doubled. We only + // double the timeout property on the window if the property + // exists. The property is deleted if the window becomes + // responsive. + continue_hang_detection = false; +#pragma warning(disable:4311) + int child_window_message_timeout = + reinterpret_cast<int>(GetProp( + hung_window, HungWindowDetector::kHungChildWindowTimeout)); +#pragma warning(default:4311) + if (child_window_message_timeout) { + child_window_message_timeout *= 2; +#pragma warning(disable:4312) + SetProp(hung_window, HungWindowDetector::kHungChildWindowTimeout, + reinterpret_cast<HANDLE>(child_window_message_timeout)); +#pragma warning(default:4312) + } + } + current_hung_plugin_window_ = NULL; + } + } + if (HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS == *action) { + // Enable the top-level window just in case the plugin had been + // displaying a modal box that had disabled the top-level window + EnableWindow(top_level_window, TRUE); + } + return continue_hang_detection; +} + +void HungPluginAction::OnWindowResponsive(HWND window) { + if (window == current_hung_plugin_window_) { + // The message timeout for this window should fallback to the default + // timeout as this window is now responsive. + RemoveProp(window, HungWindowDetector::kHungChildWindowTimeout); + // The monitored plugin recovered. Let's dismiss the message box. + EnumThreadWindows(GetCurrentThreadId(), + reinterpret_cast<WNDENUMPROC>(DismissMessageBox), + NULL); + } +} + +bool HungPluginAction::GetPluginName(HWND plugin_window, + DWORD browser_process_id, + std::wstring* plugin_name) { + DCHECK(plugin_name); + HWND window_to_check = plugin_window; + while (NULL != window_to_check) { + DWORD process_id = 0; + GetWindowThreadProcessId(window_to_check, &process_id); + if (process_id == browser_process_id) { + // If we have reached a window the that belongs to the browser process + // we have gone too far. + return false; + } + if (WebPluginDelegateImpl::GetPluginNameFromWindow(window_to_check, + plugin_name)) { + return true; + } + window_to_check = GetParent(window_to_check); + } + return false; +} + +// static +BOOL CALLBACK HungPluginAction::DismissMessageBox(HWND window, LPARAM ignore) { + std::wstring class_name = win_util::GetClassNameW(window); + // #32770 is the dialog window class which is the window class of + // the message box being displayed. + if (class_name == L"#32770") { + EndDialog(window, IDNO); + return FALSE; + } + return TRUE; +} + +// static +void CALLBACK HungPluginAction::HungWindowResponseCallback(HWND target_window, + UINT message, + ULONG_PTR data, + LRESULT result) { + HungPluginAction* instance = reinterpret_cast<HungPluginAction*>(data); + DCHECK(NULL != instance); + if (NULL != instance) { + instance->OnWindowResponsive(target_window); + } +} diff --git a/chrome/browser/hang_monitor/hung_plugin_action.h b/chrome/browser/hang_monitor/hung_plugin_action.h new file mode 100644 index 0000000..ac15a47 --- /dev/null +++ b/chrome/browser/hang_monitor/hung_plugin_action.h @@ -0,0 +1,71 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CHROME_BROWSER_HANG_MONITOR_HUNG_WINDOW_DETECTOR_H__ +#define CHROME_BROWSER_HANG_MONITOR_HUNG_WINDOW_DETECTOR_H__ + +#include "chrome/browser/hang_monitor/hung_window_detector.h" +// This class provides an implementation the +// HungWindowDetector::HungWindowNotification callback interface. +// It checks to see if the hung window belongs to a process different +// from that of the browser process and, if so, it returns an action +// of HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS. +// Note: We can write other action classes that implement the same +// interface and switch the action done on hung plugins based on user +// preferences. +class HungPluginAction : public HungWindowDetector::HungWindowNotification { + public: + HungPluginAction(); + ~HungPluginAction(); + // HungWindowNotification implementation + virtual bool OnHungWindowDetected(HWND hung_window, + HWND top_level_window, + ActionOnHungWindow* action); + + protected: + void OnWindowResponsive(HWND window); + + // The callback function for the SendMessageCallback API + static void CALLBACK HungWindowResponseCallback(HWND target_window, + UINT message, + ULONG_PTR data, + LRESULT result); + + static BOOL CALLBACK DismissMessageBox(HWND window, LPARAM ignore); + + protected: + bool GetPluginName(HWND plugin_window, + DWORD browser_process_id, + std::wstring *plugin_name); + // The currently hung plugin window that we are prompting the user about + HWND current_hung_plugin_window_; +}; + +#endif // CHROME_BROWSER_HANG_MONITOR_HUNG_WINDOW_DETECTOR_H__ + diff --git a/chrome/browser/hang_monitor/hung_window_detector.cc b/chrome/browser/hang_monitor/hung_window_detector.cc new file mode 100644 index 0000000..653d0d3 --- /dev/null +++ b/chrome/browser/hang_monitor/hung_window_detector.cc @@ -0,0 +1,201 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/browser/hang_monitor/hung_window_detector.h" + +#include <windows.h> + +#include "base/logging.h" +#include "chrome/app/result_codes.h" + +// How long do we wait for the terminated thread or process to die (in ms) +static const int kTerminateTimeout = 2000; + +const wchar_t HungWindowDetector::kHungChildWindowTimeout[] = + L"Chrome_HungChildWindowTimeout"; + +HungWindowDetector::HungWindowDetector(HungWindowNotification* notification) + : notification_(notification), + top_level_window_(NULL), + enumerating_(false) { + DCHECK(NULL != notification_); +} +// NOTE: It is the caller's responsibility to make sure that +// callbacks on this object have been stopped before +// destroying this object +HungWindowDetector::~HungWindowDetector() { +} + +bool HungWindowDetector::Initialize(HWND top_level_window, + int message_response_timeout) { + if (NULL == notification_) { + return false; + } + if (NULL == top_level_window) { + return false; + } + // It is OK to call Initialize on this object repeatedly + // with different top lebel HWNDs and timeout values each time. + // And we do not need a lock for this because we are just + // swapping DWORDs. + top_level_window_ = top_level_window; + message_response_timeout_ = message_response_timeout; + return true; +} + +void HungWindowDetector::OnTick() { + do { + AutoLock lock(hang_detection_lock_); + // If we already are checking for hung windows on another thread, + // don't do this again. + if (enumerating_) { + return; + } + enumerating_ = true; + } while (false); // To scope the AutoLock + + EnumChildWindows(top_level_window_, ChildWndEnumProc, + reinterpret_cast<LPARAM>(this)); + enumerating_ = false; +} + +bool HungWindowDetector::CheckChildWindow(HWND child_window) { + // It can happen that the window is DOA. It specifically happens + // when we have just killed a plugin process and the enum is still + // enumerating windows from that process. + if (!IsWindow(child_window)) { + return true; + } + + DWORD top_level_window_thread_id = + GetWindowThreadProcessId(top_level_window_, NULL); + + DWORD child_window_process_id = 0; + DWORD child_window_thread_id = + GetWindowThreadProcessId(child_window, &child_window_process_id); + bool continue_hang_detection = true; + + if (top_level_window_thread_id != child_window_thread_id) { + // The message timeout for a child window starts of with a default + // value specified by the message_response_timeout_ member. It is + // tracked by a property on the child window. +#pragma warning(disable:4311) + int child_window_message_timeout = + reinterpret_cast<int>(GetProp(child_window, kHungChildWindowTimeout)); +#pragma warning(default:4311) + if (!child_window_message_timeout) { + child_window_message_timeout = message_response_timeout_; + } + + DWORD result = 0; + if ((0 == SendMessageTimeout(child_window, + WM_NULL, + 0, + 0, + SMTO_BLOCK, + child_window_message_timeout, + &result)) || + IsHungAppWindow(child_window)) { + HungWindowNotification::ActionOnHungWindow action = + HungWindowNotification::HUNG_WINDOW_IGNORE; +#pragma warning(disable:4312) + SetProp(child_window, kHungChildWindowTimeout, + reinterpret_cast<HANDLE>(child_window_message_timeout)); +#pragma warning(default:4312) + continue_hang_detection = + notification_->OnHungWindowDetected(child_window, top_level_window_, + &action); + // Make sure this window still a child of our top-level parent + if (!IsChild(top_level_window_, child_window)) { + return continue_hang_detection; + } + + switch (action) { + case HungWindowNotification::HUNG_WINDOW_TERMINATE_THREAD: { + CHandle child_thread(OpenThread(THREAD_TERMINATE, + FALSE, + child_window_thread_id)); + if (NULL == child_thread.m_h) { + break; + } + // Before swinging the axe, do some sanity checks to make + // sure this window still belongs to the same thread + if (GetWindowThreadProcessId(child_window, NULL) != + child_window_thread_id) { + break; + } + TerminateThread(child_thread, 0); + WaitForSingleObject(child_thread, kTerminateTimeout); + child_thread.Close(); + break; + } + case HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS: { + CHandle child_process(OpenProcess(PROCESS_TERMINATE, + FALSE, + child_window_process_id)); + + if (NULL == child_process.m_h) { + break; + } + // Before swinging the axe, do some sanity checks to make + // sure this window still belongs to the same process + DWORD process_id_check = 0; + GetWindowThreadProcessId(child_window, &process_id_check); + if (process_id_check != child_window_process_id) { + break; + } + TerminateProcess(child_process, ResultCodes::HUNG); + WaitForSingleObject(child_process, kTerminateTimeout); + child_process.Close(); + break; + } + default: { + break; + } + } + } else { + RemoveProp(child_window, kHungChildWindowTimeout); + } + } + + return continue_hang_detection; +} + +BOOL CALLBACK HungWindowDetector::ChildWndEnumProc(HWND child_window, + LPARAM param) { + HungWindowDetector* detector_instance = + reinterpret_cast<HungWindowDetector*>(param); + if (NULL == detector_instance) { + NOTREACHED(); + return FALSE; + } + + return detector_instance->CheckChildWindow(child_window); +} + diff --git a/chrome/browser/hang_monitor/hung_window_detector.h b/chrome/browser/hang_monitor/hung_window_detector.h new file mode 100644 index 0000000..4de7beb --- /dev/null +++ b/chrome/browser/hang_monitor/hung_window_detector.h @@ -0,0 +1,116 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CHROME_BROWSER_HUNG_WINDOW_DETECTOR_H__ +#define CHROME_BROWSER_HUNG_WINDOW_DETECTOR_H__ + +#include "base/lock.h" +#include "chrome/common/worker_thread_ticker.h" + +// This class provides the following functionality: +// Given a top-level window handle, it enumerates all descendant windows +// of that window and, on finding a window that belongs to a different +// thread from that of the top-level window, it tests to see if that window +// is responding to messages. It does this test by first calling the +// IsHungAppWindow API and, additionally (since the IsHungAppWindow API +// does not deal correctly with suspended threads), send a dummy message +// (WM_NULL) to the window and verifies that the call does not timeout. +// This class is typically used in conjunction with the WorkerThreadTicker +// class so that the checking can happen on a periodic basis. +// If a hung window is detected it calls back the specified implementation of +// the HungWindowNotification interface. Currently this class only supports +// a single callback but it can be extended later to support multiple +// callbacks. +class HungWindowDetector : public WorkerThreadTicker::Callback { + public: + // This property specifies the message timeout for a child window. + static const wchar_t kHungChildWindowTimeout[]; + // This is the notification callback interface that is used to notify + // callers about a non-responsive window + class HungWindowNotification { + public: + enum ActionOnHungWindow { + HUNG_WINDOW_IGNORE, + HUNG_WINDOW_TERMINATE_THREAD, + HUNG_WINDOW_TERMINATE_PROCESS, + }; + + // This callback method is invoked when a hung window is detected. + // A return value of false indicates that we should stop enumerating the + // child windows of the browser window to check if they are hung. + virtual bool OnHungWindowDetected(HWND hung_window, HWND top_level_window, + ActionOnHungWindow* action) = 0; + }; + + // The notification object is not owned by this class. It is assumed that + // this pointer will be valid throughout the lifetime of this class. + // Ownership of this pointer is not transferred to this class. + // Note that the Initialize method needs to be called to initiate monitoring + // of hung windows. + HungWindowDetector(HungWindowNotification* notification); + ~HungWindowDetector(); + + // This method initialized the monitoring of hung windows. All descendant + // windows of the passed-in top-level window which belong to a thread + // different from that of the top-level window are monitored. The + // message_response_timeout parameter indicates how long this class must + // wait for a window to respond to a sent message before it is considered + // to be non-responsive. + // Initialize can be called multiple times to change the actual window to + // be monitored as well as the message response timeout + bool Initialize(HWND top_level_window, + int message_response_timeout); + + // Implementation of the WorkerThreadTicker::Callback interface + virtual void OnTick(); + + private: + // Helper function that checks whether the specified child window is hung. + // If so, it invokes the HungWindowNotification interface implementation + bool CheckChildWindow(HWND child_window); + + static BOOL CALLBACK ChildWndEnumProc(HWND child_window, LPARAM param); + + // Pointer to the HungWindowNotification callback interface. This class does + // not RefCount this pointer and it is assumed that the pointer will be valid + // throughout the lifetime of this class. + HungWindowNotification* notification_; + HWND top_level_window_; + + // How long do we wait before we consider a window hung (in ms) + int message_response_timeout_; + Lock hang_detection_lock_; + // Indicates if this object is currently enumerating hung windows + bool enumerating_; + + DISALLOW_EVIL_CONSTRUCTORS(HungWindowDetector); +}; + + +#endif // CHROME_BROWSER_HUNG_WINDOW_DETECTOR_H__ |