Eliminate TimerManager::GetCurrentDelay in favor of always referring to the fire time of the next timer.  I changed the MessagePump API to refer to a delayed_work_time instead of a delay.

I moved the ceil-based rounding code into the Window's implementations of WaitableEvent and MessagePump.

R=jar


git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1075 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 1a2bfdd793e88a64f78b38d23303550cfd0703eb
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 4964dfe..eb10ca7 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -386,16 +386,16 @@
 }
 
 void MessageLoop::DidChangeNextTimerExpiry() {
-  int delay = timer_manager_.GetCurrentDelay(); 
-  if (delay == -1)
+  Time next_delayed_work_time = timer_manager_.GetNextFireTime(); 
+  if (next_delayed_work_time.is_null())
     return;
 
   // Simulates malfunctioning, early firing timers. Pending tasks should only
   // be invoked when the delay they specify has elapsed.
   if (timer_manager_.use_broken_delay())
-    delay = 10;
+    next_delayed_work_time = Time::Now() + TimeDelta::FromMilliseconds(10);
 
-  pump_->ScheduleDelayedWork(TimeDelta::FromMilliseconds(delay));
+  pump_->ScheduleDelayedWork(next_delayed_work_time);
 }
 
 bool MessageLoop::DoWork() {
@@ -403,12 +403,12 @@
   return QueueOrRunTask(NULL);
 }
 
-bool MessageLoop::DoDelayedWork(TimeDelta* next_delay) {
+bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) {
   bool did_work = timer_manager_.RunSomePendingTimers();
 
   // We may not have run any timers, but we may still have future timers to
   // run, so we need to inform the pump again of pending timers.
-  *next_delay = TimeDelta::FromMilliseconds(timer_manager_.GetCurrentDelay());
+  *next_delayed_work_time = timer_manager_.GetNextFireTime();
 
   return did_work;
 }
diff --git a/base/message_loop.h b/base/message_loop.h
index afcab64..3821519 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -415,7 +415,7 @@
 
   // base::MessagePump::Delegate methods:
   virtual bool DoWork();
-  virtual bool DoDelayedWork(TimeDelta* next_delay);
+  virtual bool DoDelayedWork(Time* next_delayed_work_time);
   virtual bool DoIdleWork();
 
   // Start recording histogram info about events and action IF it was enabled
diff --git a/base/message_pump.h b/base/message_pump.h
index a06a435..06cef43 100644
--- a/base/message_pump.h
+++ b/base/message_pump.h
@@ -32,7 +32,7 @@
 
 #include "base/ref_counted.h"
 
-class TimeDelta;
+class Time;
 
 namespace base {
 
@@ -52,11 +52,12 @@
     // Called from within Run in response to ScheduleDelayedWork or when the
     // message pump would otherwise sleep waiting for more work.  Returns true
     // to indicate that delayed work was done.  DoIdleWork will not be called
-    // if DoDelayedWork returns true.  Upon return |next_delay| indicates the
-    // next delayed work interval.  If |next_delay| is negative, then the queue
-    // of future delayed work (timer events) is currently empty, and no
-    // additional calls to this function need to be scheduled.
-    virtual bool DoDelayedWork(TimeDelta* next_delay) = 0;
+    // if DoDelayedWork returns true.  Upon return |next_delayed_work_time|
+    // indicates the time when DoDelayedWork should be called again.  If
+    // |next_delayed_work_time| is null (per Time::is_null), then the queue of
+    // future delayed work (timer events) is currently empty, and no additional
+    // calls to this function need to be scheduled.
+    virtual bool DoDelayedWork(Time* next_delayed_work_time) = 0;
 
     // Called from within Run just before the message pump goes to sleep.
     // Returns true to indicate that idle work was done.
@@ -137,10 +138,10 @@
   // until it returns a value of false.
   virtual void ScheduleWork() = 0;
 
-  // Schedule a DoDelayedWork callback to happen after the specified delay,
+  // Schedule a DoDelayedWork callback to happen at the specified time,
   // cancelling any pending DoDelayedWork callback.  This method may only be
   // used on the thread that called Run.
-  virtual void ScheduleDelayedWork(const TimeDelta& delay) = 0;
+  virtual void ScheduleDelayedWork(const Time& delayed_work_time) = 0;
 };
 
 }  // namespace base
diff --git a/base/message_pump_default.cc b/base/message_pump_default.cc
index 916d035..a45f480 100644
--- a/base/message_pump_default.cc
+++ b/base/message_pump_default.cc
@@ -51,9 +51,13 @@
 
     // TODO(darin): Delayed work will be starved if DoWork continues to return
     // true.  We should devise a better strategy.
+    //
+    // It is tempting to call DoWork followed by DoDelayedWork before checking
+    // did_work, but we need to make sure that any tasks that were dispatched
+    // prior to a timer actually run before the timer.  Getting that right may
+    // require some additional changes.
 
-    TimeDelta delay;
-    did_work = delegate->DoDelayedWork(&delay);
+    did_work = delegate->DoDelayedWork(&delayed_work_time_);
     if (!keep_running_)
       break;
     if (did_work)
