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 |