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