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