Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 #include "content/gpu/gpu_watchdog_thread.h" | 5 #include "content/gpu/gpu_watchdog_thread.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 14 #include "base/debug/alias.h" | 14 #include "base/debug/alias.h" |
| 15 #include "base/files/file_path.h" | |
| 15 #include "base/files/file_util.h" | 16 #include "base/files/file_util.h" |
| 16 #include "base/location.h" | 17 #include "base/location.h" |
| 17 #include "base/macros.h" | 18 #include "base/macros.h" |
| 18 #include "base/power_monitor/power_monitor.h" | 19 #include "base/power_monitor/power_monitor.h" |
| 19 #include "base/process/process.h" | 20 #include "base/process/process.h" |
| 20 #include "base/single_thread_task_runner.h" | 21 #include "base/single_thread_task_runner.h" |
| 21 #include "base/threading/platform_thread.h" | 22 #include "base/threading/platform_thread.h" |
| 23 #include "base/timer/elapsed_timer.h" | |
| 22 #include "build/build_config.h" | 24 #include "build/build_config.h" |
| 23 #include "content/public/common/content_switches.h" | 25 #include "content/public/common/content_switches.h" |
| 24 #include "content/public/common/result_codes.h" | 26 #include "content/public/common/result_codes.h" |
| 25 | 27 |
| 26 #if defined(OS_WIN) | 28 #if defined(OS_WIN) |
| 27 #include <windows.h> | 29 #include <windows.h> |
| 28 #endif | 30 #endif |
| 29 | 31 |
| 30 namespace content { | 32 namespace content { |
| 31 namespace { | 33 namespace { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 44 timeout_(base::TimeDelta::FromMilliseconds(timeout)), | 46 timeout_(base::TimeDelta::FromMilliseconds(timeout)), |
| 45 armed_(false), | 47 armed_(false), |
| 46 task_observer_(this), | 48 task_observer_(this), |
| 47 use_thread_cpu_time_(true), | 49 use_thread_cpu_time_(true), |
| 48 responsive_acknowledge_count_(0), | 50 responsive_acknowledge_count_(0), |
| 49 #if defined(OS_WIN) | 51 #if defined(OS_WIN) |
| 50 watched_thread_handle_(0), | 52 watched_thread_handle_(0), |
| 51 arm_cpu_time_(), | 53 arm_cpu_time_(), |
| 52 #endif | 54 #endif |
| 53 suspended_(false), | 55 suspended_(false), |
| 56 use_temp_file_for_io_checking_(false), | |
| 54 #if defined(USE_X11) | 57 #if defined(USE_X11) |
| 55 display_(NULL), | 58 display_(NULL), |
| 56 window_(0), | 59 window_(0), |
| 57 atom_(None), | 60 atom_(None), |
| 58 #endif | 61 #endif |
| 59 weak_factory_(this) { | 62 weak_factory_(this) { |
| 60 DCHECK(timeout >= 0); | 63 DCHECK(timeout >= 0); |
| 61 | 64 |
| 62 #if defined(OS_WIN) | 65 #if defined(OS_WIN) |
| 63 // GetCurrentThread returns a pseudo-handle that cannot be used by one thread | 66 // GetCurrentThread returns a pseudo-handle that cannot be used by one thread |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 201 // Do not create any new termination tasks if one has already been created | 204 // Do not create any new termination tasks if one has already been created |
| 202 // or the system is suspended. | 205 // or the system is suspended. |
| 203 if (armed_ || suspended_) | 206 if (armed_ || suspended_) |
| 204 return; | 207 return; |
| 205 | 208 |
| 206 // Must set armed before posting the task. This task might be the only task | 209 // Must set armed before posting the task. This task might be the only task |
| 207 // that will activate the TaskObserver on the watched thread and it must not | 210 // that will activate the TaskObserver on the watched thread and it must not |
| 208 // miss the false -> true transition. | 211 // miss the false -> true transition. |
| 209 armed_ = true; | 212 armed_ = true; |
| 210 | 213 |
| 214 use_temp_file_for_io_checking_ = true; | |
| 215 | |
| 211 #if defined(OS_WIN) | 216 #if defined(OS_WIN) |
| 212 arm_cpu_time_ = GetWatchedThreadTime(); | 217 arm_cpu_time_ = GetWatchedThreadTime(); |
| 213 | 218 |
| 214 QueryUnbiasedInterruptTime(&arm_interrupt_time_); | 219 QueryUnbiasedInterruptTime(&arm_interrupt_time_); |
| 215 #endif | 220 #endif |
| 216 | 221 |
| 217 check_time_ = base::Time::Now(); | 222 check_time_ = base::Time::Now(); |
| 218 check_timeticks_ = base::TimeTicks::Now(); | 223 check_timeticks_ = base::TimeTicks::Now(); |
| 219 // Immediately after the computer is woken up from being suspended it might | 224 // Immediately after the computer is woken up from being suspended it might |
| 220 // be pretty sluggish, so allow some extra time before the next timeout. | 225 // be pretty sluggish, so allow some extra time before the next timeout. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 // If the watchdog woke up significantly behind schedule, disarm and reset | 265 // If the watchdog woke up significantly behind schedule, disarm and reset |
| 261 // the watchdog check. This is to prevent the watchdog thread from terminating | 266 // the watchdog check. This is to prevent the watchdog thread from terminating |
| 262 // when a machine wakes up from sleep or hibernation, which would otherwise | 267 // when a machine wakes up from sleep or hibernation, which would otherwise |
| 263 // appear to be a hang. | 268 // appear to be a hang. |
| 264 if (base::Time::Now() > suspension_timeout_) { | 269 if (base::Time::Now() > suspension_timeout_) { |
| 265 armed_ = false; | 270 armed_ = false; |
| 266 OnCheck(true); | 271 OnCheck(true); |
| 267 return; | 272 return; |
| 268 } | 273 } |
| 269 | 274 |
| 275 // If the watchdog woke up while there is a heavy I/O we want to give the | |
| 276 // machine a chance to clear the I/O queue before terminating the process. | |
| 277 if (use_temp_file_for_io_checking_) { | |
|
jbauman
2016/05/17 22:57:20
Instead of using a flag here, we should make this
stanisc
2016/05/18 00:01:30
Good point! I didn't realize that adding sandbox r
| |
| 278 base::File temp_file; | |
| 279 base::FilePath temp_dir_path; | |
| 280 if (GetTempDir(&temp_dir_path)) { | |
| 281 base::FilePath temp_file_path = temp_dir_path.Append(L"gpu-watchdog.tmp"); | |
| 282 // Please note that multiple instances of GPU process may reuse the same | |
| 283 // temporary file. That's OK because the file is written to only when | |
| 284 // the watchdog gets triggered and about to crash the process. The file | |
| 285 // should be deleted when the last handle is closed. | |
| 286 temp_file.Initialize( | |
|
jbauman
2016/05/17 22:57:20
We're not doing anything special with the sandbox
| |
| 287 temp_file_path, | |
| 288 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE | | |
| 289 base::File::FLAG_DELETE_ON_CLOSE | base::File::FLAG_SHARE_DELETE); | |
| 290 if (temp_file.IsValid()) { | |
| 291 // Write a few bytes and wait for the write to flush. | |
| 292 const char temp_data[32] = {0}; | |
| 293 base::ElapsedTimer timer; | |
| 294 temp_file.Write(0, temp_data, sizeof(temp_data)); | |
| 295 temp_file.Flush(); | |
| 296 io_check_duration_ = timer.Elapsed(); | |
| 297 | |
| 298 // Reset the flag and re-post this task to actually terminate unless | |
| 299 // acknowledge arrives in between. | |
| 300 use_temp_file_for_io_checking_ = false; | |
| 301 message_loop()->PostTask( | |
| 302 FROM_HERE, | |
| 303 base::Bind( | |
| 304 &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang, | |
| 305 weak_factory_.GetWeakPtr())); | |
| 306 return; | |
| 307 } | |
| 308 } | |
| 309 } | |
| 310 | |
| 270 #if defined(USE_X11) | 311 #if defined(USE_X11) |
| 271 XWindowAttributes attributes; | 312 XWindowAttributes attributes; |
| 272 XGetWindowAttributes(display_, window_, &attributes); | 313 XGetWindowAttributes(display_, window_, &attributes); |
| 273 | 314 |
| 274 XSelectInput(display_, window_, PropertyChangeMask); | 315 XSelectInput(display_, window_, PropertyChangeMask); |
| 275 SetupXChangeProp(); | 316 SetupXChangeProp(); |
| 276 | 317 |
| 277 XFlush(display_); | 318 XFlush(display_); |
| 278 | 319 |
| 279 // We wait for the property change event with a timeout. If it arrives we know | 320 // We wait for the property change event with a timeout. If it arrives we know |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 457 // calls into kernel level repeatedly, giving up its quanta before it is | 498 // calls into kernel level repeatedly, giving up its quanta before it is |
| 458 // tracked, for example a loop that repeatedly Sleeps. | 499 // tracked, for example a loop that repeatedly Sleeps. |
| 459 return base::ThreadTicks() + | 500 return base::ThreadTicks() + |
| 460 base::TimeDelta::FromMilliseconds(static_cast<int64_t>( | 501 base::TimeDelta::FromMilliseconds(static_cast<int64_t>( |
| 461 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000)); | 502 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000)); |
| 462 } | 503 } |
| 463 } | 504 } |
| 464 #endif | 505 #endif |
| 465 | 506 |
| 466 } // namespace content | 507 } // namespace content |
| OLD | NEW |