| Index: chrome/gpu/gpu_watchdog_thread.cc
|
| ===================================================================
|
| --- chrome/gpu/gpu_watchdog_thread.cc (revision 67749)
|
| +++ chrome/gpu/gpu_watchdog_thread.cc (working copy)
|
| @@ -18,16 +18,32 @@
|
| }
|
| }
|
|
|
| -GpuWatchdogThread::GpuWatchdogThread(MessageLoop* watched_message_loop,
|
| - int timeout)
|
| +GpuWatchdogThread::GpuWatchdogThread(int timeout)
|
| : base::Thread("Watchdog"),
|
| - watched_message_loop_(watched_message_loop),
|
| + watched_message_loop_(MessageLoop::current()),
|
| timeout_(timeout),
|
| armed_(false),
|
| +#if defined(OS_WIN)
|
| + watched_thread_handle_(0),
|
| + arm_time_(0),
|
| +#endif
|
| ALLOW_THIS_IN_INITIALIZER_LIST(task_observer_(this)) {
|
| - DCHECK(watched_message_loop);
|
| 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
|
| +
|
| watched_message_loop_->AddTaskObserver(&task_observer_);
|
| }
|
|
|
| @@ -36,6 +52,10 @@
|
| // implicitly by the destructor, CleanUp() will not be called.
|
| DCHECK(!method_factory_.get());
|
|
|
| +#if defined(OS_WIN)
|
| + CloseHandle(watched_thread_handle_);
|
| +#endif
|
| +
|
| watched_message_loop_->RemoveTaskObserver(&task_observer_);
|
| }
|
|
|
| @@ -59,9 +79,6 @@
|
| // The method factory must be destroyed on the watchdog thread.
|
| method_factory_->RevokeAll();
|
| method_factory_.reset();
|
| -
|
| - // Prevent any more delayed tasks from being posted.
|
| - watched_message_loop_ = NULL;
|
| }
|
|
|
| GpuWatchdogThread::GpuWatchdogTaskObserver::GpuWatchdogTaskObserver(
|
| @@ -106,39 +123,87 @@
|
| armed_ = false;
|
|
|
| // The monitored thread has responded. Post a task to check it again.
|
| - if (watched_message_loop_) {
|
| - message_loop()->PostDelayedTask(
|
| - FROM_HERE,
|
| - method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnCheck),
|
| - kCheckPeriod);
|
| - }
|
| + message_loop()->PostDelayedTask(
|
| + FROM_HERE,
|
| + method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnCheck),
|
| + kCheckPeriod);
|
| }
|
|
|
| +#if defined(OS_WIN)
|
| +int64 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 static_cast<int64>(
|
| + (user_time64.QuadPart + kernel_time64.QuadPart) / 10000);
|
| +}
|
| +#endif
|
| +
|
| void GpuWatchdogThread::OnCheck() {
|
| - if (watched_message_loop_) {
|
| - // Must set armed before posting the task. This task might be the only task
|
| - // that will activate the TaskObserver on the watched thread and it must not
|
| - // miss the false -> true transition.
|
| - armed_ = true;
|
| + if (armed_)
|
| + return;
|
|
|
| - // Post a task to the monitored thread that does nothing but wake up the
|
| - // TaskObserver. Any other tasks that are pending on the watched thread will
|
| - // also wake up the observer. This simply ensures there is at least one.
|
| - watched_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableFunction(DoNothing));
|
| + // Must set armed before posting the task. This task might be the only task
|
| + // that will activate the TaskObserver on the watched thread and it must not
|
| + // miss the false -> true transition.
|
| + armed_ = true;
|
|
|
| - // Post a task to the watchdog thread to exit if the monitored thread does
|
| - // not respond in time.
|
| +#if defined(OS_WIN)
|
| + arm_time_ = GetWatchedThreadTime();
|
| +#endif
|
| +
|
| + // Post a task to the monitored thread that does nothing but wake up the
|
| + // TaskObserver. Any other tasks that are pending on the watched thread will
|
| + // also wake up the observer. This simply ensures there is at least one.
|
| + watched_message_loop_->PostTask(
|
| + FROM_HERE,
|
| + NewRunnableFunction(DoNothing));
|
| +
|
| + // Post a task to the watchdog thread to exit if the monitored thread does
|
| + // not respond in time.
|
| + message_loop()->PostDelayedTask(
|
| + FROM_HERE,
|
| + method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnExit),
|
| + timeout_);
|
| +}
|
| +
|
| +// Use the --disable-gpu-watchdog command line switch to disable this.
|
| +void GpuWatchdogThread::OnExit() {
|
| +#if defined(OS_WIN)
|
| + // Defer termination until a certain amount of user time has elapsed.
|
| + int64 time_since_arm = GetWatchedThreadTime() - arm_time_;
|
| + if (time_since_arm < timeout_) {
|
| message_loop()->PostDelayedTask(
|
| FROM_HERE,
|
| method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnExit),
|
| - timeout_);
|
| + timeout_ - time_since_arm);
|
| + return;
|
| }
|
| -}
|
| +#endif
|
|
|
| -// Use the --disable-gpu-watchdog command line switch to disable this.
|
| -void GpuWatchdogThread::OnExit() {
|
| // Make sure the timeout period is on the stack before crashing.
|
| volatile int timeout = timeout_;
|
|
|
|
|