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