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

Side by Side 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 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/gpu/gpu_watchdog_thread.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #if defined(OS_WIN) 5 #if defined(OS_WIN)
6 #include <windows.h> 6 #include <windows.h>
7 #endif 7 #endif
8 8
9 #include "chrome/gpu/gpu_watchdog_thread.h" 9 #include "chrome/gpu/gpu_watchdog_thread.h"
10 10
11 #include "base/compiler_specific.h" 11 #include "base/compiler_specific.h"
12 #include "build/build_config.h" 12 #include "build/build_config.h"
13 13
14 namespace { 14 namespace {
15 const int64 kCheckPeriod = 2000; 15 const int64 kCheckPeriod = 2000;
16 16
17 void DoNothing() { 17 void DoNothing() {
18 } 18 }
19 } 19 }
20 20
21 GpuWatchdogThread::GpuWatchdogThread(MessageLoop* watched_message_loop, 21 GpuWatchdogThread::GpuWatchdogThread(int timeout)
22 int timeout)
23 : base::Thread("Watchdog"), 22 : base::Thread("Watchdog"),
24 watched_message_loop_(watched_message_loop), 23 watched_message_loop_(MessageLoop::current()),
25 timeout_(timeout), 24 timeout_(timeout),
26 armed_(false), 25 armed_(false),
26 #if defined(OS_WIN)
27 watched_thread_handle_(0),
28 arm_time_(0),
29 #endif
27 ALLOW_THIS_IN_INITIALIZER_LIST(task_observer_(this)) { 30 ALLOW_THIS_IN_INITIALIZER_LIST(task_observer_(this)) {
28 DCHECK(watched_message_loop);
29 DCHECK(timeout >= 0); 31 DCHECK(timeout >= 0);
30 32
33 #if defined(OS_WIN)
34 // GetCurrentThread returns a pseudo-handle that cannot be used by one thread
35 // to identify another. DuplicateHandle creates a "real" handle that can be
36 // used for this purpose.
37 BOOL result = DuplicateHandle(GetCurrentProcess(),
38 GetCurrentThread(),
39 GetCurrentProcess(),
40 &watched_thread_handle_,
41 THREAD_QUERY_INFORMATION,
42 FALSE,
43 0);
44 DCHECK(result);
45 #endif
46
31 watched_message_loop_->AddTaskObserver(&task_observer_); 47 watched_message_loop_->AddTaskObserver(&task_observer_);
32 } 48 }
33 49
34 GpuWatchdogThread::~GpuWatchdogThread() { 50 GpuWatchdogThread::~GpuWatchdogThread() {
35 // Verify that the thread was explicitly stopped. If the thread is stopped 51 // Verify that the thread was explicitly stopped. If the thread is stopped
36 // implicitly by the destructor, CleanUp() will not be called. 52 // implicitly by the destructor, CleanUp() will not be called.
37 DCHECK(!method_factory_.get()); 53 DCHECK(!method_factory_.get());
38 54
55 #if defined(OS_WIN)
56 CloseHandle(watched_thread_handle_);
57 #endif
58
39 watched_message_loop_->RemoveTaskObserver(&task_observer_); 59 watched_message_loop_->RemoveTaskObserver(&task_observer_);
40 } 60 }
41 61
42 void GpuWatchdogThread::PostAcknowledge() { 62 void GpuWatchdogThread::PostAcknowledge() {
43 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use 63 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use
44 // the method factory. Rely on reference counting instead. 64 // the method factory. Rely on reference counting instead.
45 message_loop()->PostTask( 65 message_loop()->PostTask(
46 FROM_HERE, 66 FROM_HERE,
47 NewRunnableMethod(this, &GpuWatchdogThread::OnAcknowledge)); 67 NewRunnableMethod(this, &GpuWatchdogThread::OnAcknowledge));
48 } 68 }
49 69
50 void GpuWatchdogThread::Init() { 70 void GpuWatchdogThread::Init() {
51 // The method factory must be created on the watchdog thread. 71 // The method factory must be created on the watchdog thread.
52 method_factory_.reset(new MethodFactory(this)); 72 method_factory_.reset(new MethodFactory(this));
53 73
54 // Schedule the first check. 74 // Schedule the first check.
55 OnCheck(); 75 OnCheck();
56 } 76 }
57 77
58 void GpuWatchdogThread::CleanUp() { 78 void GpuWatchdogThread::CleanUp() {
59 // The method factory must be destroyed on the watchdog thread. 79 // The method factory must be destroyed on the watchdog thread.
60 method_factory_->RevokeAll(); 80 method_factory_->RevokeAll();
61 method_factory_.reset(); 81 method_factory_.reset();
62
63 // Prevent any more delayed tasks from being posted.
64 watched_message_loop_ = NULL;
65 } 82 }
66 83
67 GpuWatchdogThread::GpuWatchdogTaskObserver::GpuWatchdogTaskObserver( 84 GpuWatchdogThread::GpuWatchdogTaskObserver::GpuWatchdogTaskObserver(
68 GpuWatchdogThread* watchdog) 85 GpuWatchdogThread* watchdog)
69 : watchdog_(watchdog) { 86 : watchdog_(watchdog) {
70 } 87 }
71 88
72 GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() { 89 GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() {
73 } 90 }
74 91
(...skipping 24 matching lines...) Expand all
99 // watched thread to see armed_ being true multiple times before 116 // watched thread to see armed_ being true multiple times before
100 // the OnAcknowledge task is run on the watchdog thread. 117 // the OnAcknowledge task is run on the watchdog thread.
101 if (!armed_) 118 if (!armed_)
102 return; 119 return;
103 120
104 // Revoke any pending OnExit. 121 // Revoke any pending OnExit.
105 method_factory_->RevokeAll(); 122 method_factory_->RevokeAll();
106 armed_ = false; 123 armed_ = false;
107 124
108 // The monitored thread has responded. Post a task to check it again. 125 // The monitored thread has responded. Post a task to check it again.
109 if (watched_message_loop_) { 126 message_loop()->PostDelayedTask(
110 message_loop()->PostDelayedTask( 127 FROM_HERE,
111 FROM_HERE, 128 method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnCheck),
112 method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnCheck), 129 kCheckPeriod);
113 kCheckPeriod);
114 }
115 } 130 }
116 131
132 #if defined(OS_WIN)
133 int64 GpuWatchdogThread::GetWatchedThreadTime() {
134 FILETIME creation_time;
135 FILETIME exit_time;
136 FILETIME user_time;
137 FILETIME kernel_time;
138 BOOL result = GetThreadTimes(watched_thread_handle_,
139 &creation_time,
140 &exit_time,
141 &kernel_time,
142 &user_time);
143 DCHECK(result);
144
145 ULARGE_INTEGER user_time64;
146 user_time64.HighPart = user_time.dwHighDateTime;
147 user_time64.LowPart = user_time.dwLowDateTime;
148
149 ULARGE_INTEGER kernel_time64;
150 kernel_time64.HighPart = kernel_time.dwHighDateTime;
151 kernel_time64.LowPart = kernel_time.dwLowDateTime;
152
153 // Time is reported in units of 100 nanoseconds. Kernel and user time are
154 // summed to deal with to kinds of hangs. One is where the GPU process is
155 // stuck in user level, never calling into the kernel and kernel time is
156 // not increasing. The other is where either the kernel hangs and never
157 // returns to user level or where user level code
158 // calls into kernel level repeatedly, giving up its quanta before it is
159 // tracked, for example a loop that repeatedly Sleeps.
160 return static_cast<int64>(
161 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000);
162 }
163 #endif
164
117 void GpuWatchdogThread::OnCheck() { 165 void GpuWatchdogThread::OnCheck() {
118 if (watched_message_loop_) { 166 if (armed_)
119 // Must set armed before posting the task. This task might be the only task 167 return;
120 // that will activate the TaskObserver on the watched thread and it must not
121 // miss the false -> true transition.
122 armed_ = true;
123 168
124 // Post a task to the monitored thread that does nothing but wake up the 169 // Must set armed before posting the task. This task might be the only task
125 // TaskObserver. Any other tasks that are pending on the watched thread will 170 // that will activate the TaskObserver on the watched thread and it must not
126 // also wake up the observer. This simply ensures there is at least one. 171 // miss the false -> true transition.
127 watched_message_loop_->PostTask( 172 armed_ = true;
128 FROM_HERE,
129 NewRunnableFunction(DoNothing));
130 173
131 // Post a task to the watchdog thread to exit if the monitored thread does 174 #if defined(OS_WIN)
132 // not respond in time. 175 arm_time_ = GetWatchedThreadTime();
133 message_loop()->PostDelayedTask( 176 #endif
134 FROM_HERE, 177
135 method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnExit), 178 // Post a task to the monitored thread that does nothing but wake up the
136 timeout_); 179 // TaskObserver. Any other tasks that are pending on the watched thread will
137 } 180 // also wake up the observer. This simply ensures there is at least one.
181 watched_message_loop_->PostTask(
182 FROM_HERE,
183 NewRunnableFunction(DoNothing));
184
185 // Post a task to the watchdog thread to exit if the monitored thread does
186 // not respond in time.
187 message_loop()->PostDelayedTask(
188 FROM_HERE,
189 method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnExit),
190 timeout_);
138 } 191 }
139 192
140 // Use the --disable-gpu-watchdog command line switch to disable this. 193 // Use the --disable-gpu-watchdog command line switch to disable this.
141 void GpuWatchdogThread::OnExit() { 194 void GpuWatchdogThread::OnExit() {
195 #if defined(OS_WIN)
196 // Defer termination until a certain amount of user time has elapsed.
197 int64 time_since_arm = GetWatchedThreadTime() - arm_time_;
198 if (time_since_arm < timeout_) {
199 message_loop()->PostDelayedTask(
200 FROM_HERE,
201 method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnExit),
202 timeout_ - time_since_arm);
203 return;
204 }
205 #endif
206
142 // Make sure the timeout period is on the stack before crashing. 207 // Make sure the timeout period is on the stack before crashing.
143 volatile int timeout = timeout_; 208 volatile int timeout = timeout_;
144 209
145 // For minimal developer annoyance, don't keep crashing. 210 // For minimal developer annoyance, don't keep crashing.
146 static bool crashed = false; 211 static bool crashed = false;
147 if (crashed) 212 if (crashed)
148 return; 213 return;
149 214
150 #if defined(OS_WIN) 215 #if defined(OS_WIN)
151 if (IsDebuggerPresent()) 216 if (IsDebuggerPresent())
152 return; 217 return;
153 #endif 218 #endif
154 219
155 LOG(ERROR) << "The GPU process hung. Restarting after " 220 LOG(ERROR) << "The GPU process hung. Restarting after "
156 << timeout_ << " seconds."; 221 << timeout_ << " seconds.";
157 222
158 volatile int* null_pointer = NULL; 223 volatile int* null_pointer = NULL;
159 *null_pointer = timeout; 224 *null_pointer = timeout;
160 225
161 crashed = true; 226 crashed = true;
162 } 227 }
OLDNEW
« 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