• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/watchdog.h"
6 
7 #include "base/compiler_specific.h"
8 #include "base/platform_thread.h"
9 
10 using base::TimeDelta;
11 using base::TimeTicks;
12 
13 //------------------------------------------------------------------------------
14 // Public API methods.
15 
16 // Start thread running in a Disarmed state.
Watchdog(const TimeDelta & duration,const std::string & thread_watched_name,bool enabled)17 Watchdog::Watchdog(const TimeDelta& duration,
18                    const std::string& thread_watched_name,
19                    bool enabled)
20   : init_successful_(false),
21     lock_(),
22     condition_variable_(&lock_),
23     state_(DISARMED),
24     duration_(duration),
25     thread_watched_name_(thread_watched_name),
26     ALLOW_THIS_IN_INITIALIZER_LIST(delegate_(this)) {
27   if (!enabled)
28     return;  // Don't start thread, or doing anything really.
29   init_successful_ = PlatformThread::Create(0,  // Default stack size.
30                                             &delegate_,
31                                             &handle_);
32   DCHECK(init_successful_);
33 }
34 
35 // Notify watchdog thread, and wait for it to finish up.
~Watchdog()36 Watchdog::~Watchdog() {
37   if (!init_successful_)
38     return;
39   {
40     AutoLock lock(lock_);
41     state_ = SHUTDOWN;
42   }
43   condition_variable_.Signal();
44   PlatformThread::Join(handle_);
45 }
46 
Arm()47 void Watchdog::Arm() {
48   ArmAtStartTime(TimeTicks::Now());
49 }
50 
ArmSomeTimeDeltaAgo(const TimeDelta & time_delta)51 void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) {
52   ArmAtStartTime(TimeTicks::Now() - time_delta);
53 }
54 
55 // Start clock for watchdog.
ArmAtStartTime(const TimeTicks start_time)56 void Watchdog::ArmAtStartTime(const TimeTicks start_time) {
57   {
58     AutoLock lock(lock_);
59     start_time_ = start_time;
60     state_ = ARMED;
61   }
62   // Force watchdog to wake up, and go to sleep with the timer ticking with the
63   // proper duration.
64   condition_variable_.Signal();
65 }
66 
67 // Disable watchdog so that it won't do anything when time expires.
Disarm()68 void Watchdog::Disarm() {
69   AutoLock lock(lock_);
70   state_ = DISARMED;
71   // We don't need to signal, as the watchdog will eventually wake up, and it
72   // will check its state and time, and act accordingly.
73 }
74 
75 //------------------------------------------------------------------------------
76 // Internal private methods that the watchdog thread uses.
77 
ThreadMain()78 void Watchdog::ThreadDelegate::ThreadMain() {
79   SetThreadName();
80   TimeDelta remaining_duration;
81   while (1) {
82     AutoLock lock(watchdog_->lock_);
83     while (DISARMED == watchdog_->state_)
84       watchdog_->condition_variable_.Wait();
85     if (SHUTDOWN == watchdog_->state_)
86       return;
87     DCHECK(ARMED == watchdog_->state_);
88     remaining_duration = watchdog_->duration_ -
89         (TimeTicks::Now() - watchdog_->start_time_);
90     if (remaining_duration.InMilliseconds() > 0) {
91       // Spurios wake?  Timer drifts?  Go back to sleep for remaining time.
92       watchdog_->condition_variable_.TimedWait(remaining_duration);
93       continue;
94     }
95     // We overslept, so this seems like a real alarm.
96     // Watch out for a user that stopped the debugger on a different alarm!
97     {
98       AutoLock static_lock(static_lock_);
99       if (last_debugged_alarm_time_ > watchdog_->start_time_) {
100         // False alarm: we started our clock before the debugger break (last
101         // alarm time).
102         watchdog_->start_time_ += last_debugged_alarm_delay_;
103         if (last_debugged_alarm_time_ > watchdog_->start_time_)
104           // Too many alarms must have taken place.
105           watchdog_->state_ = DISARMED;
106         continue;
107       }
108     }
109     watchdog_->state_ = DISARMED;  // Only alarm at most once.
110     TimeTicks last_alarm_time = TimeTicks::Now();
111     watchdog_->Alarm();  // Set a break point here to debug on alarms.
112     TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time;
113     if (last_alarm_delay <= TimeDelta::FromMilliseconds(2))
114       continue;
115     // Ignore race of two alarms/breaks going off at roughly the same time.
116     AutoLock static_lock(static_lock_);
117     // This was a real debugger break.
118     last_debugged_alarm_time_ = last_alarm_time;
119     last_debugged_alarm_delay_ = last_alarm_delay;
120   }
121 }
122 
SetThreadName() const123 void Watchdog::ThreadDelegate::SetThreadName() const {
124   std::string name = watchdog_->thread_watched_name_ + " Watchdog";
125   PlatformThread::SetName(name.c_str());
126   DLOG(INFO) << "Watchdog active: " << name;
127 }
128 
129 // static
ResetStaticData()130 void Watchdog::ResetStaticData() {
131   AutoLock lock(static_lock_);
132   last_debugged_alarm_time_ = TimeTicks();
133   last_debugged_alarm_delay_ = TimeDelta();
134 }
135 
136 // static
137 Lock Watchdog::static_lock_;  // Lock for access of static data...
138 // static
139 TimeTicks Watchdog::last_debugged_alarm_time_ = TimeTicks();
140 // static
141 TimeDelta Watchdog::last_debugged_alarm_delay_;
142