15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/watchdog.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When the debugger breaks (when we alarm), all the other alarms that are 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// armed will expire (also alarm). To diminish this effect, we track any 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// delay due to debugger breaks, and we *try* to adjust the effective start 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// time of other alarms to step past the debugging break. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Without this safety net, any alarm will typically trigger a host of follow 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on alarms from callers that specify old times. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)struct StaticData { 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Lock for access of static data... 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Lock lock; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // When did we last alarm and get stuck (for a while) in a debugger? 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) TimeTicks last_debugged_alarm_time; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // How long did we sit on a break in the debugger? 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) TimeDelta last_debugged_alarm_delay; 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)LazyInstance<StaticData>::Leaky g_static_data = LAZY_INSTANCE_INITIALIZER; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start thread running in a Disarmed state. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Watchdog::Watchdog(const TimeDelta& duration, 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& thread_watched_name, 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool enabled) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : enabled_(enabled), 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lock_(), 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) condition_variable_(&lock_), 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_(DISARMED), 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) duration_(duration), 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_watched_name_(thread_watched_name), 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) delegate_(this) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enabled_) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Don't start thread, or doing anything really. 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enabled_ = PlatformThread::Create(0, // Default stack size. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &delegate_, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &handle_); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(enabled_); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Notify watchdog thread, and wait for it to finish up. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Watchdog::~Watchdog() { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enabled_) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsJoinable()) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cleanup(); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) condition_variable_.Signal(); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlatformThread::Join(handle_); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::Cleanup() { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enabled_) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(lock_); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = SHUTDOWN; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) condition_variable_.Signal(); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Watchdog::IsJoinable() { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enabled_) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(lock_); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (state_ == JOINABLE); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::Arm() { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ArmAtStartTime(TimeTicks::Now()); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ArmAtStartTime(TimeTicks::Now() - time_delta); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start clock for watchdog. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ArmAtStartTime(const TimeTicks start_time) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(lock_); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_time_ = start_time; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = ARMED; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Force watchdog to wake up, and go to sleep with the timer ticking with the 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // proper duration. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) condition_variable_.Signal(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Disable watchdog so that it won't do anything when time expires. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::Disarm() { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(lock_); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = DISARMED; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't need to signal, as the watchdog will eventually wake up, and it 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will check its state and time, and act accordingly. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::Alarm() { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Watchdog alarmed for " << thread_watched_name_; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------ 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Internal private methods that the watchdog thread uses. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ThreadDelegate::ThreadMain() { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetThreadName(); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta remaining_duration; 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StaticData* static_data = g_static_data.Pointer(); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (1) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(watchdog_->lock_); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (DISARMED == watchdog_->state_) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) watchdog_->condition_variable_.Wait(); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SHUTDOWN == watchdog_->state_) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) watchdog_->state_ = JOINABLE; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ARMED == watchdog_->state_); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) remaining_duration = watchdog_->duration_ - 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (TimeTicks::Now() - watchdog_->start_time_); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (remaining_duration.InMilliseconds() > 0) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Spurios wake? Timer drifts? Go back to sleep for remaining time. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) watchdog_->condition_variable_.TimedWait(remaining_duration); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We overslept, so this seems like a real alarm. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Watch out for a user that stopped the debugger on a different alarm! 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AutoLock static_lock(static_data->lock); 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (static_data->last_debugged_alarm_time > watchdog_->start_time_) { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // False alarm: we started our clock before the debugger break (last 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // alarm time). 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) watchdog_->start_time_ += static_data->last_debugged_alarm_delay; 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (static_data->last_debugged_alarm_time > watchdog_->start_time_) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Too many alarms must have taken place. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) watchdog_->state_ = DISARMED; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) watchdog_->state_ = DISARMED; // Only alarm at most once. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks last_alarm_time = TimeTicks::Now(); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoUnlock lock(watchdog_->lock_); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) watchdog_->Alarm(); // Set a break point here to debug on alarms. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (last_alarm_delay <= TimeDelta::FromMilliseconds(2)) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore race of two alarms/breaks going off at roughly the same time. 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AutoLock static_lock(static_data->lock); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This was a real debugger break. 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static_data->last_debugged_alarm_time = last_alarm_time; 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static_data->last_debugged_alarm_delay = last_alarm_delay; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ThreadDelegate::SetThreadName() const { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string name = watchdog_->thread_watched_name_ + " Watchdog"; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlatformThread::SetName(name.c_str()); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Watchdog active: " << name; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Watchdog::ResetStaticData() { 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StaticData* static_data = g_static_data.Pointer(); 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AutoLock lock(static_data->lock); 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static_data->last_debugged_alarm_time = TimeTicks(); 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static_data->last_debugged_alarm_delay = TimeDelta(); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 185