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

Unified Diff: chrome/gpu/gpu_watchdog_thread.cc

Issue 5301007: Fixed null dereference in GPU watchdog termination code.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 1 month 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/gpu/gpu_watchdog_thread.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_;
« no previous file with comments | « chrome/gpu/gpu_watchdog_thread.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698