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 |