diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-26 19:48:34 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-26 19:48:34 +0000 |
commit | 097ae5a93a863b604fd6dbd939bed0c2be1afed2 (patch) | |
tree | 61177362b1c1bd2d1b2438acc50ccb2c061b176e /base | |
parent | 902c971382790170852fe5b5d22d1b79adb31056 (diff) | |
download | chromium_src-097ae5a93a863b604fd6dbd939bed0c2be1afed2.zip chromium_src-097ae5a93a863b604fd6dbd939bed0c2be1afed2.tar.gz chromium_src-097ae5a93a863b604fd6dbd939bed0c2be1afed2.tar.bz2 |
Make SystemMonitor not a Singleton and move it out of base
SystemMonitor makes an assumption that through its lifetime a MessageLoop exists and stays the same. It is difficult and error-prone to satisfy that when it is a Singleton. It has caused problems in the past.
Additionally, extract HighResoltionTimerManager out of time_win.cc, eliminating yet another Singleton.
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/431008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33214 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/base.gyp | 5 | ||||
-rw-r--r-- | base/system_monitor.cc | 98 | ||||
-rw-r--r-- | base/system_monitor.h | 129 | ||||
-rw-r--r-- | base/system_monitor_posix.cc | 14 | ||||
-rw-r--r-- | base/system_monitor_unittest.cc | 86 | ||||
-rw-r--r-- | base/system_monitor_win.cc | 52 | ||||
-rw-r--r-- | base/test/test_suite.h | 8 | ||||
-rw-r--r-- | base/time.h | 9 | ||||
-rw-r--r-- | base/time_win.cc | 79 |
9 files changed, 19 insertions, 461 deletions
diff --git a/base/base.gyp b/base/base.gyp index 7238928..23b85b1 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -321,10 +321,6 @@ 'sys_string_conversions_linux.cc', 'sys_string_conversions_mac.mm', 'sys_string_conversions_win.cc', - 'system_monitor.cc', - 'system_monitor.h', - 'system_monitor_posix.cc', - 'system_monitor_win.cc', 'task.h', 'thread.cc', 'thread.h', @@ -654,7 +650,6 @@ 'sys_info_unittest.cc', 'sys_string_conversions_mac_unittest.mm', 'sys_string_conversions_unittest.cc', - 'system_monitor_unittest.cc', 'task_unittest.cc', 'thread_collision_warner_unittest.cc', 'thread_local_storage_unittest.cc', diff --git a/base/system_monitor.cc b/base/system_monitor.cc deleted file mode 100644 index 44cdce5..0000000 --- a/base/system_monitor.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/system_monitor.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/singleton.h" - -namespace base { - -#if defined(ENABLE_BATTERY_MONITORING) -// The amount of time (in ms) to wait before running the initial -// battery check. -static int kDelayedBatteryCheckMs = 10 * 1000; -#endif // defined(ENABLE_BATTERY_MONITORING) - -SystemMonitor::SystemMonitor() - : battery_in_use_(false), - suspended_(false) { - observer_list_ = new ObserverListThreadSafe<PowerObserver>(); -} - -void SystemMonitor::ProcessPowerMessage(PowerEvent event_id) { - // Suppress duplicate notifications. Some platforms may - // send multiple notifications of the same event. - switch (event_id) { - case POWER_STATE_EVENT: - { - bool on_battery = IsBatteryPower(); - if (on_battery != battery_in_use_) { - battery_in_use_ = on_battery; - NotifyPowerStateChange(); - } - } - break; - case RESUME_EVENT: - if (suspended_) { - suspended_ = false; - NotifyResume(); - } - break; - case SUSPEND_EVENT: - if (!suspended_) { - suspended_ = true; - NotifySuspend(); - } - break; - } -} - -void SystemMonitor::AddObserver(PowerObserver* obs) { - observer_list_->AddObserver(obs); -} - -void SystemMonitor::RemoveObserver(PowerObserver* obs) { - observer_list_->RemoveObserver(obs); -} - -void SystemMonitor::NotifyPowerStateChange() { - LOG(INFO) << L"PowerStateChange: " - << (BatteryPower() ? L"On" : L"Off") << L" battery"; - observer_list_->Notify(&PowerObserver::OnPowerStateChange, BatteryPower()); -} - -void SystemMonitor::NotifySuspend() { - LOG(INFO) << L"Power Suspending"; - observer_list_->Notify(&PowerObserver::OnSuspend); -} - -void SystemMonitor::NotifyResume() { - LOG(INFO) << L"Power Resuming"; - observer_list_->Notify(&PowerObserver::OnResume); -} - -// static -SystemMonitor* SystemMonitor::Get() { - // Uses the LeakySingletonTrait because cleanup is optional. - return - Singleton<SystemMonitor, LeakySingletonTraits<SystemMonitor> >::get(); -} - -// static -void SystemMonitor::Start() { -#if defined(ENABLE_BATTERY_MONITORING) - DCHECK(MessageLoop::current()); // Can't call start too early. - SystemMonitor* monitor = Get(); - monitor->delayed_battery_check_.Start( - TimeDelta::FromMilliseconds(kDelayedBatteryCheckMs), monitor, - &SystemMonitor::BatteryCheck); -#endif // defined(ENABLE_BATTERY_MONITORING) -} - -void SystemMonitor::BatteryCheck() { - ProcessPowerMessage(SystemMonitor::POWER_STATE_EVENT); -} - -} // namespace base diff --git a/base/system_monitor.h b/base/system_monitor.h deleted file mode 100644 index 71d8436..0000000 --- a/base/system_monitor.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SYSTEM_MONITOR_H_ -#define BASE_SYSTEM_MONITOR_H_ - -#include "build/build_config.h" - -// Windows HiRes timers drain the battery faster so we need to know the battery -// status. This isn't true for other platforms. -#if defined(OS_WIN) -#define ENABLE_BATTERY_MONITORING 1 -#else -#undef ENABLE_BATTERY_MONITORING -#endif // !OS_WIN - -#include "base/observer_list_threadsafe.h" -#if defined(ENABLE_BATTERY_MONITORING) -#include "base/timer.h" -#endif // defined(ENABLE_BATTERY_MONITORING) - -namespace base { - -// Class for monitoring various system-related subsystems -// such as power management, network status, etc. -// TODO(mbelshe): Add support beyond just power management. -class SystemMonitor { - public: - // Retrieves the Singleton. - static SystemMonitor* Get(); - - // Start the System Monitor within a process. This method - // is provided so that the battery check can be deferred. - // The MessageLoop must be started before calling this - // method. - // This is a no-op on platforms for which ENABLE_BATTERY_MONITORING is - // disabled. - static void Start(); - - // - // Power-related APIs - // - - // Is the computer currently on battery power. - // Can be called on any thread. - bool BatteryPower() const { - // Using a lock here is not necessary for just a bool. - return battery_in_use_; - } - - // Normalized list of power events. - enum PowerEvent { - POWER_STATE_EVENT, // The Power status of the system has changed. - SUSPEND_EVENT, // The system is being suspended. - RESUME_EVENT // The system is being resumed. - }; - - // Callbacks will be called on the thread which creates the SystemMonitor. - // During the callback, Add/RemoveObserver will block until the callbacks - // are finished. Observers should implement quick callback functions; if - // lengthy operations are needed, the observer should take care to invoke - // the operation on an appropriate thread. - class PowerObserver { - public: - // Notification of a change in power status of the computer, such - // as from switching between battery and A/C power. - virtual void OnPowerStateChange(bool on_battery_power) {} - - // Notification that the system is suspending. - virtual void OnSuspend() {} - - // Notification that the system is resuming. - virtual void OnResume() {} - }; - - // Add a new observer. - // Can be called from any thread. - // Must not be called from within a notification callback. - void AddObserver(PowerObserver* obs); - - // Remove an existing observer. - // Can be called from any thread. - // Must not be called from within a notification callback. - void RemoveObserver(PowerObserver* obs); - -#if defined(OS_WIN) - // Windows-specific handling of a WM_POWERBROADCAST message. - // Embedders of this API should hook their top-level window - // message loop and forward WM_POWERBROADCAST through this call. - void ProcessWmPowerBroadcastMessage(int event_id); -#endif - - // Cross-platform handling of a power event. - void ProcessPowerMessage(PowerEvent event_id); - - // Constructor. - // Don't use this; access SystemMonitor via the Singleton. - SystemMonitor(); - - private: - // Platform-specific method to check whether the system is currently - // running on battery power. Returns true if running on batteries, - // false otherwise. - bool IsBatteryPower(); - - // Checks the battery status and notifies observers if the battery - // status has changed. - void BatteryCheck(); - - // Functions to trigger notifications. - void NotifyPowerStateChange(); - void NotifySuspend(); - void NotifyResume(); - - scoped_refptr<ObserverListThreadSafe<PowerObserver> > observer_list_; - bool battery_in_use_; - bool suspended_; - -#if defined(ENABLE_BATTERY_MONITORING) - base::OneShotTimer<SystemMonitor> delayed_battery_check_; -#endif - - DISALLOW_COPY_AND_ASSIGN(SystemMonitor); -}; - -} - -#endif // BASE_SYSTEM_MONITOR_H_ diff --git a/base/system_monitor_posix.cc b/base/system_monitor_posix.cc deleted file mode 100644 index a4a118c..0000000 --- a/base/system_monitor_posix.cc +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/system_monitor.h" - -namespace base { - -bool SystemMonitor::IsBatteryPower() { - NOTIMPLEMENTED(); - return false; -} - -} // namespace base diff --git a/base/system_monitor_unittest.cc b/base/system_monitor_unittest.cc deleted file mode 100644 index 7ba3a6b..0000000 --- a/base/system_monitor_unittest.cc +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/system_monitor.h" -#include "testing/gtest/include/gtest/gtest.h" - -class PowerTest : public base::SystemMonitor::PowerObserver { - public: - PowerTest() - : battery_(false), - power_state_changes_(0), - suspends_(0), - resumes_(0) {}; - - // PowerObserver callbacks. - void OnPowerStateChange(bool on_battery_power) { - power_state_changes_++; - } - - void OnSuspend() { - suspends_++; - } - - void OnResume() { - resumes_++; - } - - // Test status counts. - bool battery() { return battery_; } - int power_state_changes() { return power_state_changes_; } - int suspends() { return suspends_; } - int resumes() { return resumes_; } - - private: - bool battery_; // Do we currently think we're on battery power. - int power_state_changes_; // Count of OnPowerStateChange notifications. - int suspends_; // Count of OnSuspend notifications. - int resumes_; // Count of OnResume notifications. -}; - -TEST(SystemMonitor, PowerNotifications) { - const int kObservers = 5; - - // Initialize a message loop for this to run on. - MessageLoop loop; - // Initialize time() since it registers as a SystemMonitor observer. - base::Time now = base::Time::Now(); - - base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); - PowerTest test[kObservers]; - for (int index = 0; index < kObservers; ++index) - system_monitor->AddObserver(&test[index]); - - // Send a bunch of power changes. Since the battery power hasn't - // actually changed, we shouldn't get notifications. - for (int index = 0; index < 5; index++) { - system_monitor->ProcessPowerMessage(base::SystemMonitor::POWER_STATE_EVENT); - EXPECT_EQ(test[0].power_state_changes(), 0); - } - - // Sending resume when not suspended should have no effect. - system_monitor->ProcessPowerMessage(base::SystemMonitor::RESUME_EVENT); - loop.RunAllPending(); - EXPECT_EQ(test[0].resumes(), 0); - - // Pretend we suspended. - system_monitor->ProcessPowerMessage(base::SystemMonitor::SUSPEND_EVENT); - loop.RunAllPending(); - EXPECT_EQ(test[0].suspends(), 1); - - // Send a second suspend notification. This should be suppressed. - system_monitor->ProcessPowerMessage(base::SystemMonitor::SUSPEND_EVENT); - loop.RunAllPending(); - EXPECT_EQ(test[0].suspends(), 1); - - // Pretend we were awakened. - system_monitor->ProcessPowerMessage(base::SystemMonitor::RESUME_EVENT); - loop.RunAllPending(); - EXPECT_EQ(test[0].resumes(), 1); - - // Send a duplicate resume notification. This should be suppressed. - system_monitor->ProcessPowerMessage(base::SystemMonitor::RESUME_EVENT); - loop.RunAllPending(); - EXPECT_EQ(test[0].resumes(), 1); -} diff --git a/base/system_monitor_win.cc b/base/system_monitor_win.cc deleted file mode 100644 index 8a2d8c9..0000000 --- a/base/system_monitor_win.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/system_monitor.h" - -namespace base { - -void SystemMonitor::ProcessWmPowerBroadcastMessage(int event_id) { - PowerEvent power_event; - switch (event_id) { - case PBT_APMPOWERSTATUSCHANGE: // The power status changed. - power_event = POWER_STATE_EVENT; - break; - case PBT_APMRESUMEAUTOMATIC: // Resume from suspend. - //case PBT_APMRESUMESUSPEND: // User-initiated resume from suspend. - // We don't notify for this latter event - // because if it occurs it is always sent as a - // second event after PBT_APMRESUMEAUTOMATIC. - power_event = RESUME_EVENT; - break; - case PBT_APMSUSPEND: // System has been suspended. - power_event = SUSPEND_EVENT; - break; - default: - return; - - // Other Power Events: - // PBT_APMBATTERYLOW - removed in Vista. - // PBT_APMOEMEVENT - removed in Vista. - // PBT_APMQUERYSUSPEND - removed in Vista. - // PBT_APMQUERYSUSPENDFAILED - removed in Vista. - // PBT_APMRESUMECRITICAL - removed in Vista. - // PBT_POWERSETTINGCHANGE - user changed the power settings. - } - ProcessPowerMessage(power_event); -} - -// Function to query the system to see if it is currently running on -// battery power. Returns true if running on battery. -bool SystemMonitor::IsBatteryPower() { - SYSTEM_POWER_STATUS status; - if (!GetSystemPowerStatus(&status)) { - LOG(ERROR) << "GetSystemPowerStatus failed: " << GetLastError(); - return false; - } - return (status.ACLineStatus == 0); -} - - - -} // namespace base diff --git a/base/test/test_suite.h b/base/test/test_suite.h index 44e8511..2566b1a 100644 --- a/base/test/test_suite.h +++ b/base/test/test_suite.h @@ -182,10 +182,10 @@ class TestSuite { CHECK(base::EnableInProcessStackDumping()); #if defined(OS_WIN) - // For unit tests we turn on the high resolution timer and disable - // base::Time's use of SystemMonitor. Tests create and destroy the message - // loop, which causes a crash with SystemMonitor (http://crbug.com/12187). - base::Time::EnableHiResClockForTests(); + // Make sure we run with high resolution timer to minimize differences + // between production code and test code. + bool result = base::Time::UseHighResolutionTimer(true); + CHECK(result); // In some cases, we do not want to see standard error dialogs. if (!IsDebuggerPresent() && diff --git a/base/time.h b/base/time.h index 8cd752a..33ab227 100644 --- a/base/time.h +++ b/base/time.h @@ -242,12 +242,9 @@ class Time { static Time FromFileTime(FILETIME ft); FILETIME ToFileTime() const; - // Monitor system power state and disable high resolution timer when we're - // on battery. See time_win.cc for more details. - static void StartSystemMonitorObserver(); - - // Enable high resolution timer unconditionally. Only for test code. - static void EnableHiResClockForTests(); + // Enable or disable Windows high resolution timer. For more details + // see comments in time_win.cc. Returns true on success. + static bool UseHighResolutionTimer(bool use); #endif // Converts an exploded structure representing either the local time or UTC diff --git a/base/time_win.cc b/base/time_win.cc index 9fdcab1..eedf468 100644 --- a/base/time_win.cc +++ b/base/time_win.cc @@ -45,7 +45,6 @@ #include "base/logging.h" #include "base/cpu.h" #include "base/singleton.h" -#include "base/system_monitor.h" using base::Time; using base::TimeDelta; @@ -88,65 +87,6 @@ void InitializeClock() { initial_time = CurrentWallclockMicroseconds(); } -class HighResolutionTimerManager : public base::SystemMonitor::PowerObserver { - public: - ~HighResolutionTimerManager() { - StopMonitoring(); - UseHiResClock(false); - } - - void Enable() { - StopMonitoring(); - UseHiResClock(true); - } - - void StartMonitoring() { - if (is_monitoring_) - return; - is_monitoring_ = true; - base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); - system_monitor->AddObserver(this); - UseHiResClock(!system_monitor->BatteryPower()); - } - - void StopMonitoring() { - if (!is_monitoring_) - return; - is_monitoring_ = false; - base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); - if (system_monitor) - system_monitor->RemoveObserver(this); - } - - // Interfaces for monitoring Power changes. - void OnPowerStateChange(bool on_battery_power) { - UseHiResClock(!on_battery_power); - } - - private: - HighResolutionTimerManager() - : is_monitoring_(false), - hi_res_clock_enabled_(false) { - } - friend struct DefaultSingletonTraits<HighResolutionTimerManager>; - - // Enable or disable the faster multimedia timer. - void UseHiResClock(bool enabled) { - if (enabled == hi_res_clock_enabled_) - return; - if (enabled) - timeBeginPeriod(1); - else - timeEndPeriod(1); - hi_res_clock_enabled_ = enabled; - } - - bool is_monitoring_; - bool hi_res_clock_enabled_; - - DISALLOW_COPY_AND_ASSIGN(HighResolutionTimerManager); -}; - } // namespace // Time ----------------------------------------------------------------------- @@ -208,13 +148,18 @@ FILETIME Time::ToFileTime() const { } // static -void Time::StartSystemMonitorObserver() { - Singleton<HighResolutionTimerManager>()->StartMonitoring(); -} - -// static -void Time::EnableHiResClockForTests() { - Singleton<HighResolutionTimerManager>()->Enable(); +bool Time::UseHighResolutionTimer(bool use) { + // TODO(mbelshe): Make sure that switching the system timer resolution + // doesn't break Timer firing order etc. An example test would be to have + // two threads. One would have a bunch of timers, and another would turn the + // high resolution timer on and off. + + MMRESULT result; + if (use) + result = timeBeginPeriod(1); + else + result = timeEndPeriod(1); + return (result == TIMERR_NOERROR); } // static |