| Index: content/gpu/gpu_watchdog_thread.cc
|
| diff --git a/content/gpu/gpu_watchdog_thread.cc b/content/gpu/gpu_watchdog_thread.cc
|
| index 22982db10489fcd6e00d6a9eb8a5f45c95a7f7dc..4cfde4f94b51803d2866226284431054230bd223 100644
|
| --- a/content/gpu/gpu_watchdog_thread.cc
|
| +++ b/content/gpu/gpu_watchdog_thread.cc
|
| @@ -42,6 +42,10 @@
|
| timeout_(base::TimeDelta::FromMilliseconds(timeout)),
|
| armed_(false),
|
| task_observer_(this),
|
| +#if defined(OS_WIN)
|
| + watched_thread_handle_(0),
|
| + arm_cpu_time_(),
|
| +#endif
|
| suspended_(false),
|
| #if defined(USE_X11)
|
| display_(NULL),
|
| @@ -50,6 +54,20 @@
|
| #endif
|
| weak_factory_(this) {
|
| DCHECK(timeout >= 0);
|
| +
|
| +#if defined(OS_WIN)
|
| + // GetCurrentThread returns a pseudo-handle that cannot be used by one thread
|
| + // to identify another. DuplicateHandle creates a "real" handle that can be
|
| + // used for this purpose.
|
| + BOOL result = DuplicateHandle(GetCurrentProcess(),
|
| + GetCurrentThread(),
|
| + GetCurrentProcess(),
|
| + &watched_thread_handle_,
|
| + THREAD_QUERY_INFORMATION,
|
| + FALSE,
|
| + 0);
|
| + DCHECK(result);
|
| +#endif
|
|
|
| #if defined(OS_CHROMEOS)
|
| tty_file_ = base::OpenFile(base::FilePath(kTtyFilePath), "r");
|
| @@ -106,6 +124,10 @@
|
| // implicitly by the destructor, CleanUp() will not be called.
|
| DCHECK(!weak_factory_.HasWeakPtrs());
|
|
|
| +#if defined(OS_WIN)
|
| + CloseHandle(watched_thread_handle_);
|
| +#endif
|
| +
|
| base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
|
| if (power_monitor)
|
| power_monitor->RemoveObserver(this);
|
| @@ -163,6 +185,10 @@
|
| // that will activate the TaskObserver on the watched thread and it must not
|
| // miss the false -> true transition.
|
| armed_ = true;
|
| +
|
| +#if defined(OS_WIN)
|
| + arm_cpu_time_ = GetWatchedThreadTime();
|
| +#endif
|
|
|
| // Immediately after the computer is woken up from being suspended it might
|
| // be pretty sluggish, so allow some extra time before the next timeout.
|
| @@ -188,6 +214,21 @@
|
| void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
|
| // Should not get here while the system is suspended.
|
| DCHECK(!suspended_);
|
| +
|
| +#if defined(OS_WIN)
|
| + // Defer termination until a certain amount of CPU time has elapsed on the
|
| + // watched thread.
|
| + base::TimeDelta time_since_arm = GetWatchedThreadTime() - arm_cpu_time_;
|
| + if (time_since_arm < timeout_) {
|
| + message_loop()->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
|
| + weak_factory_.GetWeakPtr()),
|
| + timeout_ - time_since_arm);
|
| + return;
|
| + }
|
| +#endif
|
|
|
| // If the watchdog woke up significantly behind schedule, disarm and reset
|
| // the watchdog check. This is to prevent the watchdog thread from terminating
|
| @@ -329,4 +370,37 @@
|
| OnCheck(true);
|
| }
|
|
|
| +#if defined(OS_WIN)
|
| +base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() {
|
| + FILETIME creation_time;
|
| + FILETIME exit_time;
|
| + FILETIME user_time;
|
| + FILETIME kernel_time;
|
| + BOOL result = GetThreadTimes(watched_thread_handle_,
|
| + &creation_time,
|
| + &exit_time,
|
| + &kernel_time,
|
| + &user_time);
|
| + DCHECK(result);
|
| +
|
| + ULARGE_INTEGER user_time64;
|
| + user_time64.HighPart = user_time.dwHighDateTime;
|
| + user_time64.LowPart = user_time.dwLowDateTime;
|
| +
|
| + ULARGE_INTEGER kernel_time64;
|
| + kernel_time64.HighPart = kernel_time.dwHighDateTime;
|
| + kernel_time64.LowPart = kernel_time.dwLowDateTime;
|
| +
|
| + // Time is reported in units of 100 nanoseconds. Kernel and user time are
|
| + // summed to deal with to kinds of hangs. One is where the GPU process is
|
| + // stuck in user level, never calling into the kernel and kernel time is
|
| + // not increasing. The other is where either the kernel hangs and never
|
| + // returns to user level or where user level code
|
| + // calls into kernel level repeatedly, giving up its quanta before it is
|
| + // tracked, for example a loop that repeatedly Sleeps.
|
| + return base::TimeDelta::FromMilliseconds(static_cast<int64_t>(
|
| + (user_time64.QuadPart + kernel_time64.QuadPart) / 10000));
|
| +}
|
| +#endif
|
| +
|
| } // namespace content
|
|
|