Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / base / threading / watchdog.cc
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.
4
5 #include "base/threading/watchdog.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/threading/platform_thread.h"
11
12 namespace base {
13
14 namespace {
15
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.
22
23 struct StaticData {
24   // Lock for access of static data...
25   Lock lock;
26
27   // When did we last alarm and get stuck (for a while) in a debugger?
28   TimeTicks last_debugged_alarm_time;
29
30   // How long did we sit on a break in the debugger?
31   TimeDelta last_debugged_alarm_delay;
32 };
33
34 LazyInstance<StaticData>::Leaky g_static_data = LAZY_INSTANCE_INITIALIZER;
35
36 }  // namespace
37
38 // Start thread running in a Disarmed state.
39 Watchdog::Watchdog(const TimeDelta& duration,
40                    const std::string& thread_watched_name,
41                    bool enabled)
42   : enabled_(enabled),
43     lock_(),
44     condition_variable_(&lock_),
45     state_(DISARMED),
46     duration_(duration),
47     thread_watched_name_(thread_watched_name),
48     delegate_(this) {
49   if (!enabled_)
50     return;  // Don't start thread, or doing anything really.
51   enabled_ = PlatformThread::Create(0,  // Default stack size.
52                                     &delegate_,
53                                     &handle_);
54   DCHECK(enabled_);
55 }
56
57 // Notify watchdog thread, and wait for it to finish up.
58 Watchdog::~Watchdog() {
59   if (!enabled_)
60     return;
61   if (!IsJoinable())
62     Cleanup();
63   condition_variable_.Signal();
64   PlatformThread::Join(handle_);
65 }
66
67 void Watchdog::Cleanup() {
68   if (!enabled_)
69     return;
70   {
71     AutoLock lock(lock_);
72     state_ = SHUTDOWN;
73   }
74   condition_variable_.Signal();
75 }
76
77 bool Watchdog::IsJoinable() {
78   if (!enabled_)
79     return true;
80   AutoLock lock(lock_);
81   return (state_ == JOINABLE);
82 }
83
84 void Watchdog::Arm() {
85   ArmAtStartTime(TimeTicks::Now());
86 }
87
88 void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) {
89   ArmAtStartTime(TimeTicks::Now() - time_delta);
90 }
91
92 // Start clock for watchdog.
93 void Watchdog::ArmAtStartTime(const TimeTicks start_time) {
94   {
95     AutoLock lock(lock_);
96     start_time_ = start_time;
97     state_ = ARMED;
98   }
99   // Force watchdog to wake up, and go to sleep with the timer ticking with the
100   // proper duration.
101   condition_variable_.Signal();
102 }
103
104 // Disable watchdog so that it won't do anything when time expires.
105 void Watchdog::Disarm() {
106   AutoLock lock(lock_);
107   state_ = DISARMED;
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.
110 }
111
112 void Watchdog::Alarm() {
113   DVLOG(1) << "Watchdog alarmed for " << thread_watched_name_;
114 }
115
116 //------------------------------------------------------------------------------
117 // Internal private methods that the watchdog thread uses.
118
119 void Watchdog::ThreadDelegate::ThreadMain() {
120   SetThreadName();
121   TimeDelta remaining_duration;
122   StaticData* static_data = g_static_data.Pointer();
123   while (1) {
124     AutoLock lock(watchdog_->lock_);
125     while (DISARMED == watchdog_->state_)
126       watchdog_->condition_variable_.Wait();
127     if (SHUTDOWN == watchdog_->state_) {
128       watchdog_->state_ = JOINABLE;
129       return;
130     }
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);
137       continue;
138     }
139     // We overslept, so this seems like a real alarm.
140     // Watch out for a user that stopped the debugger on a different alarm!
141     {
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
145         // alarm time).
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;
150         continue;
151       }
152     }
153     watchdog_->state_ = DISARMED;  // Only alarm at most once.
154     TimeTicks last_alarm_time = TimeTicks::Now();
155     {
156       AutoUnlock unlock(watchdog_->lock_);
157       watchdog_->Alarm();  // Set a break point here to debug on alarms.
158     }
159     TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time;
160     if (last_alarm_delay <= TimeDelta::FromMilliseconds(2))
161       continue;
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;
167   }
168 }
169
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;
174 }
175
176 // static
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();
182 }
183
184 }  // namespace base