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

Side by Side Diff: content/gpu/gpu_watchdog_thread.cc

Issue 22289002: Added suspend/resume detection to the GpuWatchdogThread (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Derp. Null references are bad. Created 7 years, 4 months 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 | « content/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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/gpu/gpu_watchdog_thread.h" 9 #include "content/gpu/gpu_watchdog_thread.h"
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/command_line.h" 13 #include "base/command_line.h"
14 #include "base/compiler_specific.h" 14 #include "base/compiler_specific.h"
15 #include "base/power_monitor/power_monitor.h"
15 #include "base/process/process.h" 16 #include "base/process/process.h"
16 #include "build/build_config.h" 17 #include "build/build_config.h"
17 #include "content/public/common/content_switches.h" 18 #include "content/public/common/content_switches.h"
18 #include "content/public/common/result_codes.h" 19 #include "content/public/common/result_codes.h"
19 20
20 namespace content { 21 namespace content {
21 namespace { 22 namespace {
22 const int64 kCheckPeriodMs = 2000; 23 const int64 kCheckPeriodMs = 2000;
23 } // namespace 24 } // namespace
24 25
25 GpuWatchdogThread::GpuWatchdogThread(int timeout) 26 GpuWatchdogThread::GpuWatchdogThread(int timeout)
26 : base::Thread("Watchdog"), 27 : base::Thread("Watchdog"),
27 watched_message_loop_(base::MessageLoop::current()), 28 watched_message_loop_(base::MessageLoop::current()),
28 timeout_(base::TimeDelta::FromMilliseconds(timeout)), 29 timeout_(base::TimeDelta::FromMilliseconds(timeout)),
29 armed_(false), 30 armed_(false),
30 #if defined(OS_WIN) 31 #if defined(OS_WIN)
31 watched_thread_handle_(0), 32 watched_thread_handle_(0),
32 arm_cpu_time_(), 33 arm_cpu_time_(),
33 #endif 34 #endif
34 task_observer_(this), 35 task_observer_(this),
35 weak_factory_(this) { 36 weak_factory_(this),
37 suspended_(false) {
36 DCHECK(timeout >= 0); 38 DCHECK(timeout >= 0);
37 39
38 #if defined(OS_WIN) 40 #if defined(OS_WIN)
39 // GetCurrentThread returns a pseudo-handle that cannot be used by one thread 41 // GetCurrentThread returns a pseudo-handle that cannot be used by one thread
40 // to identify another. DuplicateHandle creates a "real" handle that can be 42 // to identify another. DuplicateHandle creates a "real" handle that can be
41 // used for this purpose. 43 // used for this purpose.
42 BOOL result = DuplicateHandle(GetCurrentProcess(), 44 BOOL result = DuplicateHandle(GetCurrentProcess(),
43 GetCurrentThread(), 45 GetCurrentThread(),
44 GetCurrentProcess(), 46 GetCurrentProcess(),
45 &watched_thread_handle_, 47 &watched_thread_handle_,
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 99
98 GpuWatchdogThread::~GpuWatchdogThread() { 100 GpuWatchdogThread::~GpuWatchdogThread() {
99 // Verify that the thread was explicitly stopped. If the thread is stopped 101 // Verify that the thread was explicitly stopped. If the thread is stopped
100 // implicitly by the destructor, CleanUp() will not be called. 102 // implicitly by the destructor, CleanUp() will not be called.
101 DCHECK(!weak_factory_.HasWeakPtrs()); 103 DCHECK(!weak_factory_.HasWeakPtrs());
102 104
103 #if defined(OS_WIN) 105 #if defined(OS_WIN)
104 CloseHandle(watched_thread_handle_); 106 CloseHandle(watched_thread_handle_);
105 #endif 107 #endif
106 108
109 base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
110 if (power_monitor)
111 power_monitor->RemoveObserver(this);
112
107 watched_message_loop_->RemoveTaskObserver(&task_observer_); 113 watched_message_loop_->RemoveTaskObserver(&task_observer_);
108 } 114 }
109 115
110 void GpuWatchdogThread::OnAcknowledge() { 116 void GpuWatchdogThread::OnAcknowledge() {
117 CHECK(base::PlatformThread::CurrentId() == thread_id());
118
111 // The check has already been acknowledged and another has already been 119 // The check has already been acknowledged and another has already been
112 // scheduled by a previous call to OnAcknowledge. It is normal for a 120 // scheduled by a previous call to OnAcknowledge. It is normal for a
113 // watched thread to see armed_ being true multiple times before 121 // watched thread to see armed_ being true multiple times before
114 // the OnAcknowledge task is run on the watchdog thread. 122 // the OnAcknowledge task is run on the watchdog thread.
115 if (!armed_) 123 if (!armed_)
116 return; 124 return;
117 125
118 // Revoke any pending hang termination. 126 // Revoke any pending hang termination.
119 weak_factory_.InvalidateWeakPtrs(); 127 weak_factory_.InvalidateWeakPtrs();
120 armed_ = false; 128 armed_ = false;
121 129
130 if (suspended_)
131 return;
132
122 // If it took a long time for the acknowledgement, assume the computer was 133 // If it took a long time for the acknowledgement, assume the computer was
123 // recently suspended. 134 // recently suspended.
124 bool was_suspended = (base::Time::Now() > suspension_timeout_); 135 bool was_suspended = (base::Time::Now() > suspension_timeout_);
125 136
126 // The monitored thread has responded. Post a task to check it again. 137 // The monitored thread has responded. Post a task to check it again.
127 message_loop()->PostDelayedTask( 138 message_loop()->PostDelayedTask(
128 FROM_HERE, 139 FROM_HERE,
129 base::Bind(&GpuWatchdogThread::OnCheck, weak_factory_.GetWeakPtr(), 140 base::Bind(&GpuWatchdogThread::OnCheck, weak_factory_.GetWeakPtr(),
130 was_suspended), 141 was_suspended),
131 base::TimeDelta::FromMilliseconds(kCheckPeriodMs)); 142 base::TimeDelta::FromMilliseconds(kCheckPeriodMs));
132 } 143 }
133 144
134 void GpuWatchdogThread::OnCheck(bool after_suspend) { 145 void GpuWatchdogThread::OnCheck(bool after_suspend) {
135 if (armed_) 146 CHECK(base::PlatformThread::CurrentId() == thread_id());
147
148 // Do not create any new termination tasks if one has already been created
149 // or the system is suspended.
150 if (armed_ || suspended_)
136 return; 151 return;
137 152
138 // Must set armed before posting the task. This task might be the only task 153 // Must set armed before posting the task. This task might be the only task
139 // that will activate the TaskObserver on the watched thread and it must not 154 // that will activate the TaskObserver on the watched thread and it must not
140 // miss the false -> true transition. 155 // miss the false -> true transition.
141 armed_ = true; 156 armed_ = true;
142 157
143 #if defined(OS_WIN) 158 #if defined(OS_WIN)
144 arm_cpu_time_ = GetWatchedThreadTime(); 159 arm_cpu_time_ = GetWatchedThreadTime();
145 #endif 160 #endif
(...skipping 15 matching lines...) Expand all
161 message_loop()->PostDelayedTask( 176 message_loop()->PostDelayedTask(
162 FROM_HERE, 177 FROM_HERE,
163 base::Bind( 178 base::Bind(
164 &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang, 179 &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
165 weak_factory_.GetWeakPtr()), 180 weak_factory_.GetWeakPtr()),
166 timeout); 181 timeout);
167 } 182 }
168 183
169 // Use the --disable-gpu-watchdog command line switch to disable this. 184 // Use the --disable-gpu-watchdog command line switch to disable this.
170 void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() { 185 void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
186 // Should not get here while the system is suspended.
187 DCHECK(!suspended_);
188
171 #if defined(OS_WIN) 189 #if defined(OS_WIN)
172 // Defer termination until a certain amount of CPU time has elapsed on the 190 // Defer termination until a certain amount of CPU time has elapsed on the
173 // watched thread. 191 // watched thread.
174 base::TimeDelta time_since_arm = GetWatchedThreadTime() - arm_cpu_time_; 192 base::TimeDelta time_since_arm = GetWatchedThreadTime() - arm_cpu_time_;
175 if (time_since_arm < timeout_) { 193 if (time_since_arm < timeout_) {
176 message_loop()->PostDelayedTask( 194 message_loop()->PostDelayedTask(
177 FROM_HERE, 195 FROM_HERE,
178 base::Bind( 196 base::Bind(
179 &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang, 197 &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
180 weak_factory_.GetWeakPtr()), 198 weak_factory_.GetWeakPtr()),
(...skipping 26 matching lines...) Expand all
207 225
208 LOG(ERROR) << "The GPU process hung. Terminating after " 226 LOG(ERROR) << "The GPU process hung. Terminating after "
209 << timeout_.InMilliseconds() << " ms."; 227 << timeout_.InMilliseconds() << " ms.";
210 228
211 // Deliberately crash the process to create a crash dump. 229 // Deliberately crash the process to create a crash dump.
212 *((volatile int*)0) = 0x1337; 230 *((volatile int*)0) = 0x1337;
213 231
214 terminated = true; 232 terminated = true;
215 } 233 }
216 234
235 void GpuWatchdogThread::AddPowerObserver() {
236 message_loop()->PostTask(
237 FROM_HERE,
238 base::Bind(&GpuWatchdogThread::OnAddPowerObserver, this));
239 }
240
241 void GpuWatchdogThread::OnAddPowerObserver() {
242 base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
243 DCHECK(power_monitor);
244 power_monitor->AddObserver(this);
245 }
246
247 void GpuWatchdogThread::OnSuspend() {
248 suspended_ = true;
249
250 // When suspending force an acknowledgement to cancel any pending termination
251 // tasks.
252 OnAcknowledge();
253 }
254
255 void GpuWatchdogThread::OnResume() {
256 suspended_ = false;
257
258 // After resuming jump-start the watchdog again.
259 armed_ = false;
260 OnCheck(true);
261 }
262
217 #if defined(OS_WIN) 263 #if defined(OS_WIN)
218 base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() { 264 base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() {
219 FILETIME creation_time; 265 FILETIME creation_time;
220 FILETIME exit_time; 266 FILETIME exit_time;
221 FILETIME user_time; 267 FILETIME user_time;
222 FILETIME kernel_time; 268 FILETIME kernel_time;
223 BOOL result = GetThreadTimes(watched_thread_handle_, 269 BOOL result = GetThreadTimes(watched_thread_handle_,
224 &creation_time, 270 &creation_time,
225 &exit_time, 271 &exit_time,
226 &kernel_time, 272 &kernel_time,
(...skipping 14 matching lines...) Expand all
241 // not increasing. The other is where either the kernel hangs and never 287 // not increasing. The other is where either the kernel hangs and never
242 // returns to user level or where user level code 288 // returns to user level or where user level code
243 // calls into kernel level repeatedly, giving up its quanta before it is 289 // calls into kernel level repeatedly, giving up its quanta before it is
244 // tracked, for example a loop that repeatedly Sleeps. 290 // tracked, for example a loop that repeatedly Sleeps.
245 return base::TimeDelta::FromMilliseconds(static_cast<int64>( 291 return base::TimeDelta::FromMilliseconds(static_cast<int64>(
246 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000)); 292 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000));
247 } 293 }
248 #endif 294 #endif
249 295
250 } // namespace content 296 } // namespace content
OLDNEW
« no previous file with comments | « content/gpu/gpu_watchdog_thread.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698