summaryrefslogtreecommitdiffstats
path: root/base/watchdog.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 21:49:38 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 21:49:38 +0000
commitd7cae12696b96500c05dd2d430f6238922c20c96 (patch)
treeecff27b367735535b2a66477f8cd89d3c462a6c0 /base/watchdog.cc
parentee2815e28d408216cf94e874825b6bcf76c69083 (diff)
downloadchromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.zip
chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.gz
chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.bz2
Add base to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/watchdog.cc')
-rw-r--r--base/watchdog.cc171
1 files changed, 171 insertions, 0 deletions
diff --git a/base/watchdog.cc b/base/watchdog.cc
new file mode 100644
index 0000000..1d9c183
--- /dev/null
+++ b/base/watchdog.cc
@@ -0,0 +1,171 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/watchdog.h"
+#include "base/string_util.h"
+#include "base/thread.h"
+
+//------------------------------------------------------------------------------
+// Public API methods.
+
+// Start thread running in a Disarmed state.
+Watchdog::Watchdog(const TimeDelta& duration,
+ const std::wstring& thread_watched_name,
+ bool enabled)
+ : lock_(),
+ condition_variable_(&lock_),
+ state_(DISARMED),
+ duration_(duration),
+ thread_watched_name_(thread_watched_name),
+ handle_(NULL),
+ thread_id_(0) {
+ if (!enabled)
+ return; // Don't start thread, or doing anything really.
+ handle_ = CreateThread(NULL, // security
+ 0, // Default stack size.
+ Watchdog::ThreadStart,
+ reinterpret_cast<void*>(this),
+ CREATE_SUSPENDED,
+ &thread_id_);
+ DCHECK(NULL != handle_);
+ if (NULL == handle_)
+ return ;
+ ResumeThread(handle_); // WINAPI call.
+}
+
+// Notify watchdog thread, and wait for it to finish up.
+Watchdog::~Watchdog() {
+ if (NULL == handle_)
+ return;
+ {
+ AutoLock lock(lock_);
+ state_ = SHUTDOWN;
+ }
+ condition_variable_.Signal();
+ DWORD results = WaitForSingleObject(handle_, INFINITE);
+ DCHECK(WAIT_OBJECT_0 == results);
+ CloseHandle(handle_);
+ handle_ = NULL;
+}
+
+void Watchdog::Arm() {
+ ArmAtStartTime(TimeTicks::Now());
+}
+
+void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) {
+ ArmAtStartTime(TimeTicks::Now() - time_delta);
+}
+
+// Start clock for watchdog.
+void Watchdog::ArmAtStartTime(const TimeTicks start_time) {
+ {
+ AutoLock lock(lock_);
+ start_time_ = start_time;
+ state_ = ARMED;
+ }
+ // Force watchdog to wake up, and go to sleep with the timer ticking with the
+ // proper duration.
+ condition_variable_.Signal();
+}
+
+// Disable watchdog so that it won't do anything when time expires.
+void Watchdog::Disarm() {
+ if (NULL == handle_)
+ return;
+ AutoLock lock(lock_);
+ state_ = DISARMED;
+ // We don't need to signal, as the watchdog will eventually wake up, and it
+ // will check its state and time, and act accordingly.
+}
+
+//------------------------------------------------------------------------------
+// Internal private methods that the watchdog thread uses.
+
+// static
+DWORD __stdcall Watchdog::ThreadStart(void* pThis) {
+ Watchdog* watchdog = reinterpret_cast<Watchdog*>(pThis);
+ return watchdog->Run();
+}
+
+unsigned Watchdog::Run() {
+ SetThreadName();
+ TimeDelta remaining_duration;
+ while (1) {
+ AutoLock lock(lock_);
+ while (DISARMED == state_)
+ condition_variable_.Wait();
+ if (SHUTDOWN == state_)
+ return 0;
+ DCHECK(ARMED == state_);
+ remaining_duration = duration_ - (TimeTicks::Now() - start_time_);
+ if (remaining_duration.InMilliseconds() > 0) {
+ // Spurios wake? Timer drifts? Go back to sleep for remaining time.
+ condition_variable_.TimedWait(remaining_duration);
+ } else {
+ // We overslept, so this seems like a real alarm.
+ // Watch out for a user that stopped the debugger on a different alarm!
+ {
+ AutoLock static_lock(static_lock_);
+ if (last_debugged_alarm_time_ > start_time_) {
+ // False alarm: we started our clock before the debugger break (last
+ // alarm time).
+ start_time_ += last_debugged_alarm_delay_;
+ if (last_debugged_alarm_time_ > start_time_)
+ state_ = DISARMED; // Too many alarms must have taken place.
+ continue;
+ }
+ }
+ state_ = DISARMED; // Only alarm at most once.
+ TimeTicks last_alarm_time = TimeTicks::Now();
+ Alarm(); // Set a break point here to debug on alarms.
+ TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time;
+ if (last_alarm_delay > TimeDelta::FromMilliseconds(2)) {
+ // Ignore race of two alarms/breaks going off at roughly the same time.
+ AutoLock static_lock(static_lock_);
+ // This was a real debugger break.
+ last_debugged_alarm_time_ = last_alarm_time;
+ last_debugged_alarm_delay_ = last_alarm_delay;
+ }
+ }
+ }
+}
+
+void Watchdog::SetThreadName() const {
+ std::string name = StringPrintf("%s Watchdog",
+ WideToASCII(thread_watched_name_).c_str());
+ Thread::SetThreadName(name.c_str(), thread_id_);
+ DLOG(INFO) << "Watchdog active: " << name;
+}
+
+// static
+Lock Watchdog::static_lock_; // Lock for access of static data...
+// static
+TimeTicks Watchdog::last_debugged_alarm_time_ = TimeTicks();
+// static
+TimeDelta Watchdog::last_debugged_alarm_delay_;