15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/watchdog.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When the debugger breaks (when we alarm), all the other alarms that are
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// armed will expire (also alarm).  To diminish this effect, we track any
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// delay due to debugger breaks, and we *try* to adjust the effective start
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// time of other alarms to step past the debugging break.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Without this safety net, any alarm will typically trigger a host of follow
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on alarms from callers that specify old times.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)struct StaticData {
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Lock for access of static data...
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Lock lock;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // When did we last alarm and get stuck (for a while) in a debugger?
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TimeTicks last_debugged_alarm_time;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // How long did we sit on a break in the debugger?
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TimeDelta last_debugged_alarm_delay;
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)LazyInstance<StaticData>::Leaky g_static_data = LAZY_INSTANCE_INITIALIZER;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start thread running in a Disarmed state.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Watchdog::Watchdog(const TimeDelta& duration,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   const std::string& thread_watched_name,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   bool enabled)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : enabled_(enabled),
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lock_(),
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    condition_variable_(&lock_),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_(DISARMED),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    duration_(duration),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_watched_name_(thread_watched_name),
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delegate_(this) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!enabled_)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Don't start thread, or doing anything really.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enabled_ = PlatformThread::Create(0,  // Default stack size.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &delegate_,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &handle_);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(enabled_);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Notify watchdog thread, and wait for it to finish up.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Watchdog::~Watchdog() {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!enabled_)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsJoinable())
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cleanup();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  condition_variable_.Signal();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PlatformThread::Join(handle_);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::Cleanup() {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!enabled_)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AutoLock lock(lock_);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = SHUTDOWN;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  condition_variable_.Signal();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Watchdog::IsJoinable() {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!enabled_)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(lock_);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (state_ == JOINABLE);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::Arm() {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ArmAtStartTime(TimeTicks::Now());
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ArmAtStartTime(TimeTicks::Now() - time_delta);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start clock for watchdog.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ArmAtStartTime(const TimeTicks start_time) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AutoLock lock(lock_);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start_time_ = start_time;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = ARMED;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force watchdog to wake up, and go to sleep with the timer ticking with the
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // proper duration.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  condition_variable_.Signal();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Disable watchdog so that it won't do anything when time expires.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::Disarm() {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(lock_);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = DISARMED;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't need to signal, as the watchdog will eventually wake up, and it
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will check its state and time, and act accordingly.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::Alarm() {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Watchdog alarmed for " << thread_watched_name_;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Internal private methods that the watchdog thread uses.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ThreadDelegate::ThreadMain() {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetThreadName();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeDelta remaining_duration;
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  StaticData* static_data = g_static_data.Pointer();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (1) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AutoLock lock(watchdog_->lock_);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (DISARMED == watchdog_->state_)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      watchdog_->condition_variable_.Wait();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (SHUTDOWN == watchdog_->state_) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      watchdog_->state_ = JOINABLE;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(ARMED == watchdog_->state_);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remaining_duration = watchdog_->duration_ -
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (TimeTicks::Now() - watchdog_->start_time_);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (remaining_duration.InMilliseconds() > 0) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Spurios wake?  Timer drifts?  Go back to sleep for remaining time.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      watchdog_->condition_variable_.TimedWait(remaining_duration);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We overslept, so this seems like a real alarm.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Watch out for a user that stopped the debugger on a different alarm!
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      AutoLock static_lock(static_data->lock);
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (static_data->last_debugged_alarm_time > watchdog_->start_time_) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // False alarm: we started our clock before the debugger break (last
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // alarm time).
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        watchdog_->start_time_ += static_data->last_debugged_alarm_delay;
147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (static_data->last_debugged_alarm_time > watchdog_->start_time_)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Too many alarms must have taken place.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          watchdog_->state_ = DISARMED;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    watchdog_->state_ = DISARMED;  // Only alarm at most once.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TimeTicks last_alarm_time = TimeTicks::Now();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AutoUnlock lock(watchdog_->lock_);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      watchdog_->Alarm();  // Set a break point here to debug on alarms.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (last_alarm_delay <= TimeDelta::FromMilliseconds(2))
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ignore race of two alarms/breaks going off at roughly the same time.
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    AutoLock static_lock(static_data->lock);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This was a real debugger break.
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    static_data->last_debugged_alarm_time = last_alarm_time;
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    static_data->last_debugged_alarm_delay = last_alarm_delay;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ThreadDelegate::SetThreadName() const {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string name = watchdog_->thread_watched_name_ + " Watchdog";
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PlatformThread::SetName(name.c_str());
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Watchdog active: " << name;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ResetStaticData() {
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  StaticData* static_data = g_static_data.Pointer();
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  AutoLock lock(static_data->lock);
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static_data->last_debugged_alarm_time = TimeTicks();
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  static_data->last_debugged_alarm_delay = TimeDelta();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
185