1 // Copyright (c) 2012 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.
5 #include "base/threading/watchdog.h"
7 #include "base/compiler_specific.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/threading/platform_thread.h"
16 // When the debugger breaks (when we alarm), all the other alarms that are
17 // armed will expire (also alarm). To diminish this effect, we track any
18 // delay due to debugger breaks, and we *try* to adjust the effective start
19 // time of other alarms to step past the debugging break.
20 // Without this safety net, any alarm will typically trigger a host of follow
21 // on alarms from callers that specify old times.
24 // Lock for access of static data...
27 // When did we last alarm and get stuck (for a while) in a debugger?
28 TimeTicks last_debugged_alarm_time
;
30 // How long did we sit on a break in the debugger?
31 TimeDelta last_debugged_alarm_delay
;
34 LazyInstance
<StaticData
>::Leaky g_static_data
= LAZY_INSTANCE_INITIALIZER
;
38 // Start thread running in a Disarmed state.
39 Watchdog::Watchdog(const TimeDelta
& duration
,
40 const std::string
& thread_watched_name
,
44 condition_variable_(&lock_
),
47 thread_watched_name_(thread_watched_name
),
50 return; // Don't start thread, or doing anything really.
51 enabled_
= PlatformThread::Create(0, // Default stack size.
57 // Notify watchdog thread, and wait for it to finish up.
58 Watchdog::~Watchdog() {
63 condition_variable_
.Signal();
64 PlatformThread::Join(handle_
);
67 void Watchdog::Cleanup() {
74 condition_variable_
.Signal();
77 bool Watchdog::IsJoinable() {
81 return (state_
== JOINABLE
);
84 void Watchdog::Arm() {
85 ArmAtStartTime(TimeTicks::Now());
88 void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta
& time_delta
) {
89 ArmAtStartTime(TimeTicks::Now() - time_delta
);
92 // Start clock for watchdog.
93 void Watchdog::ArmAtStartTime(const TimeTicks start_time
) {
96 start_time_
= start_time
;
99 // Force watchdog to wake up, and go to sleep with the timer ticking with the
101 condition_variable_
.Signal();
104 // Disable watchdog so that it won't do anything when time expires.
105 void Watchdog::Disarm() {
106 AutoLock
lock(lock_
);
108 // We don't need to signal, as the watchdog will eventually wake up, and it
109 // will check its state and time, and act accordingly.
112 void Watchdog::Alarm() {
113 DVLOG(1) << "Watchdog alarmed for " << thread_watched_name_
;
116 //------------------------------------------------------------------------------
117 // Internal private methods that the watchdog thread uses.
119 void Watchdog::ThreadDelegate::ThreadMain() {
121 TimeDelta remaining_duration
;
122 StaticData
* static_data
= g_static_data
.Pointer();
124 AutoLock
lock(watchdog_
->lock_
);
125 while (DISARMED
== watchdog_
->state_
)
126 watchdog_
->condition_variable_
.Wait();
127 if (SHUTDOWN
== watchdog_
->state_
) {
128 watchdog_
->state_
= JOINABLE
;
131 DCHECK(ARMED
== watchdog_
->state_
);
132 remaining_duration
= watchdog_
->duration_
-
133 (TimeTicks::Now() - watchdog_
->start_time_
);
134 if (remaining_duration
.InMilliseconds() > 0) {
135 // Spurios wake? Timer drifts? Go back to sleep for remaining time.
136 watchdog_
->condition_variable_
.TimedWait(remaining_duration
);
139 // We overslept, so this seems like a real alarm.
140 // Watch out for a user that stopped the debugger on a different alarm!
142 AutoLock
static_lock(static_data
->lock
);
143 if (static_data
->last_debugged_alarm_time
> watchdog_
->start_time_
) {
144 // False alarm: we started our clock before the debugger break (last
146 watchdog_
->start_time_
+= static_data
->last_debugged_alarm_delay
;
147 if (static_data
->last_debugged_alarm_time
> watchdog_
->start_time_
)
148 // Too many alarms must have taken place.
149 watchdog_
->state_
= DISARMED
;
153 watchdog_
->state_
= DISARMED
; // Only alarm at most once.
154 TimeTicks last_alarm_time
= TimeTicks::Now();
156 AutoUnlock
unlock(watchdog_
->lock_
);
157 watchdog_
->Alarm(); // Set a break point here to debug on alarms.
159 TimeDelta last_alarm_delay
= TimeTicks::Now() - last_alarm_time
;
160 if (last_alarm_delay
<= TimeDelta::FromMilliseconds(2))
162 // Ignore race of two alarms/breaks going off at roughly the same time.
163 AutoLock
static_lock(static_data
->lock
);
164 // This was a real debugger break.
165 static_data
->last_debugged_alarm_time
= last_alarm_time
;
166 static_data
->last_debugged_alarm_delay
= last_alarm_delay
;
170 void Watchdog::ThreadDelegate::SetThreadName() const {
171 std::string name
= watchdog_
->thread_watched_name_
+ " Watchdog";
172 PlatformThread::SetName(name
.c_str());
173 DVLOG(1) << "Watchdog active: " << name
;
177 void Watchdog::ResetStaticData() {
178 StaticData
* static_data
= g_static_data
.Pointer();
179 AutoLock
lock(static_data
->lock
);
180 static_data
->last_debugged_alarm_time
= TimeTicks();
181 static_data
->last_debugged_alarm_delay
= TimeDelta();