| 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 |