summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/message_loop.cc41
-rw-r--r--base/message_pump.h18
-rw-r--r--base/message_pump_default.cc14
-rw-r--r--base/message_pump_win.cc5
-rw-r--r--base/task.h21
-rw-r--r--base/timer.cc15
-rw-r--r--base/timer.h3
7 files changed, 68 insertions, 49 deletions
diff --git a/base/message_loop.cc b/base/message_loop.cc
index cd44b92..410394f 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -66,7 +66,11 @@ MessageLoop::MessageLoop(Type type)
// TODO(darin): Choose the pump based on the requested type.
#if defined(OS_WIN)
- pump_ = new base::MessagePumpWin();
+ if (type_ == TYPE_DEFAULT) {
+ pump_ = new base::MessagePumpDefault();
+ } else {
+ pump_ = new base::MessagePumpWin();
+ }
#else
pump_ = new base::MessagePumpDefault();
#endif
@@ -180,10 +184,17 @@ void MessageLoop::Quit() {
void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here,
Task* task, int delay_ms) {
task->SetBirthPlace(from_here);
- DCHECK(delay_ms >= 0);
- DCHECK(!task->is_owned_by_message_loop());
- task->set_posted_task_delay(delay_ms);
- DCHECK(task->is_owned_by_message_loop());
+
+ DCHECK(!task->owned_by_message_loop_);
+ task->owned_by_message_loop_ = true;
+
+ if (delay_ms > 0) {
+ task->delayed_run_time_ =
+ Time::Now() + TimeDelta::FromMilliseconds(delay_ms);
+ } else {
+ DCHECK(delay_ms == 0) << "delay should not be negative";
+ }
+
PostTaskInternal(task);
}
@@ -231,7 +242,7 @@ bool MessageLoop::RunTimerTask(Timer* timer) {
HistogramEvent(kTimerEvent);
Task* task = timer->task();
- if (task->is_owned_by_message_loop()) {
+ if (task->owned_by_message_loop_) {
// We constructed it through PostDelayedTask().
DCHECK(!timer->repeating());
timer->set_task(NULL);
@@ -249,7 +260,7 @@ bool MessageLoop::RunTimerTask(Timer* timer) {
void MessageLoop::DiscardTimer(Timer* timer) {
Task* task = timer->task();
- if (task->is_owned_by_message_loop()) {
+ if (task->owned_by_message_loop_) {
DCHECK(!timer->repeating());
timer->set_task(NULL);
delete timer; // We constructed it through PostDelayedTask().
@@ -292,7 +303,7 @@ void MessageLoop::RunTask(Task* task) {
HistogramEvent(kTaskRunEvent);
// task may self-delete during Run() if we don't happen to own it.
// ...so check *before* we Run, since we can't check after.
- bool we_own_task = task->is_owned_by_message_loop();
+ bool we_own_task = task->owned_by_message_loop_;
task->Run();
if (we_own_task)
task->RecycleOrDelete(); // Relinquish control, and probably delete.
@@ -331,12 +342,16 @@ void MessageLoop::ReloadWorkQueue() {
while (!new_task_list.Empty()) {
Task* task = new_task_list.Pop();
- DCHECK(task->is_owned_by_message_loop());
-
- if (task->posted_task_delay() > 0)
- timer_manager_.StartTimer(task->posted_task_delay(), task, false);
- else
+ DCHECK(task->owned_by_message_loop_);
+
+ // TODO(darin): We should probably postpone starting the timer until we
+ // process the work queue as starting the timer here breaks the FIFO
+ // ordering of tasks.
+ if (!task->delayed_run_time_.is_null()) {
+ timer_manager_.StartTimer(new Timer(task->delayed_run_time_, task));
+ } else {
work_queue_.Push(task);
+ }
}
}
diff --git a/base/message_pump.h b/base/message_pump.h
index 4b53f4e..da4d214 100644
--- a/base/message_pump.h
+++ b/base/message_pump.h
@@ -54,21 +54,22 @@ class MessagePump : public RefCountedThreadSafe<MessagePump> {
// bool did_work = DoInternalWork();
// if (should_quit_)
// break;
+ //
// did_work |= delegate_->DoWork();
// if (should_quit_)
// break;
- // if (did_work)
- // continue;
//
- // did_work = delegate_->DoDelayedWork();
+ // did_work |= delegate_->DoDelayedWork();
// if (should_quit_)
// break;
+ //
// if (did_work)
// continue;
//
// did_work = delegate_->DoIdleWork();
// if (should_quit_)
// break;
+ //
// if (did_work)
// continue;
//
@@ -80,13 +81,10 @@ class MessagePump : public RefCountedThreadSafe<MessagePump> {
// completion (for example). WaitForWork is a private method that simply
// blocks until there is more work of any type to do.
//
- // Notice that the run loop alternates between calling DoInternalWork and
- // calling the delegate's DoWork method. This helps ensure that neither work
- // queue starves the other. However, DoDelayedWork may be starved. The
- // implementation may decide to periodically let some DoDelayedWork calls go
- // through if either DoInternalWork or DoWork is dominating the run loop.
- // This can be important for message pumps that are used to drive animations,
- // for example.
+ // Notice that the run loop cycles between calling DoInternalWork, DoWork,
+ // and DoDelayedWork methods. This helps ensure that neither work queue
+ // starves the other. This is important for message pumps that are used to
+ // drive animations, for example.
//
// Notice also that after each callout to foreign code, the run loop checks
// to see if it should quit. The Quit method is responsible for setting this
diff --git a/base/message_pump_default.cc b/base/message_pump_default.cc
index 0460b28..c88f465 100644
--- a/base/message_pump_default.cc
+++ b/base/message_pump_default.cc
@@ -20,26 +20,18 @@ void MessagePumpDefault::Run(Delegate* delegate) {
bool did_work = delegate->DoWork();
if (!keep_running_)
break;
- if (did_work)
- continue;
-
- // 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.
- did_work = delegate->DoDelayedWork(&delayed_work_time_);
+ did_work |= delegate->DoDelayedWork(&delayed_work_time_);
if (!keep_running_)
break;
+
if (did_work)
continue;
did_work = delegate->DoIdleWork();
if (!keep_running_)
break;
+
if (did_work)
continue;
diff --git a/base/message_pump_win.cc b/base/message_pump_win.cc
index 289e089..7b053c3 100644
--- a/base/message_pump_win.cc
+++ b/base/message_pump_win.cc
@@ -273,10 +273,7 @@ void MessagePumpWin::DoRunLoop() {
if (state_->should_quit)
break;
- if (more_work_is_plausible)
- continue;
-
- more_work_is_plausible =
+ more_work_is_plausible |=
state_->delegate->DoDelayedWork(&delayed_work_time_);
// If we did not process any delayed work, then we can assume that our
// existing WM_TIMER if any will fire when delayed work should run. We
diff --git a/base/task.h b/base/task.h
index 42277d4..99bec4e 100644
--- a/base/task.h
+++ b/base/task.h
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/non_thread_safe.h"
#include "base/revocable_store.h"
+#include "base/time.h"
#include "base/tracked.h"
#include "base/tuple.h"
@@ -24,6 +25,8 @@ class TimerManager;
class Task;
+// TODO(darin): Eliminate TaskBase. This data is ML specific and is not
+// applicable to other uses of Task.
class TaskBase : public tracked_objects::Tracked {
public:
TaskBase() { Reset(); }
@@ -53,28 +56,23 @@ class TaskBase : public tracked_objects::Tracked {
// derived classes should attempt this feat, as a replacement for creating a
// new instance.
void Reset() {
- posted_task_delay_ = -1;
priority_ = 0;
+ delayed_run_time_ = Time();
next_task_ = NULL;
nestable_ = true;
+ owned_by_message_loop_ = false;
}
private:
friend class base::TimerManager; // To check is_owned_by_message_loop().
- friend class MessageLoop; // To maintain posted_task_delay().
-
- // Access methods used ONLY by friends in MessageLoop and TimerManager
- int posted_task_delay() const { return posted_task_delay_; }
- bool is_owned_by_message_loop() const { return 0 <= posted_task_delay_; }
- void set_posted_task_delay(int delay) { posted_task_delay_ = delay; }
+ friend class MessageLoop; // To maintain posted_task_delay().
// Priority for execution by MessageLoop. 0 is default. Higher means run
// sooner, and lower (including negative) means run less soon.
int priority_;
- // Slot to hold delay if the task was passed to PostTask(). If it was not
- // passed to PostTask, then the delay is negative (the default).
- int posted_task_delay_;
+ // The time when a delayed task should be run.
+ Time delayed_run_time_;
// When tasks are collected into a queue by MessageLoop, this member is used
// to form a null terminated list.
@@ -84,6 +82,9 @@ class TaskBase : public tracked_objects::Tracked {
// only in the top level message loop.
bool nestable_;
+ // True if this Task is owned by the message loop.
+ bool owned_by_message_loop_;
+
DISALLOW_COPY_AND_ASSIGN(TaskBase);
};
diff --git a/base/timer.cc b/base/timer.cc
index 09a13f6..5cf6002 100644
--- a/base/timer.cc
+++ b/base/timer.cc
@@ -32,6 +32,19 @@ Timer::Timer(int delay, Task* task, bool repeating)
Reset();
}
+Timer::Timer(Time fire_time, Task* task)
+ : task_(task),
+ fire_time_(fire_time),
+ repeating_(false) {
+ timer_id_ = timer_id_counter_.GetNext();
+
+ // TODO(darin): kill off this stuff
+ creation_time_ = Time::Now();
+ delay_ = static_cast<int>((fire_time_ - creation_time_).InMilliseconds());
+ DCHECK(delay_ >= 0);
+ DHISTOGRAM_COUNTS(L"Timer.Durations", delay_);
+}
+
void Timer::Reset() {
creation_time_ = Time::Now();
fire_time_ = creation_time_ + TimeDelta::FromMilliseconds(delay_);
@@ -144,7 +157,7 @@ bool TimerManager::RunSomePendingTimers() {
// now (i.e., current task needs to be reentrant).
// TODO(jar): We may block tasks that we can queue from being popped.
if (!message_loop_->NestableTasksAllowed() &&
- !pending->task()->is_owned_by_message_loop())
+ !pending->task()->owned_by_message_loop_)
break;
timers_.pop();
diff --git a/base/timer.h b/base/timer.h
index add7844..d78423a 100644
--- a/base/timer.h
+++ b/base/timer.h
@@ -74,6 +74,9 @@ class Timer {
public:
Timer(int delay, Task* task, bool repeating);
+ // For one-shot timers, you can also specify the exact fire time.
+ Timer(Time fire_time, Task* task);
+
// The task to be run when the timer fires.
Task* task() const { return task_; }
void set_task(Task* task) { task_ = task; }