This source file includes following definitions.
- delegate_
- Cleanup
- IsJoinable
- Arm
- ArmSomeTimeDeltaAgo
- ArmAtStartTime
- Disarm
- Alarm
- ThreadMain
- SetThreadName
- ResetStaticData
#include "base/threading/watchdog.h"
#include "base/compiler_specific.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/threading/platform_thread.h"
namespace base {
namespace {
struct StaticData {
Lock lock;
TimeTicks last_debugged_alarm_time;
TimeDelta last_debugged_alarm_delay;
};
LazyInstance<StaticData>::Leaky g_static_data = LAZY_INSTANCE_INITIALIZER;
}
Watchdog::Watchdog(const TimeDelta& duration,
const std::string& thread_watched_name,
bool enabled)
: enabled_(enabled),
lock_(),
condition_variable_(&lock_),
state_(DISARMED),
duration_(duration),
thread_watched_name_(thread_watched_name),
delegate_(this) {
if (!enabled_)
return;
enabled_ = PlatformThread::Create(0,
&delegate_,
&handle_);
DCHECK(enabled_);
}
Watchdog::~Watchdog() {
if (!enabled_)
return;
if (!IsJoinable())
Cleanup();
condition_variable_.Signal();
PlatformThread::Join(handle_);
}
void Watchdog::Cleanup() {
if (!enabled_)
return;
{
AutoLock lock(lock_);
state_ = SHUTDOWN;
}
condition_variable_.Signal();
}
bool Watchdog::IsJoinable() {
if (!enabled_)
return true;
AutoLock lock(lock_);
return (state_ == JOINABLE);
}
void Watchdog::Arm() {
ArmAtStartTime(TimeTicks::Now());
}
void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) {
ArmAtStartTime(TimeTicks::Now() - time_delta);
}
void Watchdog::ArmAtStartTime(const TimeTicks start_time) {
{
AutoLock lock(lock_);
start_time_ = start_time;
state_ = ARMED;
}
condition_variable_.Signal();
}
void Watchdog::Disarm() {
AutoLock lock(lock_);
state_ = DISARMED;
}
void Watchdog::Alarm() {
DVLOG(1) << "Watchdog alarmed for " << thread_watched_name_;
}
void Watchdog::ThreadDelegate::ThreadMain() {
SetThreadName();
TimeDelta remaining_duration;
StaticData* static_data = g_static_data.Pointer();
while (1) {
AutoLock lock(watchdog_->lock_);
while (DISARMED == watchdog_->state_)
watchdog_->condition_variable_.Wait();
if (SHUTDOWN == watchdog_->state_) {
watchdog_->state_ = JOINABLE;
return;
}
DCHECK(ARMED == watchdog_->state_);
remaining_duration = watchdog_->duration_ -
(TimeTicks::Now() - watchdog_->start_time_);
if (remaining_duration.InMilliseconds() > 0) {
watchdog_->condition_variable_.TimedWait(remaining_duration);
continue;
}
{
AutoLock static_lock(static_data->lock);
if (static_data->last_debugged_alarm_time > watchdog_->start_time_) {
watchdog_->start_time_ += static_data->last_debugged_alarm_delay;
if (static_data->last_debugged_alarm_time > watchdog_->start_time_)
watchdog_->state_ = DISARMED;
continue;
}
}
watchdog_->state_ = DISARMED;
TimeTicks last_alarm_time = TimeTicks::Now();
{
AutoUnlock lock(watchdog_->lock_);
watchdog_->Alarm();
}
TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time;
if (last_alarm_delay <= TimeDelta::FromMilliseconds(2))
continue;
AutoLock static_lock(static_data->lock);
static_data->last_debugged_alarm_time = last_alarm_time;
static_data->last_debugged_alarm_delay = last_alarm_delay;
}
}
void Watchdog::ThreadDelegate::SetThreadName() const {
std::string name = watchdog_->thread_watched_name_ + " Watchdog";
PlatformThread::SetName(name.c_str());
DVLOG(1) << "Watchdog active: " << name;
}
void Watchdog::ResetStaticData() {
StaticData* static_data = g_static_data.Pointer();
AutoLock lock(static_data->lock);
static_data->last_debugged_alarm_time = TimeTicks();
static_data->last_debugged_alarm_delay = TimeDelta();
}
}