| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/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(int timeout) | 21 GpuWatchdogThread::GpuWatchdogThread(int timeout) |
| 22 : base::Thread("Watchdog"), | 22 : base::Thread("Watchdog"), |
| 23 watched_message_loop_(MessageLoop::current()), | 23 watched_message_loop_(MessageLoop::current()), |
| 24 timeout_(timeout), | 24 timeout_(timeout), |
| 25 armed_(false), | 25 armed_(false), |
| 26 #if defined(OS_WIN) | 26 #if defined(OS_WIN) |
| 27 watched_thread_handle_(0), | 27 watched_thread_handle_(0), |
| 28 arm_cpu_time_(0), | 28 arm_cpu_time_(0), |
| 29 #endif | 29 #endif |
| 30 ALLOW_THIS_IN_INITIALIZER_LIST(task_observer_(this)) { | 30 ALLOW_THIS_IN_INITIALIZER_LIST(closure_observer_(this)) { |
| 31 DCHECK(timeout >= 0); | 31 DCHECK(timeout >= 0); |
| 32 | 32 |
| 33 #if defined(OS_WIN) | 33 #if defined(OS_WIN) |
| 34 // GetCurrentThread returns a pseudo-handle that cannot be used by one thread | 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 | 35 // to identify another. DuplicateHandle creates a "real" handle that can be |
| 36 // used for this purpose. | 36 // used for this purpose. |
| 37 BOOL result = DuplicateHandle(GetCurrentProcess(), | 37 BOOL result = DuplicateHandle(GetCurrentProcess(), |
| 38 GetCurrentThread(), | 38 GetCurrentThread(), |
| 39 GetCurrentProcess(), | 39 GetCurrentProcess(), |
| 40 &watched_thread_handle_, | 40 &watched_thread_handle_, |
| 41 THREAD_QUERY_INFORMATION, | 41 THREAD_QUERY_INFORMATION, |
| 42 FALSE, | 42 FALSE, |
| 43 0); | 43 0); |
| 44 DCHECK(result); | 44 DCHECK(result); |
| 45 #endif | 45 #endif |
| 46 | 46 |
| 47 watched_message_loop_->AddTaskObserver(&task_observer_); | 47 watched_message_loop_->AddClosureObserver(&closure_observer_); |
| 48 } | 48 } |
| 49 | 49 |
| 50 GpuWatchdogThread::~GpuWatchdogThread() { | 50 GpuWatchdogThread::~GpuWatchdogThread() { |
| 51 // 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 |
| 52 // implicitly by the destructor, CleanUp() will not be called. | 52 // implicitly by the destructor, CleanUp() will not be called. |
| 53 DCHECK(!method_factory_.get()); | 53 DCHECK(!method_factory_.get()); |
| 54 | 54 |
| 55 #if defined(OS_WIN) | 55 #if defined(OS_WIN) |
| 56 CloseHandle(watched_thread_handle_); | 56 CloseHandle(watched_thread_handle_); |
| 57 #endif | 57 #endif |
| 58 | 58 |
| 59 watched_message_loop_->RemoveTaskObserver(&task_observer_); | 59 watched_message_loop_->RemoveClosureObserver(&closure_observer_); |
| 60 } | 60 } |
| 61 | 61 |
| 62 void GpuWatchdogThread::PostAcknowledge() { | 62 void GpuWatchdogThread::PostAcknowledge() { |
| 63 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use | 63 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use |
| 64 // the method factory. Rely on reference counting instead. | 64 // the method factory. Rely on reference counting instead. |
| 65 message_loop()->PostTask( | 65 message_loop()->PostTask( |
| 66 FROM_HERE, | 66 FROM_HERE, |
| 67 NewRunnableMethod(this, &GpuWatchdogThread::OnAcknowledge)); | 67 NewRunnableMethod(this, &GpuWatchdogThread::OnAcknowledge)); |
| 68 } | 68 } |
| 69 | 69 |
| 70 void GpuWatchdogThread::Init() { | 70 void GpuWatchdogThread::Init() { |
| 71 // The method factory must be created on the watchdog thread. | 71 // The method factory must be created on the watchdog thread. |
| 72 method_factory_.reset(new MethodFactory(this)); | 72 method_factory_.reset(new MethodFactory(this)); |
| 73 | 73 |
| 74 // Schedule the first check. | 74 // Schedule the first check. |
| 75 OnCheck(); | 75 OnCheck(); |
| 76 } | 76 } |
| 77 | 77 |
| 78 void GpuWatchdogThread::CleanUp() { | 78 void GpuWatchdogThread::CleanUp() { |
| 79 // The method factory must be destroyed on the watchdog thread. | 79 // The method factory must be destroyed on the watchdog thread. |
| 80 method_factory_->RevokeAll(); | 80 method_factory_->RevokeAll(); |
| 81 method_factory_.reset(); | 81 method_factory_.reset(); |
| 82 } | 82 } |
| 83 | 83 |
| 84 GpuWatchdogThread::GpuWatchdogTaskObserver::GpuWatchdogTaskObserver( | 84 GpuWatchdogThread::GpuWatchdogClosureObserver::GpuWatchdogClosureObserver( |
| 85 GpuWatchdogThread* watchdog) | 85 GpuWatchdogThread* watchdog) |
| 86 : watchdog_(watchdog) { | 86 : watchdog_(watchdog) { |
| 87 } | 87 } |
| 88 | 88 |
| 89 GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() { | 89 GpuWatchdogThread::GpuWatchdogClosureObserver::~GpuWatchdogClosureObserver() { |
| 90 } | 90 } |
| 91 | 91 |
| 92 void GpuWatchdogThread::GpuWatchdogTaskObserver::WillProcessTask( | 92 void GpuWatchdogThread::GpuWatchdogClosureObserver::WillProcessClosure( |
| 93 const Task* task) | 93 base::TimeTicks time_posted) { |
| 94 { | |
| 95 CheckArmed(); | 94 CheckArmed(); |
| 96 } | 95 } |
| 97 | 96 |
| 98 void GpuWatchdogThread::GpuWatchdogTaskObserver::DidProcessTask( | 97 void GpuWatchdogThread::GpuWatchdogClosureObserver::DidProcessClosure( |
| 99 const Task* task) | 98 base::TimeTicks time_posted) { |
| 100 { | |
| 101 CheckArmed(); | 99 CheckArmed(); |
| 102 } | 100 } |
| 103 | 101 |
| 104 void GpuWatchdogThread::GpuWatchdogTaskObserver::CheckArmed() | 102 void GpuWatchdogThread::GpuWatchdogClosureObserver::CheckArmed() { |
| 105 { | |
| 106 // Acknowledge the watchdog if it has armed itself. The watchdog will not | 103 // Acknowledge the watchdog if it has armed itself. The watchdog will not |
| 107 // change its armed state until it is acknowledged. | 104 // change its armed state until it is acknowledged. |
| 108 if (watchdog_->armed()) { | 105 if (watchdog_->armed()) { |
| 109 watchdog_->PostAcknowledge(); | 106 watchdog_->PostAcknowledge(); |
| 110 } | 107 } |
| 111 } | 108 } |
| 112 | 109 |
| 113 void GpuWatchdogThread::OnAcknowledge() { | 110 void GpuWatchdogThread::OnAcknowledge() { |
| 114 // The check has already been acknowledged and another has already been | 111 // The check has already been acknowledged and another has already been |
| 115 // scheduled by a previous call to OnAcknowledge. It is normal for a | 112 // scheduled by a previous call to OnAcknowledge. It is normal for a |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 return static_cast<int64>( | 157 return static_cast<int64>( |
| 161 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000); | 158 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000); |
| 162 } | 159 } |
| 163 #endif | 160 #endif |
| 164 | 161 |
| 165 void GpuWatchdogThread::OnCheck() { | 162 void GpuWatchdogThread::OnCheck() { |
| 166 if (armed_) | 163 if (armed_) |
| 167 return; | 164 return; |
| 168 | 165 |
| 169 // Must set armed before posting the task. This task might be the only task | 166 // Must set armed before posting the task. This task might be the only task |
| 170 // that will activate the TaskObserver on the watched thread and it must not | 167 // that will activate the ClosureObserver on the watched thread and it must |
| 171 // miss the false -> true transition. | 168 // not miss the false -> true transition. |
| 172 armed_ = true; | 169 armed_ = true; |
| 173 | 170 |
| 174 #if defined(OS_WIN) | 171 #if defined(OS_WIN) |
| 175 arm_cpu_time_ = GetWatchedThreadTime(); | 172 arm_cpu_time_ = GetWatchedThreadTime(); |
| 176 #endif | 173 #endif |
| 177 | 174 |
| 178 arm_absolute_time_ = base::Time::Now(); | 175 arm_absolute_time_ = base::Time::Now(); |
| 179 | 176 |
| 180 // Post a task to the monitored thread that does nothing but wake up the | 177 // Post a task to the monitored thread that does nothing but wake up the |
| 181 // TaskObserver. Any other tasks that are pending on the watched thread will | 178 // ClosureObserver. Any other tasks that are pending on the watched thread |
| 182 // also wake up the observer. This simply ensures there is at least one. | 179 // will also wake up the observer. This simply ensures there is at least one. |
| 183 watched_message_loop_->PostTask( | 180 watched_message_loop_->PostTask( |
| 184 FROM_HERE, | 181 FROM_HERE, |
| 185 NewRunnableFunction(DoNothing)); | 182 NewRunnableFunction(DoNothing)); |
| 186 | 183 |
| 187 // Post a task to the watchdog thread to exit if the monitored thread does | 184 // Post a task to the watchdog thread to exit if the monitored thread does |
| 188 // not respond in time. | 185 // not respond in time. |
| 189 message_loop()->PostDelayedTask( | 186 message_loop()->PostDelayedTask( |
| 190 FROM_HERE, | 187 FROM_HERE, |
| 191 method_factory_->NewRunnableMethod( | 188 method_factory_->NewRunnableMethod( |
| 192 &GpuWatchdogThread::DeliberatelyCrashingToRecoverFromHang), | 189 &GpuWatchdogThread::DeliberatelyCrashingToRecoverFromHang), |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 #endif | 231 #endif |
| 235 | 232 |
| 236 LOG(ERROR) << "The GPU process hung. Terminating after " | 233 LOG(ERROR) << "The GPU process hung. Terminating after " |
| 237 << timeout_ << " ms."; | 234 << timeout_ << " ms."; |
| 238 | 235 |
| 239 volatile int* null_pointer = NULL; | 236 volatile int* null_pointer = NULL; |
| 240 *null_pointer = timeout; | 237 *null_pointer = timeout; |
| 241 | 238 |
| 242 crashed = true; | 239 crashed = true; |
| 243 } | 240 } |
| OLD | NEW |