Home | History | Annotate | Download | only in base
      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.
     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.
     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 
     47 void Watchdog::Arm() {
     48   ArmAtStartTime(TimeTicks::Now());
     49 }
     50 
     51 void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) {
     52   ArmAtStartTime(TimeTicks::Now() - time_delta);
     53 }
     54 
     55 // Start clock for watchdog.
     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.
     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 
     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 
    123 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
    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