OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/gpu/gpu_watchdog_thread.h" | 9 #include "chrome/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 |
| 17 void DoNothing() { |
| 18 } |
16 } | 19 } |
17 | 20 |
18 GpuWatchdogThread::GpuWatchdogThread(MessageLoop* watched_message_loop, | 21 GpuWatchdogThread::GpuWatchdogThread(MessageLoop* watched_message_loop, |
19 int timeout) | 22 int timeout) |
20 : base::Thread("Watchdog"), | 23 : base::Thread("Watchdog"), |
21 watched_message_loop_(watched_message_loop), | 24 watched_message_loop_(watched_message_loop), |
22 timeout_(timeout) { | 25 timeout_(timeout), |
| 26 armed_(false), |
| 27 ALLOW_THIS_IN_INITIALIZER_LIST(task_observer_(this)) { |
23 DCHECK(watched_message_loop); | 28 DCHECK(watched_message_loop); |
24 DCHECK(timeout >= 0); | 29 DCHECK(timeout >= 0); |
| 30 |
| 31 watched_message_loop_->AddTaskObserver(&task_observer_); |
25 } | 32 } |
26 | 33 |
27 GpuWatchdogThread::~GpuWatchdogThread() { | 34 GpuWatchdogThread::~GpuWatchdogThread() { |
28 // Verify that the thread was explicitly stopped. If the thread is stopped | 35 // Verify that the thread was explicitly stopped. If the thread is stopped |
29 // implicitly by the destructor, CleanUp() will not be called. | 36 // implicitly by the destructor, CleanUp() will not be called. |
30 DCHECK(!method_factory_.get()); | 37 DCHECK(!method_factory_.get()); |
| 38 |
| 39 watched_message_loop_->RemoveTaskObserver(&task_observer_); |
| 40 } |
| 41 |
| 42 void GpuWatchdogThread::PostAcknowledge() { |
| 43 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use |
| 44 // the method factory. Rely on reference counting instead. |
| 45 message_loop()->PostTask( |
| 46 FROM_HERE, |
| 47 NewRunnableMethod(this, &GpuWatchdogThread::OnAcknowledge)); |
31 } | 48 } |
32 | 49 |
33 void GpuWatchdogThread::Init() { | 50 void GpuWatchdogThread::Init() { |
34 // The method factory must be created on the watchdog thread. | 51 // The method factory must be created on the watchdog thread. |
35 method_factory_.reset(new MethodFactory(this)); | 52 method_factory_.reset(new MethodFactory(this)); |
36 | 53 |
37 // Schedule the first check. | 54 // Schedule the first check. |
38 OnCheck(); | 55 OnCheck(); |
39 } | 56 } |
40 | 57 |
41 void GpuWatchdogThread::CleanUp() { | 58 void GpuWatchdogThread::CleanUp() { |
42 // The method factory must be destroyed on the watchdog thread. | 59 // The method factory must be destroyed on the watchdog thread. |
43 method_factory_->RevokeAll(); | 60 method_factory_->RevokeAll(); |
44 method_factory_.reset(); | 61 method_factory_.reset(); |
45 | 62 |
46 // Prevent any more delayed tasks from being posted. | 63 // Prevent any more delayed tasks from being posted. |
47 watched_message_loop_ = NULL; | 64 watched_message_loop_ = NULL; |
48 } | 65 } |
49 | 66 |
| 67 GpuWatchdogThread::GpuWatchdogTaskObserver::GpuWatchdogTaskObserver( |
| 68 GpuWatchdogThread* watchdog) |
| 69 : watchdog_(watchdog) { |
| 70 } |
| 71 |
| 72 GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() { |
| 73 } |
| 74 |
| 75 void GpuWatchdogThread::GpuWatchdogTaskObserver::WillProcessTask( |
| 76 const Task* task) |
| 77 { |
| 78 CheckArmed(); |
| 79 } |
| 80 |
| 81 void GpuWatchdogThread::GpuWatchdogTaskObserver::DidProcessTask( |
| 82 const Task* task) |
| 83 { |
| 84 CheckArmed(); |
| 85 } |
| 86 |
| 87 void GpuWatchdogThread::GpuWatchdogTaskObserver::CheckArmed() |
| 88 { |
| 89 // Acknowledge the watchdog if it has armed itself. The watchdog will not |
| 90 // change its armed state until it is acknowledged. |
| 91 if (watchdog_->armed()) { |
| 92 watchdog_->PostAcknowledge(); |
| 93 } |
| 94 } |
| 95 |
50 void GpuWatchdogThread::OnAcknowledge() { | 96 void GpuWatchdogThread::OnAcknowledge() { |
| 97 // The check has already been acknowledged and another has already been |
| 98 // scheduled by a previous call to OnAcknowledge. It is normal for a |
| 99 // watched thread to see armed_ being true multiple times before |
| 100 // the OnAcknowledge task is run on the watchdog thread. |
| 101 if (!armed_) |
| 102 return; |
| 103 |
51 // Revoke any pending OnExit. | 104 // Revoke any pending OnExit. |
52 method_factory_->RevokeAll(); | 105 method_factory_->RevokeAll(); |
| 106 armed_ = false; |
53 | 107 |
54 // The monitored thread has responded. Post a task to check it again. | 108 // The monitored thread has responded. Post a task to check it again. |
55 if (watched_message_loop_) { | 109 if (watched_message_loop_) { |
56 message_loop()->PostDelayedTask( | 110 message_loop()->PostDelayedTask( |
57 FROM_HERE, | 111 FROM_HERE, |
58 method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnCheck), | 112 method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnCheck), |
59 kCheckPeriod); | 113 kCheckPeriod); |
60 } | 114 } |
61 } | 115 } |
62 | 116 |
63 void GpuWatchdogThread::OnCheck() { | 117 void GpuWatchdogThread::OnCheck() { |
64 if (watched_message_loop_) { | 118 if (watched_message_loop_) { |
65 // Post a task to the monitored thread that simply responds with a task that | 119 // Must set armed before posting the task. This task might be the only task |
66 // calls OnAcknowldge. | 120 // that will activate the TaskObserver on the watched thread and it must not |
| 121 // miss the false -> true transition. |
| 122 armed_ = true; |
| 123 |
| 124 // Post a task to the monitored thread that does nothing but wake up the |
| 125 // TaskObserver. Any other tasks that are pending on the watched thread will |
| 126 // also wake up the observer. This simply ensures there is at least one. |
67 watched_message_loop_->PostTask( | 127 watched_message_loop_->PostTask( |
68 FROM_HERE, | 128 FROM_HERE, |
69 NewRunnableMethod(this, &GpuWatchdogThread::PostAcknowledge)); | 129 NewRunnableFunction(DoNothing)); |
70 | 130 |
71 // Post a task to the watchdog thread to exit if the nmonitored thread does | 131 // Post a task to the watchdog thread to exit if the monitored thread does |
72 // not respond in time. | 132 // not respond in time. |
73 message_loop()->PostDelayedTask( | 133 message_loop()->PostDelayedTask( |
74 FROM_HERE, | 134 FROM_HERE, |
75 method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnExit), | 135 method_factory_->NewRunnableMethod(&GpuWatchdogThread::OnExit), |
76 timeout_); | 136 timeout_); |
77 } | 137 } |
78 } | 138 } |
79 | 139 |
80 void GpuWatchdogThread::PostAcknowledge() { | |
81 // Called on the monitored thread. Responds with OnAcknowledge. Cannot use | |
82 // the method factory. Rely on reference counting instead. | |
83 message_loop()->PostTask( | |
84 FROM_HERE, | |
85 NewRunnableMethod(this, &GpuWatchdogThread::OnAcknowledge)); | |
86 } | |
87 | |
88 // Use the --disable-gpu-watchdog command line switch to disable this. | 140 // Use the --disable-gpu-watchdog command line switch to disable this. |
89 void GpuWatchdogThread::OnExit() { | 141 void GpuWatchdogThread::OnExit() { |
90 // Make sure the timeout period is on the stack before crashing. | 142 // Make sure the timeout period is on the stack before crashing. |
91 volatile int timeout = timeout_; | 143 volatile int timeout = timeout_; |
92 | 144 |
93 // For minimal developer annoyance, don't keep crashing. | 145 // For minimal developer annoyance, don't keep crashing. |
94 static bool crashed = false; | 146 static bool crashed = false; |
95 if (crashed) | 147 if (crashed) |
96 return; | 148 return; |
97 | 149 |
98 #if defined(OS_WIN) | 150 #if defined(OS_WIN) |
99 if (IsDebuggerPresent()) | 151 if (IsDebuggerPresent()) |
100 return; | 152 return; |
101 #endif | 153 #endif |
102 | 154 |
103 LOG(ERROR) << "The GPU process hung. Restarting after " | 155 LOG(ERROR) << "The GPU process hung. Restarting after " |
104 << timeout_ << " seconds."; | 156 << timeout_ << " seconds."; |
105 | 157 |
106 volatile int* null_pointer = NULL; | 158 volatile int* null_pointer = NULL; |
107 *null_pointer = timeout; | 159 *null_pointer = timeout; |
108 | 160 |
109 crashed = true; | 161 crashed = true; |
110 } | 162 } |
OLD | NEW |