| 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 #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 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 &watched_thread_handle_, | 43 &watched_thread_handle_, |
| 44 THREAD_QUERY_INFORMATION, | 44 THREAD_QUERY_INFORMATION, |
| 45 FALSE, | 45 FALSE, |
| 46 0); | 46 0); |
| 47 DCHECK(result); | 47 DCHECK(result); |
| 48 #endif | 48 #endif |
| 49 | 49 |
| 50 watched_message_loop_->AddTaskObserver(&task_observer_); | 50 watched_message_loop_->AddTaskObserver(&task_observer_); |
| 51 } | 51 } |
| 52 | 52 |
| 53 GpuWatchdogThread::~GpuWatchdogThread() { | |
| 54 // Verify that the thread was explicitly stopped. If the thread is stopped | |
| 55 // implicitly by the destructor, CleanUp() will not be called. | |
| 56 DCHECK(!weak_factory_.HasWeakPtrs()); | |
| 57 | |
| 58 #if defined(OS_WIN) | |
| 59 CloseHandle(watched_thread_handle_); | |
| 60 #endif | |
| 61 | |
| 62 watched_message_loop_->RemoveTaskObserver(&task_observer_); | |
| 63 } | |
| 64 | |
| 65 void GpuWatchdogThread::PostAcknowledge() { | 53 void GpuWatchdogThread::PostAcknowledge() { |
| 66 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use | 54 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use |
| 67 // the method factory. Rely on reference counting instead. | 55 // the method factory. Rely on reference counting instead. |
| 68 message_loop()->PostTask( | 56 message_loop()->PostTask( |
| 69 FROM_HERE, | 57 FROM_HERE, |
| 70 base::Bind(&GpuWatchdogThread::OnAcknowledge, this)); | 58 base::Bind(&GpuWatchdogThread::OnAcknowledge, this)); |
| 71 } | 59 } |
| 72 | 60 |
| 61 void GpuWatchdogThread::CheckArmed() { |
| 62 // Acknowledge the watchdog if it has armed itself. The watchdog will not |
| 63 // change its armed state until it is acknowledged. |
| 64 if (armed()) { |
| 65 PostAcknowledge(); |
| 66 } |
| 67 } |
| 68 |
| 73 void GpuWatchdogThread::Init() { | 69 void GpuWatchdogThread::Init() { |
| 74 // Schedule the first check. | 70 // Schedule the first check. |
| 75 OnCheck(); | 71 OnCheck(); |
| 76 } | 72 } |
| 77 | 73 |
| 78 void GpuWatchdogThread::CleanUp() { | 74 void GpuWatchdogThread::CleanUp() { |
| 79 weak_factory_.InvalidateWeakPtrs(); | 75 weak_factory_.InvalidateWeakPtrs(); |
| 80 } | 76 } |
| 81 | 77 |
| 82 GpuWatchdogThread::GpuWatchdogTaskObserver::GpuWatchdogTaskObserver( | 78 GpuWatchdogThread::GpuWatchdogTaskObserver::GpuWatchdogTaskObserver( |
| 83 GpuWatchdogThread* watchdog) | 79 GpuWatchdogThread* watchdog) |
| 84 : watchdog_(watchdog) { | 80 : watchdog_(watchdog) { |
| 85 } | 81 } |
| 86 | 82 |
| 87 GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() { | 83 GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() { |
| 88 } | 84 } |
| 89 | 85 |
| 90 void GpuWatchdogThread::GpuWatchdogTaskObserver::WillProcessTask( | 86 void GpuWatchdogThread::GpuWatchdogTaskObserver::WillProcessTask( |
| 91 base::TimeTicks time_posted) { | 87 base::TimeTicks time_posted) { |
| 92 watchdog_->CheckArmed(); | 88 watchdog_->CheckArmed(); |
| 93 } | 89 } |
| 94 | 90 |
| 95 void GpuWatchdogThread::GpuWatchdogTaskObserver::DidProcessTask( | 91 void GpuWatchdogThread::GpuWatchdogTaskObserver::DidProcessTask( |
| 96 base::TimeTicks time_posted) { | 92 base::TimeTicks time_posted) { |
| 97 watchdog_->CheckArmed(); | 93 watchdog_->CheckArmed(); |
| 98 } | 94 } |
| 99 | 95 |
| 100 void GpuWatchdogThread::CheckArmed() { | 96 GpuWatchdogThread::~GpuWatchdogThread() { |
| 101 // Acknowledge the watchdog if it has armed itself. The watchdog will not | 97 // Verify that the thread was explicitly stopped. If the thread is stopped |
| 102 // change its armed state until it is acknowledged. | 98 // implicitly by the destructor, CleanUp() will not be called. |
| 103 if (armed()) { | 99 DCHECK(!weak_factory_.HasWeakPtrs()); |
| 104 PostAcknowledge(); | 100 |
| 105 } | 101 #if defined(OS_WIN) |
| 102 CloseHandle(watched_thread_handle_); |
| 103 #endif |
| 104 |
| 105 watched_message_loop_->RemoveTaskObserver(&task_observer_); |
| 106 } | 106 } |
| 107 | 107 |
| 108 void GpuWatchdogThread::OnAcknowledge() { | 108 void GpuWatchdogThread::OnAcknowledge() { |
| 109 // The check has already been acknowledged and another has already been | 109 // The check has already been acknowledged and another has already been |
| 110 // scheduled by a previous call to OnAcknowledge. It is normal for a | 110 // scheduled by a previous call to OnAcknowledge. It is normal for a |
| 111 // watched thread to see armed_ being true multiple times before | 111 // watched thread to see armed_ being true multiple times before |
| 112 // the OnAcknowledge task is run on the watchdog thread. | 112 // the OnAcknowledge task is run on the watchdog thread. |
| 113 if (!armed_) | 113 if (!armed_) |
| 114 return; | 114 return; |
| 115 | 115 |
| 116 // Revoke any pending hang termination. | 116 // Revoke any pending hang termination. |
| 117 weak_factory_.InvalidateWeakPtrs(); | 117 weak_factory_.InvalidateWeakPtrs(); |
| 118 armed_ = false; | 118 armed_ = false; |
| 119 | 119 |
| 120 // The monitored thread has responded. Post a task to check it again. | 120 // The monitored thread has responded. Post a task to check it again. |
| 121 message_loop()->PostDelayedTask( | 121 message_loop()->PostDelayedTask( |
| 122 FROM_HERE, | 122 FROM_HERE, |
| 123 base::Bind(&GpuWatchdogThread::OnCheck, weak_factory_.GetWeakPtr()), | 123 base::Bind(&GpuWatchdogThread::OnCheck, weak_factory_.GetWeakPtr()), |
| 124 base::TimeDelta::FromMilliseconds(kCheckPeriodMs)); | 124 base::TimeDelta::FromMilliseconds(kCheckPeriodMs)); |
| 125 } | 125 } |
| 126 | 126 |
| 127 #if defined(OS_WIN) | |
| 128 base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() { | |
| 129 FILETIME creation_time; | |
| 130 FILETIME exit_time; | |
| 131 FILETIME user_time; | |
| 132 FILETIME kernel_time; | |
| 133 BOOL result = GetThreadTimes(watched_thread_handle_, | |
| 134 &creation_time, | |
| 135 &exit_time, | |
| 136 &kernel_time, | |
| 137 &user_time); | |
| 138 DCHECK(result); | |
| 139 | |
| 140 ULARGE_INTEGER user_time64; | |
| 141 user_time64.HighPart = user_time.dwHighDateTime; | |
| 142 user_time64.LowPart = user_time.dwLowDateTime; | |
| 143 | |
| 144 ULARGE_INTEGER kernel_time64; | |
| 145 kernel_time64.HighPart = kernel_time.dwHighDateTime; | |
| 146 kernel_time64.LowPart = kernel_time.dwLowDateTime; | |
| 147 | |
| 148 // Time is reported in units of 100 nanoseconds. Kernel and user time are | |
| 149 // summed to deal with to kinds of hangs. One is where the GPU process is | |
| 150 // stuck in user level, never calling into the kernel and kernel time is | |
| 151 // not increasing. The other is where either the kernel hangs and never | |
| 152 // returns to user level or where user level code | |
| 153 // calls into kernel level repeatedly, giving up its quanta before it is | |
| 154 // tracked, for example a loop that repeatedly Sleeps. | |
| 155 return base::TimeDelta::FromMilliseconds(static_cast<int64>( | |
| 156 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000)); | |
| 157 } | |
| 158 #endif | |
| 159 | |
| 160 void GpuWatchdogThread::OnCheck() { | 127 void GpuWatchdogThread::OnCheck() { |
| 161 if (armed_) | 128 if (armed_) |
| 162 return; | 129 return; |
| 163 | 130 |
| 164 // Must set armed before posting the task. This task might be the only task | 131 // Must set armed before posting the task. This task might be the only task |
| 165 // that will activate the TaskObserver on the watched thread and it must not | 132 // that will activate the TaskObserver on the watched thread and it must not |
| 166 // miss the false -> true transition. | 133 // miss the false -> true transition. |
| 167 armed_ = true; | 134 armed_ = true; |
| 168 | 135 |
| 169 #if defined(OS_WIN) | 136 #if defined(OS_WIN) |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 #endif | 196 #endif |
| 230 | 197 |
| 231 LOG(ERROR) << "The GPU process hung. Terminating after " | 198 LOG(ERROR) << "The GPU process hung. Terminating after " |
| 232 << timeout_.InMilliseconds() << " ms."; | 199 << timeout_.InMilliseconds() << " ms."; |
| 233 | 200 |
| 234 base::Process current_process(base::GetCurrentProcessHandle()); | 201 base::Process current_process(base::GetCurrentProcessHandle()); |
| 235 current_process.Terminate(content::RESULT_CODE_HUNG); | 202 current_process.Terminate(content::RESULT_CODE_HUNG); |
| 236 | 203 |
| 237 terminated = true; | 204 terminated = true; |
| 238 } | 205 } |
| 206 |
| 207 #if defined(OS_WIN) |
| 208 base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() { |
| 209 FILETIME creation_time; |
| 210 FILETIME exit_time; |
| 211 FILETIME user_time; |
| 212 FILETIME kernel_time; |
| 213 BOOL result = GetThreadTimes(watched_thread_handle_, |
| 214 &creation_time, |
| 215 &exit_time, |
| 216 &kernel_time, |
| 217 &user_time); |
| 218 DCHECK(result); |
| 219 |
| 220 ULARGE_INTEGER user_time64; |
| 221 user_time64.HighPart = user_time.dwHighDateTime; |
| 222 user_time64.LowPart = user_time.dwLowDateTime; |
| 223 |
| 224 ULARGE_INTEGER kernel_time64; |
| 225 kernel_time64.HighPart = kernel_time.dwHighDateTime; |
| 226 kernel_time64.LowPart = kernel_time.dwLowDateTime; |
| 227 |
| 228 // Time is reported in units of 100 nanoseconds. Kernel and user time are |
| 229 // summed to deal with to kinds of hangs. One is where the GPU process is |
| 230 // stuck in user level, never calling into the kernel and kernel time is |
| 231 // not increasing. The other is where either the kernel hangs and never |
| 232 // returns to user level or where user level code |
| 233 // calls into kernel level repeatedly, giving up its quanta before it is |
| 234 // tracked, for example a loop that repeatedly Sleeps. |
| 235 return base::TimeDelta::FromMilliseconds(static_cast<int64>( |
| 236 (user_time64.QuadPart + kernel_time64.QuadPart) / 10000)); |
| 237 } |
| 238 #endif |
| OLD | NEW |