• 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 // The Watchdog class creates a second thread that can Alarm if a specific
6 // duration of time passes without proper attention.  The duration of time is
7 // specified at construction time.  The Watchdog may be used many times by
8 // simply calling Arm() (to start timing) and Disarm() (to reset the timer).
9 // The Watchdog is typically used under a debugger, where the stack traces on
10 // other threads can be examined if/when the Watchdog alarms.
11 
12 // Some watchdogs will be enabled or disabled via command line switches. To
13 // facilitate such code, an "enabled" argument for the constuctor can be used
14 // to permanently disable the watchdog.  Disabled watchdogs don't even spawn
15 // a second thread, and their methods call (Arm() and Disarm()) return very
16 // quickly.
17 
18 #ifndef BASE_WATCHDOG_H__
19 #define BASE_WATCHDOG_H__
20 
21 #include <string>
22 
23 #include "base/condition_variable.h"
24 #include "base/lock.h"
25 #include "base/logging.h"
26 #include "base/platform_thread.h"
27 #include "base/time.h"
28 
29 class Watchdog {
30  public:
31   // Constructor specifies how long the Watchdog will wait before alarming.
32   Watchdog(const base::TimeDelta& duration,
33            const std::string& thread_watched_name,
34            bool enabled);
35   virtual ~Watchdog();
36 
37   // Start timing, and alarm when time expires (unless we're disarm()ed.)
38   void Arm();  // Arm  starting now.
39   void ArmSomeTimeDeltaAgo(const base::TimeDelta& time_delta);
40   void ArmAtStartTime(const base::TimeTicks start_time);
41 
42   // Reset time, and do not set off the alarm.
43   void Disarm();
44 
45   // Alarm is called if the time expires after an Arm() without someone calling
46   // Disarm().  This method can be overridden to create testable classes.
Alarm()47   virtual void Alarm() {
48     DLOG(INFO) << "Watchdog alarmed for " << thread_watched_name_;
49   }
50 
51   // Reset static data to initial state. Useful for tests, to ensure
52   // they are independent.
53   static void ResetStaticData();
54 
55  private:
56   class ThreadDelegate : public PlatformThread::Delegate {
57    public:
ThreadDelegate(Watchdog * watchdog)58     explicit ThreadDelegate(Watchdog* watchdog) : watchdog_(watchdog) {
59     }
60     virtual void ThreadMain();
61    private:
62     Watchdog* watchdog_;
63 
64     void SetThreadName() const;
65   };
66 
67   enum State {ARMED, DISARMED, SHUTDOWN };
68 
69   bool init_successful_;
70 
71   Lock lock_;  // Mutex for state_.
72   ConditionVariable condition_variable_;
73   State state_;
74   const base::TimeDelta duration_;  // How long after start_time_ do we alarm?
75   const std::string thread_watched_name_;
76   PlatformThreadHandle handle_;
77   ThreadDelegate delegate_;  // Store it, because it must outlive the thread.
78 
79   base::TimeTicks start_time_;  // Start of epoch, and alarm after duration_.
80 
81   // When the debugger breaks (when we alarm), all the other alarms that are
82   // armed will expire (also alarm).  To diminish this effect, we track any
83   // delay due to debugger breaks, and we *try* to adjust the effective start
84   // time of other alarms to step past the debugging break.
85   // Without this safety net, any alarm will typically trigger a host of follow
86   // on alarms from callers that specify old times.
87   static Lock static_lock_;  // Lock for access of static data...
88   // When did we last alarm and get stuck (for a while) in a debugger?
89   static base::TimeTicks last_debugged_alarm_time_;
90   // How long did we sit on a break in the debugger?
91   static base::TimeDelta last_debugged_alarm_delay_;
92 
93   DISALLOW_COPY_AND_ASSIGN(Watchdog);
94 };
95 
96 #endif  // BASE_WATCHDOG_H__
97