@@ -64,13 +68,18 @@
       break;
     if (did_work)
       continue;
-    // When DoIdleWork does not work, we also assume that it ran very quickly
-    // such that |delay| still properly indicates how long we are to sleep.
 
-    if (delay < TimeDelta::FromMilliseconds(0)) {
+    if (delayed_work_time_.is_null()) {
       event_.Wait();
     } else {
-      event_.TimedWait(delay);
+      TimeDelta delay = delayed_work_time_ - Time::Now();
+      if (delay > TimeDelta()) {
+        event_.TimedWait(delay);
+      } else {
+        // It looks like delayed_work_time_ indicates a time in the past, so we
+        // need to call DoDelayedWork now.
+        delayed_work_time_ = Time();
+      }
     }
     // Since event_ is auto-reset, we don't need to do anything special here
     // other than service each delegate method.
@@ -89,12 +98,11 @@
   event_.Signal();
 }
 
-void MessagePumpDefault::ScheduleDelayedWork(const TimeDelta& delay) {
+void MessagePumpDefault::ScheduleDelayedWork(const Time& delayed_work_time) {
   // We know that we can't be blocked on Wait right now since this method can
-  // only be called on the same thread as Run, but to ensure that when we do
-  // sleep, we sleep for the right time, we signal the event to cause the Run
-  // loop to do one more iteration.
-  event_.Signal();
+  // only be called on the same thread as Run, so we only need to update our
+  // record of how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
 }
 
 }  // namespace base
diff --git a/base/message_pump_default.h b/base/message_pump_default.h
index 1c1af71..7c65013 100644
--- a/base/message_pump_default.h
+++ b/base/message_pump_default.h
@@ -44,7 +44,7 @@
   virtual void Run(Delegate* delegate);
   virtual void Quit();
   virtual void ScheduleWork();
-  virtual void ScheduleDelayedWork(const TimeDelta& delay);
+  virtual void ScheduleDelayedWork(const Time& delayed_work_time);
 
  private:
   // This flag is set to false when Run should return.
@@ -53,6 +53,9 @@
   // Used to sleep until there is more work to do.
   WaitableEvent event_;
 
+  // The time at which we should call DoDelayedWork.
+  Time delayed_work_time_;
+
   DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);
 };
 
diff --git a/base/timer.cc b/base/timer.cc
index 46fae6e..aced8cb 100644
--- a/base/timer.cc
+++ b/base/timer.cc
@@ -55,14 +55,6 @@
   Reset();
 }
 
-int Timer::GetCurrentDelay() const {
-  // Be careful here.  Timers have a precision of microseconds, but this API is
-  // in milliseconds.  If there are 5.5ms left, should the delay be 5 or 6?  It
-  // should be 6 to avoid timers firing early.
-  double delay = ceil((fire_time_ - Time::Now()).InMillisecondsF());
-  return static_cast<int>(delay);
-}
-
 void Timer::Reset() {
   creation_time_ = Time::Now();
   fire_time_ = creation_time_ + TimeDelta::FromMilliseconds(delay_);
@@ -163,7 +155,7 @@
   // timers have been set.
   const int kMaxTimersPerCall = 2;
   for (int i = 0; i < kMaxTimersPerCall; ++i) {
-    if (timers_.empty() || GetCurrentDelay() > 0)
+    if (timers_.empty() || timers_.top()->fire_time() > Time::Now())
       break;
 
     // Get a pending timer.  Deal with updating the timers_ queue and setting
@@ -211,13 +203,11 @@
     DidChangeNextTimer();
 }
 
-int TimerManager::GetCurrentDelay() {
+Time TimerManager::GetNextFireTime() const {
   if (timers_.empty())
-    return -1;
-  int delay = timers_.top()->GetCurrentDelay();
-  if (delay < 0)
-    delay = 0;
-  return delay;
+    return Time();
+
+  return timers_.top()->fire_time();
 }
 
 void TimerManager::DidChangeNextTimer() {
diff --git a/base/timer.h b/base/timer.h
index c23f725..74fe27b 100644
--- a/base/timer.h
+++ b/base/timer.h
@@ -59,9 +59,6 @@
   Task* task() const { return task_; }
   void set_task(Task* task) { task_ = task; }
 
-  // Returns the time in msec relative to now that the timer should fire.
-  int GetCurrentDelay() const;
-
   // Returns the absolute time at which the timer should fire.
   const Time &fire_time() const { return fire_time_; }
 
@@ -177,9 +174,10 @@
   // Returns true if it runs a task, false otherwise.
   bool RunSomePendingTimers();
 
-  // The number of milliseconds remaining until the pending timer (top of the
-  // pqueue) needs to be fired. Returns -1 if no timers are pending.
-  int GetCurrentDelay();
+  // The absolute time at which the next timer is to fire.  If there is not a
+  // next timer to run, then the is_null property of the returned Time object
+  // will be true.  NOTE: This could be a time in the past!
+  Time GetNextFireTime() const;
 
 #ifdef UNIT_TEST
   // For testing only, used to simulate broken early-firing WM_TIMER