summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 16:02:23 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 16:02:23 +0000
commitb224f79da757434cee55b721806ff8553fc80b0a (patch)
tree881f07f4f5cb2de7565ecba99b085994fb7cd03e /base
parent7f7f19674990528290d019d36d588a6f02836f37 (diff)
downloadchromium_src-b224f79da757434cee55b721806ff8553fc80b0a.zip
chromium_src-b224f79da757434cee55b721806ff8553fc80b0a.tar.gz
chromium_src-b224f79da757434cee55b721806ff8553fc80b0a.tar.bz2
Add support for base::Closure in the MessageLoop, and reimplement the whole sucker on top of base::Closure. After this, all Task objects that are posted will be wrapped in a closure prior to dispatch.
BUG=35223 TEST=unittests. Review URL: http://codereview.chromium.org/6463013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@82300 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/bind_helpers.h2
-rw-r--r--base/bind_internal_win.h7
-rw-r--r--base/bind_internal_win.h.pump7
-rw-r--r--base/message_loop.cc228
-rw-r--r--base/message_loop.h92
-rw-r--r--base/message_loop_unittest.cc1072
6 files changed, 766 insertions, 642 deletions
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
index 3293dbb..27434e0 100644
--- a/base/bind_helpers.h
+++ b/base/bind_helpers.h
@@ -145,7 +145,7 @@ class SupportsAddRefAndRelease {
#pragma warning(default:4624)
#endif
- template <void(BaseMixin::*)(void)> struct Helper {};
+ template <void(BaseMixin::*)(void)> struct Helper {};
template <typename C>
static No& Check(Helper<&C::AddRef>*, Helper<&C::Release>*);
diff --git a/base/bind_internal_win.h b/base/bind_internal_win.h
index 976a4d7..85ba2ae 100644
--- a/base/bind_internal_win.h
+++ b/base/bind_internal_win.h
@@ -15,6 +15,11 @@
#define BASE_BIND_INTERNAL_WIN_H_
#pragma once
+// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
+// the same as __cdecl which would turn the following specializations into
+// multiple definitions.
+#if !defined(ARCH_CPU_X86_64)
+
namespace base {
namespace internal {
@@ -180,4 +185,6 @@ struct FunctionTraits<R(__fastcall *)(X1, X2, X3, X4, X5, X6)> {
} // namespace internal
} // namespace base
+#endif // !defined(ARCH_CPU_X86_64)
+
#endif // BASE_BIND_INTERNAL_WIN_H_
diff --git a/base/bind_internal_win.h.pump b/base/bind_internal_win.h.pump
index 06ceaca1..d293fcc 100644
--- a/base/bind_internal_win.h.pump
+++ b/base/bind_internal_win.h.pump
@@ -18,6 +18,11 @@ $var MAX_ARITY = 6
#define BASE_BIND_INTERNAL_WIN_H_
#pragma once
+// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
+// the same as __cdecl which would turn the following specializations into
+// multiple definitions.
+#if !defined(ARCH_CPU_X86_64)
+
namespace base {
namespace internal {
@@ -69,4 +74,6 @@ $for ARG [[
} // namespace internal
} // namespace base
+#endif // !defined(ARCH_CPU_X86_64)
+
#endif // BASE_BIND_INTERNAL_WIN_H_
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 1154c3e..bf0d25d 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -4,20 +4,18 @@
#include "base/message_loop.h"
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
-#endif
-
#include <algorithm>
+#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/message_pump_default.h"
#include "base/metrics/histogram.h"
+#include "base/scoped_ptr.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread_local.h"
+#include "base/tracked_objects.h"
#if defined(OS_MACOSX)
#include "base/message_pump_mac.h"
@@ -26,6 +24,8 @@
#include "base/message_pump_libevent.h"
#endif
#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
#include "base/message_pump_glib.h"
#endif
#if defined(TOUCH_UI)
@@ -81,6 +81,40 @@ const base::LinearHistogram::DescriptionPair event_descriptions_[] = {
bool enable_histogrammer_ = false;
+// TODO(ajwong): This is one use case for having a Owned() tag that behaves
+// like a "Unique" pointer. If we had that, and Tasks were always safe to
+// delete on MessageLoop shutdown, this class could just be a function.
+class TaskClosureAdapter : public base::RefCounted<TaskClosureAdapter> {
+ public:
+ // |should_leak_task| points to a flag variable that can be used to determine
+ // if this class should leak the Task on destruction. This is important
+ // at MessageLoop shutdown since not all tasks can be safely deleted without
+ // running. See MessageLoop::DeletePendingTasks() for the exact behavior
+ // of when a Task should be deleted. It is subtle.
+ TaskClosureAdapter(Task* task, bool* should_leak_task)
+ : task_(task),
+ should_leak_task_(should_leak_task) {
+ }
+
+ void Run() {
+ task_->Run();
+ delete task_;
+ task_ = NULL;
+ }
+
+ private:
+ friend class base::RefCounted<TaskClosureAdapter>;
+
+ ~TaskClosureAdapter() {
+ if (!*should_leak_task_) {
+ delete task_;
+ }
+ }
+
+ Task* task_;
+ bool* should_leak_task_;
+};
+
} // namespace
//------------------------------------------------------------------------------
@@ -124,6 +158,7 @@ MessageLoop::MessageLoop(Type type)
exception_restoration_(false),
message_histogram_(NULL),
state_(NULL),
+ should_leak_tasks_(true),
#ifdef OS_WIN
os_modal_loop_(false),
#endif // OS_WIN
@@ -220,22 +255,74 @@ void MessageLoop::RemoveDestructionObserver(
void MessageLoop::PostTask(
const tracked_objects::Location& from_here, Task* task) {
- PostTask_Helper(from_here, task, 0, true);
+ PendingTask pending_task(
+ base::Bind(&TaskClosureAdapter::Run,
+ new TaskClosureAdapter(task, &should_leak_tasks_)),
+ from_here,
+ CalculateDelayedRuntime(0), true);
+ AddToIncomingQueue(&pending_task);
}
void MessageLoop::PostDelayedTask(
const tracked_objects::Location& from_here, Task* task, int64 delay_ms) {
- PostTask_Helper(from_here, task, delay_ms, true);
+ PendingTask pending_task(
+ base::Bind(&TaskClosureAdapter::Run,
+ new TaskClosureAdapter(task, &should_leak_tasks_)),
+ from_here,
+ CalculateDelayedRuntime(delay_ms), true);
+ AddToIncomingQueue(&pending_task);
}
void MessageLoop::PostNonNestableTask(
const tracked_objects::Location& from_here, Task* task) {
- PostTask_Helper(from_here, task, 0, false);
+ PendingTask pending_task(
+ base::Bind(&TaskClosureAdapter::Run,
+ new TaskClosureAdapter(task, &should_leak_tasks_)),
+ from_here,
+ CalculateDelayedRuntime(0), false);
+ AddToIncomingQueue(&pending_task);
}
void MessageLoop::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here, Task* task, int64 delay_ms) {
- PostTask_Helper(from_here, task, delay_ms, false);
+ PendingTask pending_task(
+ base::Bind(&TaskClosureAdapter::Run,
+ new TaskClosureAdapter(task, &should_leak_tasks_)),
+ from_here,
+ CalculateDelayedRuntime(delay_ms), false);
+ AddToIncomingQueue(&pending_task);
+}
+
+void MessageLoop::PostTask(
+ const tracked_objects::Location& from_here, const base::Closure& task) {
+ DCHECK(!task.is_null());
+ PendingTask pending_task(task, from_here, CalculateDelayedRuntime(0), true);
+ AddToIncomingQueue(&pending_task);
+}
+
+void MessageLoop::PostDelayedTask(
+ const tracked_objects::Location& from_here, const base::Closure& task,
+ int64 delay_ms) {
+ DCHECK(!task.is_null());
+ PendingTask pending_task(task, from_here,
+ CalculateDelayedRuntime(delay_ms), true);
+ AddToIncomingQueue(&pending_task);
+}
+
+void MessageLoop::PostNonNestableTask(
+ const tracked_objects::Location& from_here, const base::Closure& task) {
+ DCHECK(!task.is_null());
+ PendingTask pending_task(task, from_here, CalculateDelayedRuntime(0), false);
+ AddToIncomingQueue(&pending_task);
+}
+
+void MessageLoop::PostNonNestableDelayedTask(
+ const tracked_objects::Location& from_here, const base::Closure& task,
+ int64 delay_ms) {
+ DCHECK(!task.is_null());
+ PendingTask pending_task(task, from_here,
+ CalculateDelayedRuntime(delay_ms), false);
+ AddToIncomingQueue(&pending_task);
}
void MessageLoop::Run() {
@@ -353,31 +440,40 @@ bool MessageLoop::ProcessNextDelayedNonNestableTask() {
if (deferred_non_nestable_work_queue_.empty())
return false;
- Task* task = deferred_non_nestable_work_queue_.front().task;
+ PendingTask pending_task = deferred_non_nestable_work_queue_.front();
deferred_non_nestable_work_queue_.pop();
- RunTask(task);
+ RunTask(pending_task);
return true;
}
-void MessageLoop::RunTask(Task* task) {
+void MessageLoop::RunTask(const PendingTask& pending_task) {
DCHECK(nestable_tasks_allowed_);
// Execute the task and assume the worst: It is probably not reentrant.
nestable_tasks_allowed_ = false;
HistogramEvent(kTaskRunEvent);
FOR_EACH_OBSERVER(TaskObserver, task_observers_,
- WillProcessTask(task));
- task->Run();
- FOR_EACH_OBSERVER(TaskObserver, task_observers_, DidProcessTask(task));
- delete task;
+ WillProcessTask(pending_task.time_posted));
+ pending_task.task.Run();
+ FOR_EACH_OBSERVER(TaskObserver, task_observers_,
+ DidProcessTask(pending_task.time_posted));
+
+#if defined(TRACK_ALL_TASK_OBJECTS)
+ if (tracked_objects::ThreadData::IsActive() && pending_task.post_births) {
+ tracked_objects::ThreadData::current()->TallyADeath(
+ *pending_task.post_births,
+ TimeTicks::Now() - pending_task.time_posted);
+ }
+#endif // defined(TRACK_ALL_TASK_OBJECTS)
nestable_tasks_allowed_ = true;
}
-bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
+bool MessageLoop::DeferOrRunPendingTask(
+ const PendingTask& pending_task) {
if (pending_task.nestable || state_->run_depth == 1) {
- RunTask(pending_task.task);
+ RunTask(pending_task);
// Show that we ran a task (Note: a new one might arrive as a
// consequence!).
return true;
@@ -419,6 +515,18 @@ void MessageLoop::ReloadWorkQueue() {
bool MessageLoop::DeletePendingTasks() {
bool did_work = !work_queue_.empty();
+ // TODO(darin): Delete all tasks once it is safe to do so.
+ // Until it is totally safe, just do it when running Purify or
+ // Valgrind.
+ //
+ // See http://crbug.com/61131
+ //
+#if defined(PURIFY) || defined(USE_HEAPCHECKER)
+ should_leak_tasks_ = false;
+#else
+ if (RunningOnValgrind())
+ should_leak_tasks_ = false;
+#endif // defined(OS_POSIX)
while (!work_queue_.empty()) {
PendingTask pending_task = work_queue_.front();
work_queue_.pop();
@@ -427,52 +535,31 @@ bool MessageLoop::DeletePendingTasks() {
// normally be deleted in case of any funny dependencies between delayed
// tasks.
AddToDelayedWorkQueue(pending_task);
- } else {
- // TODO(darin): Delete all tasks once it is safe to do so.
- // Until it is totally safe, just do it when running Purify or
- // Valgrind.
-#if defined(PURIFY) || defined(USE_HEAPCHECKER)
- delete pending_task.task;
-#else
- if (RunningOnValgrind())
- delete pending_task.task;
-#endif // defined(OS_POSIX)
}
}
did_work |= !deferred_non_nestable_work_queue_.empty();
while (!deferred_non_nestable_work_queue_.empty()) {
- // TODO(darin): Delete all tasks once it is safe to do so.
- // Until it is totaly safe, only delete them under Purify and Valgrind.
- Task* task = NULL;
-#if defined(PURIFY) || defined(USE_HEAPCHECKER)
- task = deferred_non_nestable_work_queue_.front().task;
-#else
- if (RunningOnValgrind())
- task = deferred_non_nestable_work_queue_.front().task;
-#endif
deferred_non_nestable_work_queue_.pop();
- if (task)
- delete task;
}
did_work |= !delayed_work_queue_.empty();
+
+ // Historically, we always delete the task regardless of valgrind status. It's
+ // not completely clear why we want to leak them in the loops above. This
+ // code is replicating legacy behavior, and should not be considered
+ // absolutely "correct" behavior. See TODO above about deleting all tasks
+ // when it's safe.
+ should_leak_tasks_ = false;
while (!delayed_work_queue_.empty()) {
- Task* task = delayed_work_queue_.top().task;
delayed_work_queue_.pop();
- delete task;
}
+ should_leak_tasks_ = true;
return did_work;
}
-// Possibly called on a background thread!
-void MessageLoop::PostTask_Helper(
- const tracked_objects::Location& from_here, Task* task, int64 delay_ms,
- bool nestable) {
- task->SetBirthPlace(from_here);
-
- PendingTask pending_task(task, nestable);
-
+TimeTicks MessageLoop::CalculateDelayedRuntime(int64 delay_ms) {
+ TimeTicks delayed_run_time;
if (delay_ms > 0) {
- pending_task.delayed_run_time =
+ delayed_run_time =
TimeTicks::Now() + TimeDelta::FromMilliseconds(delay_ms);
#if defined(OS_WIN)
@@ -504,6 +591,11 @@ void MessageLoop::PostTask_Helper(
}
#endif
+ return delayed_run_time;
+}
+
+// Possibly called on a background thread!
+void MessageLoop::AddToIncomingQueue(PendingTask* pending_task) {
// Warning: Don't try to short-circuit, and handle this thread's tasks more
// directly, as it could starve handling of foreign threads. Put every task
// into this queue.
@@ -513,7 +605,8 @@ void MessageLoop::PostTask_Helper(
base::AutoLock locked(incoming_queue_lock_);
bool was_empty = incoming_queue_.empty();
- incoming_queue_.push(pending_task);
+ incoming_queue_.push(*pending_task);
+ pending_task->task.Reset();
if (!was_empty)
return; // Someone else should have started the sub-pump.
@@ -566,8 +659,8 @@ bool MessageLoop::DoWork() {
work_queue_.pop();
if (!pending_task.delayed_run_time.is_null()) {
AddToDelayedWorkQueue(pending_task);
- // If we changed the topmost task, then it is time to re-schedule.
- if (delayed_work_queue_.top().task == pending_task.task)
+ // If we changed the topmost task, then it is time to reschedule.
+ if (delayed_work_queue_.top().task.Equals(pending_task.task))
pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
} else {
if (DeferOrRunPendingTask(pending_task))
@@ -580,7 +673,7 @@ bool MessageLoop::DoWork() {
return false;
}
-bool MessageLoop::DoDelayedWork(base::TimeTicks* next_delayed_work_time) {
+bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
recent_time_ = *next_delayed_work_time = TimeTicks();
return false;
@@ -648,6 +741,33 @@ MessageLoop::AutoRunState::~AutoRunState() {
//------------------------------------------------------------------------------
// MessageLoop::PendingTask
+MessageLoop::PendingTask::PendingTask(
+ const base::Closure& task,
+ const tracked_objects::Location& posted_from,
+ TimeTicks delayed_run_time,
+ bool nestable)
+ : task(task),
+ time_posted(TimeTicks::Now()),
+ delayed_run_time(delayed_run_time),
+ sequence_num(0),
+ nestable(nestable) {
+#if defined(TRACK_ALL_TASK_OBJECTS)
+ if (tracked_objects::ThreadData::IsActive()) {
+ tracked_objects::ThreadData* current_thread_data =
+ tracked_objects::ThreadData::current();
+ if (current_thread_data) {
+ post_births = current_thread_data->TallyABirth(posted_from);
+ } else {
+ // Shutdown started, and this thread wasn't registered.
+ post_births = NULL;
+ }
+ }
+#endif // defined(TRACK_ALL_TASK_OBJECTS)
+}
+
+MessageLoop::PendingTask::~PendingTask() {
+}
+
bool MessageLoop::PendingTask::operator<(const PendingTask& other) const {
// Since the top of a priority queue is defined as the "greatest" element, we
// need to invert the comparison here. We want the smaller time to be at the
diff --git a/base/message_loop.h b/base/message_loop.h
index 519e4a3..b601d9e 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -11,11 +11,14 @@
#include "base/base_api.h"
#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/message_pump.h"
#include "base/observer_list.h"
#include "base/synchronization/lock.h"
#include "base/task.h"
+#include "base/time.h"
+#include "base/tracked.h"
#if defined(OS_WIN)
// We need this to declare base::MessagePumpWin::Dispatcher, which we should
@@ -36,6 +39,12 @@ namespace base {
class Histogram;
}
+#if defined(TRACK_ALL_TASK_OBJECTS)
+namespace tracked_objects {
+class Births;
+}
+#endif // defined(TRACK_ALL_TASK_OBJECTS)
+
// A MessageLoop is used to process events for a particular thread. There is
// at most one MessageLoop instance per thread.
//
@@ -163,6 +172,29 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
void PostNonNestableDelayedTask(
const tracked_objects::Location& from_here, Task* task, int64 delay_ms);
+ // TODO(ajwong): Remove the functions above once the Task -> Closure migration
+ // is complete.
+ //
+ // There are 2 sets of Post*Task functions, one which takes the older Task*
+ // function object representation, and one that takes the newer base::Closure.
+ // We have this overload to allow a staged transition between the two systems.
+ // Once the transition is done, the functions above should be deleted.
+ void PostTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task);
+
+ void PostDelayedTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task, int64 delay_ms);
+
+ void PostNonNestableTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task);
+
+ void PostNonNestableDelayedTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task, int64 delay_ms);
+
// A variant on PostTask that deletes the given object. This is useful
// if the object needs to live until the next run of the MessageLoop (for
// example, deleting a RenderProcessHost from within an IPC callback is not
@@ -289,10 +321,10 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
TaskObserver();
// This method is called before processing a task.
- virtual void WillProcessTask(const Task* task) = 0;
+ virtual void WillProcessTask(base::TimeTicks time_posted) = 0;
// This method is called after processing a task.
- virtual void DidProcessTask(const Task* task) = 0;
+ virtual void DidProcessTask(base::TimeTicks time_posted) = 0;
protected:
virtual ~TaskObserver();
@@ -356,17 +388,34 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
// This structure is copied around by value.
struct PendingTask {
- PendingTask(Task* task, bool nestable)
- : task(task), sequence_num(0), nestable(nestable) {
- }
+ PendingTask(const base::Closure& task,
+ const tracked_objects::Location& posted_from,
+ base::TimeTicks delayed_run_time,
+ bool nestable);
+ ~PendingTask();
// Used to support sorting.
bool operator<(const PendingTask& other) const;
- Task* task; // The task to run.
- base::TimeTicks delayed_run_time; // The time when the task should be run.
- int sequence_num; // Secondary sort key for run time.
- bool nestable; // OK to dispatch from a nested loop.
+ // The task to run.
+ base::Closure task;
+
+#if defined(TRACK_ALL_TASK_OBJECTS)
+ // Counter for location where the Closure was posted from.
+ tracked_objects::Births* post_births;
+#endif // defined(TRACK_ALL_TASK_OBJECTS)
+
+ // Time this PendingTask was posted.
+ base::TimeTicks time_posted;
+
+ // The time when the task should be run.
+ base::TimeTicks delayed_run_time;
+
+ // Secondary sort key for run time.
+ int sequence_num;
+
+ // OK to dispatch from a nested loop.
+ bool nestable;
};
class TaskQueue : public std::queue<PendingTask> {
@@ -406,8 +455,8 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
// Called to process any delayed non-nestable tasks.
bool ProcessNextDelayedNonNestableTask();
- // Runs the specified task and deletes it.
- void RunTask(Task* task);
+ // Runs the specified PendingTask.
+ void RunTask(const PendingTask& pending_task);
// Calls RunTask or queues the pending_task on the deferred task list if it
// cannot be run right now. Returns true if the task was run.
@@ -416,6 +465,14 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
// Adds the pending task to delayed_work_queue_.
void AddToDelayedWorkQueue(const PendingTask& pending_task);
+ // Adds the pending task to our incoming_queue_.
+ //
+ // Caller retains ownership of |pending_task|, but this function will
+ // reset the value of pending_task->task. This is needed to ensure
+ // that the posting call stack does not retain pending_task->task
+ // beyond this function call.
+ void AddToIncomingQueue(PendingTask* pending_task);
+
// Load tasks from the incoming_queue_ into work_queue_ if the latter is
// empty. The former requires a lock to access, while the latter is directly
// accessible on this thread.
@@ -426,9 +483,8 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
// true if some work was done.
bool DeletePendingTasks();
- // Post a task to our incomming queue.
- void PostTask_Helper(const tracked_objects::Location& from_here, Task* task,
- int64 delay_ms, bool nestable);
+ // Calcuates the time at which a PendingTask should run.
+ base::TimeTicks CalculateDelayedRuntime(int64 delay_ms);
// Start recording histogram info about events and action IF it was enabled
// and IF the statistics recorder can accept a registration of our histogram.
@@ -477,14 +533,18 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
// A null terminated list which creates an incoming_queue of tasks that are
// acquired under a mutex for processing on this instance's thread. These
- // tasks have not yet been sorted out into items for our work_queue_ vs
- // items that will be handled by the TimerManager.
+ // tasks have not yet been sorted out into items for our work_queue_ vs items
+ // that will be handled by the TimerManager.
TaskQueue incoming_queue_;
// Protect access to incoming_queue_.
mutable base::Lock incoming_queue_lock_;
RunState* state_;
+ // The need for this variable is subtle. Please see implementation comments
+ // around where it is used.
+ bool should_leak_tasks_;
+
#if defined(OS_WIN)
base::TimeTicks high_resolution_timer_expiration_;
// Should be set to true before calling Windows APIs like TrackPopupMenu, etc
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
index cd681f3..be40f39 100644
--- a/base/message_loop_unittest.cc
+++ b/base/message_loop_unittest.cc
@@ -4,6 +4,9 @@
#include <vector>
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
@@ -25,6 +28,7 @@ using base::PlatformThread;
using base::Thread;
using base::Time;
using base::TimeDelta;
+using base::TimeTicks;
// TODO(darin): Platform-specific MessageLoop tests should be grouped together
// to avoid chopping this file up with so many #ifdefs.
@@ -80,19 +84,9 @@ class Foo : public base::RefCounted<Foo> {
std::string result_;
};
-class QuitMsgLoop : public base::RefCounted<QuitMsgLoop> {
- public:
- void QuitNow() {
- MessageLoop::current()->Quit();
- }
-
- private:
- friend class base::RefCounted<QuitMsgLoop>;
-
- ~QuitMsgLoop() {}
-};
-
-void RunTest_PostTask(MessageLoop::Type message_loop_type) {
+// TODO(ajwong): Remove this once we've finished getting rid of the PostTask()
+// compatibility methods.
+void RunTest_PostLegacyTask(MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
// Add tests to message loop
@@ -112,9 +106,38 @@ void RunTest_PostTask(MessageLoop::Type message_loop_type) {
foo.get(), &Foo::Test2Mixed, a, &d));
// After all tests, post a message that will shut down the message loop
- scoped_refptr<QuitMsgLoop> quit(new QuitMsgLoop());
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- quit.get(), &QuitMsgLoop::QuitNow));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
+
+ // Now kick things off
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(foo->test_count(), 105);
+ EXPECT_EQ(foo->result(), "abacad");
+}
+
+void RunTest_PostTask(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
+ // Add tests to message loop
+ scoped_refptr<Foo> foo(new Foo());
+ std::string a("a"), b("b"), c("c"), d("d");
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test0, foo.get()));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test1ConstRef, foo.get(), a));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test1Ptr, foo.get(), &b));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test1Int, foo.get(), 100));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test2Ptr, foo.get(), &a, &c));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test2Mixed, foo.get(), a, &d));
+
+ // After all tests, post a message that will shut down the message loop
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
// Now kick things off
MessageLoop::current()->Run();
@@ -129,23 +152,22 @@ void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) {
// Add tests to message loop
scoped_refptr<Foo> foo(new Foo());
std::string a("a"), b("b"), c("c"), d("d");
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- foo.get(), &Foo::Test0));
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- foo.get(), &Foo::Test1ConstRef, a));
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- foo.get(), &Foo::Test1Ptr, &b));
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- foo.get(), &Foo::Test1Int, 100));
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- foo.get(), &Foo::Test2Ptr, &a, &c));
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- foo.get(), &Foo::Test2Mixed, a, &d));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test0, foo.get()));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test1ConstRef, foo.get(), a));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test1Ptr, foo.get(), &b));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test1Int, foo.get(), 100));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test2Ptr, foo.get(), &a, &c));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &Foo::Test2Mixed, foo.get(), a, &d));
// After all tests, post a message that will shut down the message loop
- scoped_refptr<QuitMsgLoop> quit(new QuitMsgLoop());
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- quit.get(), &QuitMsgLoop::QuitNow));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
// Now kick things off with the SEH block active.
MessageLoop::current()->set_exception_restoration(true);
@@ -156,39 +178,23 @@ void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) {
EXPECT_EQ(foo->result(), "abacad");
}
-// This class runs slowly to simulate a large amount of work being done.
-class SlowTask : public Task {
- public:
- SlowTask(int pause_ms, int* quit_counter)
- : pause_ms_(pause_ms), quit_counter_(quit_counter) {
- }
- virtual void Run() {
- PlatformThread::Sleep(pause_ms_);
- if (--(*quit_counter_) == 0)
+// This function runs slowly to simulate a large amount of work being done.
+static void SlowFunc(int pause_ms, int* quit_counter) {
+ PlatformThread::Sleep(pause_ms);
+ if (--(*quit_counter) == 0)
MessageLoop::current()->Quit();
- }
- private:
- int pause_ms_;
- int* quit_counter_;
-};
+}
-// This class records the time when Run was called in a Time object, which is
+// This function records the time when Run was called in a Time object, which is
// useful for building a variety of MessageLoop tests.
-class RecordRunTimeTask : public SlowTask {
- public:
- RecordRunTimeTask(Time* run_time, int* quit_counter)
- : SlowTask(10, quit_counter), run_time_(run_time) {
- }
- virtual void Run() {
- *run_time_ = Time::Now();
+static void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
+ *run_time = Time::Now();
+
// Cause our Run function to take some time to execute. As a result we can
- // count on subsequent RecordRunTimeTask objects running at a future time,
+ // count on subsequent RecordRunTimeFunc()s running at a future time,
// without worry about the resolution of our system clock being an issue.
- SlowTask::Run();
- }
- private:
- Time* run_time_;
-};
+ SlowFunc(10, quit_counter);
+}
void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
@@ -201,7 +207,8 @@ void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) {
Time run_time;
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), kDelayMS);
+ FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+ kDelayMS);
Time time_before_run = Time::Now();
loop.Run();
@@ -211,20 +218,20 @@ void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) {
EXPECT_LT(kDelayMS, (time_after_run - time_before_run).InMilliseconds());
}
-void RunTest_PostDelayedTask_InDelayOrder(MessageLoop::Type message_loop_type) {
+void RunTest_PostDelayedTask_InDelayOrder(
+ MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
// Test that two tasks with different delays run in the right order.
-
int num_tasks = 2;
Time run_time1, run_time2;
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), 200);
+ FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), 200);
// If we get a large pause in execution (due to a context switch) here, this
// test could fail.
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 10);
+ FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), 10);
loop.Run();
EXPECT_EQ(0, num_tasks);
@@ -232,7 +239,8 @@ void RunTest_PostDelayedTask_InDelayOrder(MessageLoop::Type message_loop_type) {
EXPECT_TRUE(run_time2 < run_time1);
}
-void RunTest_PostDelayedTask_InPostOrder(MessageLoop::Type message_loop_type) {
+void RunTest_PostDelayedTask_InPostOrder(
+ MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
// Test that two tasks with the same delay run in the order in which they
@@ -249,9 +257,11 @@ void RunTest_PostDelayedTask_InPostOrder(MessageLoop::Type message_loop_type) {
Time run_time1, run_time2;
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), kDelayMS);
+ FROM_HERE,
+ base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelayMS);
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), kDelayMS);
+ FROM_HERE,
+ base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelayMS);
loop.Run();
EXPECT_EQ(0, num_tasks);
@@ -271,10 +281,9 @@ void RunTest_PostDelayedTask_InPostOrder_2(
int num_tasks = 2;
Time run_time;
- loop.PostTask(
- FROM_HERE, new SlowTask(kPauseMS, &num_tasks));
+ loop.PostTask(FROM_HERE, base::Bind(&SlowFunc, kPauseMS, &num_tasks));
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), 10);
+ FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks), 10);
Time time_before_run = Time::Now();
loop.Run();
@@ -300,10 +309,11 @@ void RunTest_PostDelayedTask_InPostOrder_3(
// Clutter the ML with tasks.
for (int i = 1; i < num_tasks; ++i)
- loop.PostTask(FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks));
+ loop.PostTask(FROM_HERE,
+ base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks));
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 1);
+ FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), 1);
loop.Run();
EXPECT_EQ(0, num_tasks);
@@ -311,7 +321,8 @@ void RunTest_PostDelayedTask_InPostOrder_3(
EXPECT_TRUE(run_time2 > run_time1);
}
-void RunTest_PostDelayedTask_SharedTimer(MessageLoop::Type message_loop_type) {
+void RunTest_PostDelayedTask_SharedTimer(
+ MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
// Test that the interval of the timer, used to run the next delayed task, is
@@ -323,9 +334,11 @@ void RunTest_PostDelayedTask_SharedTimer(MessageLoop::Type message_loop_type) {
Time run_time1, run_time2;
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), 1000000);
+ FROM_HERE,
+ base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
+ 1000000);
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 10);
+ FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), 10);
Time start_time = Time::Now();
@@ -348,27 +361,15 @@ void RunTest_PostDelayedTask_SharedTimer(MessageLoop::Type message_loop_type) {
#if defined(OS_WIN)
-class SubPumpTask : public Task {
- public:
- virtual void Run() {
- MessageLoop::current()->SetNestableTasksAllowed(true);
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- MessageLoop::current()->Quit();
- }
-};
-
-class SubPumpQuitTask : public Task {
- public:
- SubPumpQuitTask() {
- }
- virtual void Run() {
- PostQuitMessage(0);
+void SubPumpFunc() {
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
}
-};
+ MessageLoop::current()->Quit();
+}
void RunTest_PostDelayedTask_SharedTimer_SubPump() {
MessageLoop loop(MessageLoop::TYPE_UI);
@@ -381,15 +382,16 @@ void RunTest_PostDelayedTask_SharedTimer_SubPump() {
int num_tasks = 1;
Time run_time;
- loop.PostTask(FROM_HERE, new SubPumpTask());
+ loop.PostTask(FROM_HERE, base::Bind(&SubPumpFunc));
// This very delayed task should never run.
loop.PostDelayedTask(
- FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), 1000000);
+ FROM_HERE,
+ base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+ 1000000);
- // This slightly delayed task should run from within SubPumpTask::Run().
- loop.PostDelayedTask(
- FROM_HERE, new SubPumpQuitTask(), 10);
+ // This slightly delayed task should run from within SubPumpFunc).
+ loop.PostDelayedTask(FROM_HERE, base::Bind(&PostQuitMessage, 0), 10);
Time start_time = Time::Now();
@@ -411,69 +413,73 @@ void RunTest_PostDelayedTask_SharedTimer_SubPump() {
#endif // defined(OS_WIN)
-class RecordDeletionTask : public Task {
+// This is used to inject a test point for recording the destructor calls for
+// Closure objects send to MessageLoop::PostTask(). It is awkward usage since we
+// are trying to hook the actual destruction, which is not a common operation.
+class RecordDeletionProbe : public base::RefCounted<RecordDeletionProbe> {
public:
- RecordDeletionTask(Task* post_on_delete, bool* was_deleted)
+ RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted)
: post_on_delete_(post_on_delete), was_deleted_(was_deleted) {
}
- ~RecordDeletionTask() {
+ ~RecordDeletionProbe() {
*was_deleted_ = true;
if (post_on_delete_)
- MessageLoop::current()->PostTask(FROM_HERE, post_on_delete_);
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&RecordDeletionProbe::Run, post_on_delete_.get()));
}
virtual void Run() {}
private:
- Task* post_on_delete_;
+ scoped_refptr<RecordDeletionProbe> post_on_delete_;
bool* was_deleted_;
};
-void RunTest_EnsureTaskDeletion(MessageLoop::Type message_loop_type) {
+void RunTest_EnsureDeletion(MessageLoop::Type message_loop_type) {
bool a_was_deleted = false;
bool b_was_deleted = false;
{
MessageLoop loop(message_loop_type);
loop.PostTask(
- FROM_HERE, new RecordDeletionTask(NULL, &a_was_deleted));
+ FROM_HERE, base::Bind(&RecordDeletionProbe::Run,
+ new RecordDeletionProbe(NULL, &a_was_deleted)));
loop.PostDelayedTask(
- FROM_HERE, new RecordDeletionTask(NULL, &b_was_deleted), 1000);
+ FROM_HERE, base::Bind(&RecordDeletionProbe::Run,
+ new RecordDeletionProbe(NULL, &b_was_deleted)),
+ 1000); // TODO(ajwong): Do we really need 1000ms here?
}
EXPECT_TRUE(a_was_deleted);
EXPECT_TRUE(b_was_deleted);
}
-void RunTest_EnsureTaskDeletion_Chain(MessageLoop::Type message_loop_type) {
+void RunTest_EnsureDeletion_Chain(MessageLoop::Type message_loop_type) {
bool a_was_deleted = false;
bool b_was_deleted = false;
bool c_was_deleted = false;
{
MessageLoop loop(message_loop_type);
- RecordDeletionTask* a = new RecordDeletionTask(NULL, &a_was_deleted);
- RecordDeletionTask* b = new RecordDeletionTask(a, &b_was_deleted);
- RecordDeletionTask* c = new RecordDeletionTask(b, &c_was_deleted);
- loop.PostTask(FROM_HERE, c);
+ // The scoped_refptr for each of the below is held either by the chained
+ // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
+ RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted);
+ RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted);
+ RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted);
+ loop.PostTask(FROM_HERE, base::Bind(&RecordDeletionProbe::Run, c));
}
EXPECT_TRUE(a_was_deleted);
EXPECT_TRUE(b_was_deleted);
EXPECT_TRUE(c_was_deleted);
}
-class NestingTest : public Task {
- public:
- explicit NestingTest(int* depth) : depth_(depth) {
- }
- void Run() {
- if (*depth_ > 0) {
- *depth_ -= 1;
- MessageLoop::current()->PostTask(FROM_HERE, new NestingTest(depth_));
+void NestingFunc(int* depth) {
+ if (*depth > 0) {
+ *depth -= 1;
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&NestingFunc, depth));
- MessageLoop::current()->SetNestableTasksAllowed(true);
- MessageLoop::current()->Run();
- }
- MessageLoop::current()->Quit();
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ MessageLoop::current()->Run();
}
- private:
- int* depth_;
-};
+ MessageLoop::current()->Quit();
+}
#if defined(OS_WIN)
@@ -485,13 +491,14 @@ LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) {
// This task throws an SEH exception: initially write to an invalid address.
// If the right SEH filter is installed, it will fix the error.
-class CrasherTask : public Task {
+class Crasher : public base::RefCounted<Crasher> {
public:
// Ctor. If trash_SEH_handler is true, the task will override the unhandled
// exception handler with one sure to crash this test.
- explicit CrasherTask(bool trash_SEH_handler)
+ explicit Crasher(bool trash_SEH_handler)
: trash_SEH_handler_(trash_SEH_handler) {
}
+
void Run() {
PlatformThread::Sleep(1);
if (trash_SEH_handler_)
@@ -502,7 +509,7 @@ class CrasherTask : public Task {
#if defined(_M_IX86)
__asm {
- mov eax, dword ptr [CrasherTask::bad_array_]
+ mov eax, dword ptr [Crasher::bad_array_]
mov byte ptr [eax], 66
}
@@ -527,17 +534,17 @@ class CrasherTask : public Task {
static char valid_store_;
};
-volatile char* CrasherTask::bad_array_ = 0;
-char CrasherTask::valid_store_ = 0;
+volatile char* Crasher::bad_array_ = 0;
+char Crasher::valid_store_ = 0;
// This SEH filter fixes the problem and retries execution. Fixing requires
-// that the last instruction: mov eax, [CrasherTask::bad_array_] to be retried
+// that the last instruction: mov eax, [Crasher::bad_array_] to be retried
// so we move the instruction pointer 5 bytes back.
-LONG WINAPI HandleCrasherTaskException(EXCEPTION_POINTERS *ex_info) {
+LONG WINAPI HandleCrasherException(EXCEPTION_POINTERS *ex_info) {
if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_EXECUTE_HANDLER;
- CrasherTask::FixError();
+ Crasher::FixError();
#if defined(_M_IX86)
@@ -559,9 +566,11 @@ void RunTest_Crasher(MessageLoop::Type message_loop_type) {
return;
LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
- ::SetUnhandledExceptionFilter(&HandleCrasherTaskException);
+ ::SetUnhandledExceptionFilter(&HandleCrasherException);
- MessageLoop::current()->PostTask(FROM_HERE, new CrasherTask(false));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&Crasher::Run, new Crasher(false)));
MessageLoop::current()->set_exception_restoration(true);
MessageLoop::current()->Run();
MessageLoop::current()->set_exception_restoration(false);
@@ -576,9 +585,11 @@ void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) {
return;
LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
- ::SetUnhandledExceptionFilter(&HandleCrasherTaskException);
+ ::SetUnhandledExceptionFilter(&HandleCrasherException);
- MessageLoop::current()->PostTask(FROM_HERE, new CrasherTask(true));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&Crasher::Run, new Crasher(true)));
MessageLoop::current()->set_exception_restoration(true);
MessageLoop::current()->Run();
MessageLoop::current()->set_exception_restoration(false);
@@ -592,7 +603,8 @@ void RunTest_Nesting(MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
int depth = 100;
- MessageLoop::current()->PostTask(FROM_HERE, new NestingTest(&depth));
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&NestingFunc, &depth));
MessageLoop::current()->Run();
EXPECT_EQ(depth, 0);
}
@@ -627,8 +639,6 @@ struct TaskItem {
}
};
-typedef std::vector<TaskItem> TaskList;
-
std::ostream& operator <<(std::ostream& os, TaskType type) {
switch (type) {
case MESSAGEBOX: os << "MESSAGEBOX"; break;
@@ -654,223 +664,141 @@ std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
return os << item.type << " " << item.cookie << " ends";
}
-// Saves the order the tasks ran.
-class OrderedTasks : public Task {
+class TaskList {
public:
- OrderedTasks(TaskList* order, int cookie)
- : order_(order),
- type_(ORDERERD),
- cookie_(cookie) {
- }
- OrderedTasks(TaskList* order, TaskType type, int cookie)
- : order_(order),
- type_(type),
- cookie_(cookie) {
- }
-
- void RunStart() {
- TaskItem item(type_, cookie_, true);
- DVLOG(1) << item;
- order_->push_back(item);
- }
- void RunEnd() {
- TaskItem item(type_, cookie_, false);
+ void RecordStart(TaskType type, int cookie) {
+ TaskItem item(type, cookie, true);
DVLOG(1) << item;
- order_->push_back(item);
+ task_list_.push_back(item);
}
- virtual void Run() {
- RunStart();
- RunEnd();
+ void RecordEnd(TaskType type, int cookie) {
+ TaskItem item(type, cookie, false);
+ DVLOG(1) << item;
+ task_list_.push_back(item);
}
- protected:
- TaskList* order() const {
- return order_;
+ size_t Size() {
+ return task_list_.size();
}
- int cookie() const {
- return cookie_;
+ TaskItem Get(int n) {
+ return task_list_[n];
}
private:
- TaskList* order_;
- TaskType type_;
- int cookie_;
+ std::vector<TaskItem> task_list_;
};
+// Saves the order the tasks ran.
+void OrderedFunc(TaskList* order, int cookie) {
+ order->RecordStart(ORDERERD, cookie);
+ order->RecordEnd(ORDERERD, cookie);
+}
+
#if defined(OS_WIN)
// MessageLoop implicitly start a "modal message loop". Modal dialog boxes,
// common controls (like OpenFile) and StartDoc printing function can cause
// implicit message loops.
-class MessageBoxTask : public OrderedTasks {
- public:
- MessageBoxTask(TaskList* order, int cookie, bool is_reentrant)
- : OrderedTasks(order, MESSAGEBOX, cookie),
- is_reentrant_(is_reentrant) {
- }
-
- virtual void Run() {
- RunStart();
- if (is_reentrant_)
- MessageLoop::current()->SetNestableTasksAllowed(true);
- MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
- RunEnd();
- }
-
- private:
- bool is_reentrant_;
-};
+void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) {
+ order->RecordStart(MESSAGEBOX, cookie);
+ if (is_reentrant)
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
+ order->RecordEnd(MESSAGEBOX, cookie);
+}
// Will end the MessageBox.
-class EndDialogTask : public OrderedTasks {
- public:
- EndDialogTask(TaskList* order, int cookie)
- : OrderedTasks(order, ENDDIALOG, cookie) {
- }
-
- virtual void Run() {
- RunStart();
- HWND window = GetActiveWindow();
- if (window != NULL) {
- EXPECT_NE(EndDialog(window, IDCONTINUE), 0);
- // Cheap way to signal that the window wasn't found if RunEnd() isn't
- // called.
- RunEnd();
- }
+void EndDialogFunc(TaskList* order, int cookie) {
+ order->RecordStart(ENDDIALOG, cookie);
+ HWND window = GetActiveWindow();
+ if (window != NULL) {
+ EXPECT_NE(EndDialog(window, IDCONTINUE), 0);
+ // Cheap way to signal that the window wasn't found if RunEnd() isn't
+ // called.
+ order->RecordEnd(ENDDIALOG, cookie);
}
-};
+}
#endif // defined(OS_WIN)
-class RecursiveTask : public OrderedTasks {
- public:
- RecursiveTask(int depth, TaskList* order, int cookie, bool is_reentrant)
- : OrderedTasks(order, RECURSIVE, cookie),
- depth_(depth),
- is_reentrant_(is_reentrant) {
- }
-
- virtual void Run() {
- RunStart();
- if (depth_ > 0) {
- if (is_reentrant_)
- MessageLoop::current()->SetNestableTasksAllowed(true);
- MessageLoop::current()->PostTask(FROM_HERE,
- new RecursiveTask(depth_ - 1, order(), cookie(), is_reentrant_));
- }
- RunEnd();
- }
-
- private:
- int depth_;
- bool is_reentrant_;
-};
-
-class RecursiveSlowTask : public RecursiveTask {
- public:
- RecursiveSlowTask(int depth, TaskList* order, int cookie, bool is_reentrant)
- : RecursiveTask(depth, order, cookie, is_reentrant) {
- }
-
- virtual void Run() {
- RecursiveTask::Run();
- PlatformThread::Sleep(10); // milliseconds
- }
-};
-
-class QuitTask : public OrderedTasks {
- public:
- QuitTask(TaskList* order, int cookie)
- : OrderedTasks(order, QUITMESSAGELOOP, cookie) {
- }
-
- virtual void Run() {
- RunStart();
- MessageLoop::current()->Quit();
- RunEnd();
+void RecursiveFunc(TaskList* order, int cookie, int depth,
+ bool is_reentrant) {
+ order->RecordStart(RECURSIVE, cookie);
+ if (depth > 0) {
+ if (is_reentrant)
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
}
-};
+ order->RecordEnd(RECURSIVE, cookie);
+}
-class SleepTask : public OrderedTasks {
- public:
- SleepTask(TaskList* order, int cookie, int ms)
- : OrderedTasks(order, SLEEP, cookie), ms_(ms) {
- }
+void RecursiveSlowFunc(TaskList* order, int cookie, int depth,
+ bool is_reentrant) {
+ RecursiveFunc(order, cookie, depth, is_reentrant);
+ PlatformThread::Sleep(10); // milliseconds
+}
- virtual void Run() {
- RunStart();
- PlatformThread::Sleep(ms_);
- RunEnd();
- }
+void QuitFunc(TaskList* order, int cookie) {
+ order->RecordStart(QUITMESSAGELOOP, cookie);
+ MessageLoop::current()->Quit();
+ order->RecordEnd(QUITMESSAGELOOP, cookie);
+}
- private:
- int ms_;
-};
+void SleepFunc(TaskList* order, int cookie, int ms) {
+ order->RecordStart(SLEEP, cookie);
+ PlatformThread::Sleep(ms);
+ order->RecordEnd(SLEEP, cookie);
+}
#if defined(OS_WIN)
-
-class Recursive2Tasks : public Task {
- public:
- Recursive2Tasks(MessageLoop* target,
- HANDLE event,
- bool expect_window,
- TaskList* order,
- bool is_reentrant)
- : target_(target),
- event_(event),
- expect_window_(expect_window),
- order_(order),
- is_reentrant_(is_reentrant) {
- }
-
- virtual void Run() {
- target_->PostTask(FROM_HERE,
- new RecursiveTask(2, order_, 1, is_reentrant_));
- target_->PostTask(FROM_HERE,
- new MessageBoxTask(order_, 2, is_reentrant_));
- target_->PostTask(FROM_HERE,
- new RecursiveTask(2, order_, 3, is_reentrant_));
- // The trick here is that for recursive task processing, this task will be
- // ran _inside_ the MessageBox message loop, dismissing the MessageBox
- // without a chance.
- // For non-recursive task processing, this will be executed _after_ the
- // MessageBox will have been dismissed by the code below, where
- // expect_window_ is true.
- target_->PostTask(FROM_HERE, new EndDialogTask(order_, 4));
- target_->PostTask(FROM_HERE, new QuitTask(order_, 5));
-
- // Enforce that every tasks are sent before starting to run the main thread
- // message loop.
- ASSERT_TRUE(SetEvent(event_));
-
- // Poll for the MessageBox. Don't do this at home! At the speed we do it,
- // you will never realize one MessageBox was shown.
- for (; expect_window_;) {
- HWND window = FindWindow(L"#32770", kMessageBoxTitle);
- if (window) {
- // Dismiss it.
- for (;;) {
- HWND button = FindWindowEx(window, NULL, L"Button", NULL);
- if (button != NULL) {
- EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0));
- EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0));
- break;
- }
+void RecursiveFuncWin(MessageLoop* target,
+ HANDLE event,
+ bool expect_window,
+ TaskList* order,
+ bool is_reentrant) {
+ target->PostTask(FROM_HERE,
+ base::Bind(&RecursiveFunc, order, 1, 2, is_reentrant));
+ target->PostTask(FROM_HERE,
+ base::Bind(&MessageBoxFunc, order, 2, is_reentrant));
+ target->PostTask(FROM_HERE,
+ base::Bind(&RecursiveFunc, order, 3, 2, is_reentrant));
+ // The trick here is that for recursive task processing, this task will be
+ // ran _inside_ the MessageBox message loop, dismissing the MessageBox
+ // without a chance.
+ // For non-recursive task processing, this will be executed _after_ the
+ // MessageBox will have been dismissed by the code below, where
+ // expect_window_ is true.
+ target->PostTask(FROM_HERE,
+ base::Bind(&EndDialogFunc, order, 4));
+ target->PostTask(FROM_HERE,
+ base::Bind(&QuitFunc, order, 5));
+
+ // Enforce that every tasks are sent before starting to run the main thread
+ // message loop.
+ ASSERT_TRUE(SetEvent(event));
+
+ // Poll for the MessageBox. Don't do this at home! At the speed we do it,
+ // you will never realize one MessageBox was shown.
+ for (; expect_window;) {
+ HWND window = FindWindow(L"#32770", kMessageBoxTitle);
+ if (window) {
+ // Dismiss it.
+ for (;;) {
+ HWND button = FindWindowEx(window, NULL, L"Button", NULL);
+ if (button != NULL) {
+ EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0));
+ EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0));
+ break;
}
- break;
}
+ break;
}
}
-
- private:
- MessageLoop* target_;
- HANDLE event_;
- TaskList* order_;
- bool expect_window_;
- bool is_reentrant_;
-};
+}
#endif // defined(OS_WIN)
@@ -879,30 +807,34 @@ void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) {
EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
TaskList order;
- MessageLoop::current()->PostTask(FROM_HERE,
- new RecursiveTask(2, &order, 1, false));
- MessageLoop::current()->PostTask(FROM_HERE,
- new RecursiveTask(2, &order, 2, false));
- MessageLoop::current()->PostTask(FROM_HERE, new QuitTask(&order, 3));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&RecursiveFunc, &order, 1, 2, false));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&RecursiveFunc, &order, 2, 2, false));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&QuitFunc, &order, 3));
MessageLoop::current()->Run();
// FIFO order.
- ASSERT_EQ(14U, order.size());
- EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true));
- EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false));
- EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true));
- EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false));
- EXPECT_EQ(order[ 6], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[ 7], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true));
- EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false));
- EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[12], TaskItem(RECURSIVE, 2, true));
- EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false));
+ ASSERT_EQ(14U, order.Size());
+ EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+ EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+ EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+ EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+ EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
}
void RunTest_RecursiveDenial3(MessageLoop::Type message_loop_type) {
@@ -910,66 +842,66 @@ void RunTest_RecursiveDenial3(MessageLoop::Type message_loop_type) {
EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
TaskList order;
- MessageLoop::current()->PostTask(FROM_HERE,
- new RecursiveSlowTask(2, &order, 1, false));
- MessageLoop::current()->PostTask(FROM_HERE,
- new RecursiveSlowTask(2, &order, 2, false));
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- new OrderedTasks(&order, 3), 5);
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- new QuitTask(&order, 4), 5);
+ MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&RecursiveSlowFunc, &order, 1, 2, false));
+ MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&RecursiveSlowFunc, &order, 2, 2, false));
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, base::Bind(&OrderedFunc, &order, 3), 5);
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, base::Bind(&QuitFunc, &order, 4), 5);
MessageLoop::current()->Run();
// FIFO order.
- ASSERT_EQ(16U, order.size());
- EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true));
- EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false));
- EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[ 5], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[ 6], TaskItem(ORDERERD, 3, true));
- EXPECT_EQ(order[ 7], TaskItem(ORDERERD, 3, false));
- EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true));
- EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false));
- EXPECT_EQ(order[10], TaskItem(QUITMESSAGELOOP, 4, true));
- EXPECT_EQ(order[11], TaskItem(QUITMESSAGELOOP, 4, false));
- EXPECT_EQ(order[12], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[13], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[14], TaskItem(RECURSIVE, 2, true));
- EXPECT_EQ(order[15], TaskItem(RECURSIVE, 2, false));
+ ASSERT_EQ(16U, order.Size());
+ EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+ EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(6), TaskItem(ORDERERD, 3, true));
+ EXPECT_EQ(order.Get(7), TaskItem(ORDERERD, 3, false));
+ EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+ EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true));
+ EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false));
+ EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false));
}
void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
TaskList order;
- MessageLoop::current()->PostTask(FROM_HERE,
- new RecursiveTask(2, &order, 1, true));
- MessageLoop::current()->PostTask(FROM_HERE,
- new RecursiveTask(2, &order, 2, true));
- MessageLoop::current()->PostTask(FROM_HERE,
- new QuitTask(&order, 3));
+ MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&RecursiveFunc, &order, 1, 2, true));
+ MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&RecursiveFunc, &order, 2, 2, true));
+ MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&QuitFunc, &order, 3));
MessageLoop::current()->Run();
// FIFO order.
- ASSERT_EQ(14U, order.size());
- EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true));
- EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false));
- EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true));
- EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false));
- EXPECT_EQ(order[ 6], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[ 7], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true));
- EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false));
- EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[12], TaskItem(RECURSIVE, 2, true));
- EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false));
+ ASSERT_EQ(14U, order.Size());
+ EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+ EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+ EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+ EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+ EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
}
#if defined(OS_WIN)
@@ -987,35 +919,36 @@ void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
TaskList order;
base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
worker.message_loop()->PostTask(FROM_HERE,
- new Recursive2Tasks(MessageLoop::current(),
- event,
- true,
- &order,
- false));
+ base::Bind(&RecursiveFuncWin,
+ MessageLoop::current(),
+ event.Get(),
+ true,
+ &order,
+ false));
// Let the other thread execute.
WaitForSingleObject(event, INFINITE);
MessageLoop::current()->Run();
- ASSERT_EQ(order.size(), 17);
- EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[ 2], TaskItem(MESSAGEBOX, 2, true));
- EXPECT_EQ(order[ 3], TaskItem(MESSAGEBOX, 2, false));
- EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 3, true));
- EXPECT_EQ(order[ 5], TaskItem(RECURSIVE, 3, false));
- // When EndDialogTask is processed, the window is already dismissed, hence no
+ ASSERT_EQ(order.Size(), 17);
+ EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
+ EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false));
+ EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true));
+ EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false));
+ // When EndDialogFunc is processed, the window is already dismissed, hence no
// "end" entry.
- EXPECT_EQ(order[ 6], TaskItem(ENDDIALOG, 4, true));
- EXPECT_EQ(order[ 7], TaskItem(QUITMESSAGELOOP, 5, true));
- EXPECT_EQ(order[ 8], TaskItem(QUITMESSAGELOOP, 5, false));
- EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[11], TaskItem(RECURSIVE, 3, true));
- EXPECT_EQ(order[12], TaskItem(RECURSIVE, 3, false));
- EXPECT_EQ(order[13], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[14], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[15], TaskItem(RECURSIVE, 3, true));
- EXPECT_EQ(order[16], TaskItem(RECURSIVE, 3, false));
+ EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true));
+ EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true));
+ EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false));
+ EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true));
+ EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false));
+ EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true));
+ EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false));
}
// A side effect of this test is the generation a beep. Sorry. This test also
@@ -1030,80 +963,78 @@ void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
TaskList order;
base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
worker.message_loop()->PostTask(FROM_HERE,
- new Recursive2Tasks(MessageLoop::current(),
- event,
- false,
- &order,
- true));
+ base::Bind(&RecursiveFuncWin,
+ MessageLoop::current(),
+ event.Get(),
+ false,
+ &order,
+ true));
// Let the other thread execute.
WaitForSingleObject(event, INFINITE);
MessageLoop::current()->Run();
- ASSERT_EQ(order.size(), 18);
- EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[ 2], TaskItem(MESSAGEBOX, 2, true));
+ ASSERT_EQ(order.Size(), 18);
+ EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
// Note that this executes in the MessageBox modal loop.
- EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 3, true));
- EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 3, false));
- EXPECT_EQ(order[ 5], TaskItem(ENDDIALOG, 4, true));
- EXPECT_EQ(order[ 6], TaskItem(ENDDIALOG, 4, false));
- EXPECT_EQ(order[ 7], TaskItem(MESSAGEBOX, 2, false));
- /* The order can subtly change here. The reason is that when RecursiveTask(1)
+ EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true));
+ EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false));
+ EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true));
+ EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false));
+ EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false));
+ /* The order can subtly change here. The reason is that when RecursiveFunc(1)
is called in the main thread, if it is faster than getting to the
- PostTask(FROM_HERE, QuitTask) execution, the order of task execution can
- change. We don't care anyway that the order isn't correct.
- EXPECT_EQ(order[ 8], TaskItem(QUITMESSAGELOOP, 5, true));
- EXPECT_EQ(order[ 9], TaskItem(QUITMESSAGELOOP, 5, false));
- EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false));
+ PostTask(FROM_HERE, base::Bind(&QuitFunc) execution, the order of task
+ execution can change. We don't care anyway that the order isn't correct.
+ EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true));
+ EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false));
+ EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
*/
- EXPECT_EQ(order[12], TaskItem(RECURSIVE, 3, true));
- EXPECT_EQ(order[13], TaskItem(RECURSIVE, 3, false));
- EXPECT_EQ(order[14], TaskItem(RECURSIVE, 1, true));
- EXPECT_EQ(order[15], TaskItem(RECURSIVE, 1, false));
- EXPECT_EQ(order[16], TaskItem(RECURSIVE, 3, true));
- EXPECT_EQ(order[17], TaskItem(RECURSIVE, 3, false));
+ EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true));
+ EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false));
+ EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true));
+ EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false));
}
#endif // defined(OS_WIN)
-class TaskThatPumps : public OrderedTasks {
- public:
- TaskThatPumps(TaskList* order, int cookie)
- : OrderedTasks(order, PUMPS, cookie) {
- }
-
- virtual void Run() {
- RunStart();
- bool old_state = MessageLoop::current()->NestableTasksAllowed();
- MessageLoop::current()->SetNestableTasksAllowed(true);
- MessageLoop::current()->RunAllPending();
- MessageLoop::current()->SetNestableTasksAllowed(old_state);
- RunEnd();
- }
-};
+void FuncThatPumps(TaskList* order, int cookie) {
+ order->RecordStart(PUMPS, cookie);
+ bool old_state = MessageLoop::current()->NestableTasksAllowed();
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ MessageLoop::current()->RunAllPending();
+ MessageLoop::current()->SetNestableTasksAllowed(old_state);
+ order->RecordEnd(PUMPS, cookie);
+}
// Tests that non nestable tasks run in FIFO if there are no nested loops.
-void RunTest_NonNestableWithNoNesting(MessageLoop::Type message_loop_type) {
+void RunTest_NonNestableWithNoNesting(
+ MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
TaskList order;
- Task* task = new OrderedTasks(&order, 1);
- MessageLoop::current()->PostNonNestableTask(FROM_HERE, task);
- MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 2));
- MessageLoop::current()->PostTask(FROM_HERE, new QuitTask(&order, 3));
+ MessageLoop::current()->PostNonNestableTask(
+ FROM_HERE,
+ base::Bind(&OrderedFunc, &order, 1));
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&OrderedFunc, &order, 2));
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&QuitFunc, &order, 3));
MessageLoop::current()->Run();
// FIFO order.
- ASSERT_EQ(6U, order.size());
- EXPECT_EQ(order[ 0], TaskItem(ORDERERD, 1, true));
- EXPECT_EQ(order[ 1], TaskItem(ORDERERD, 1, false));
- EXPECT_EQ(order[ 2], TaskItem(ORDERERD, 2, true));
- EXPECT_EQ(order[ 3], TaskItem(ORDERERD, 2, false));
- EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true));
- EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false));
+ ASSERT_EQ(6U, order.Size());
+ EXPECT_EQ(order.Get(0), TaskItem(ORDERERD, 1, true));
+ EXPECT_EQ(order.Get(1), TaskItem(ORDERERD, 1, false));
+ EXPECT_EQ(order.Get(2), TaskItem(ORDERERD, 2, true));
+ EXPECT_EQ(order.Get(3), TaskItem(ORDERERD, 2, false));
+ EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+ EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
}
// Tests that non nestable tasks don't run when there's code in the call stack.
@@ -1113,42 +1044,52 @@ void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type,
TaskList order;
- MessageLoop::current()->PostTask(FROM_HERE,
- new TaskThatPumps(&order, 1));
- Task* task = new OrderedTasks(&order, 2);
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&FuncThatPumps, &order, 1));
if (use_delayed) {
- MessageLoop::current()->PostNonNestableDelayedTask(FROM_HERE, task, 1);
+ MessageLoop::current()->PostNonNestableDelayedTask(
+ FROM_HERE,
+ base::Bind(&OrderedFunc, &order, 2),
+ 1);
} else {
- MessageLoop::current()->PostNonNestableTask(FROM_HERE, task);
+ MessageLoop::current()->PostNonNestableTask(
+ FROM_HERE,
+ base::Bind(&OrderedFunc, &order, 2));
}
- MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 3));
- MessageLoop::current()->PostTask(FROM_HERE, new SleepTask(&order, 4, 50));
- MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 5));
- Task* non_nestable_quit = new QuitTask(&order, 6);
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&OrderedFunc, &order, 3));
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&SleepFunc, &order, 4, 50));
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&OrderedFunc, &order, 5));
if (use_delayed) {
- MessageLoop::current()->PostNonNestableDelayedTask(FROM_HERE,
- non_nestable_quit,
- 2);
+ MessageLoop::current()->PostNonNestableDelayedTask(
+ FROM_HERE,
+ base::Bind(&QuitFunc, &order, 6),
+ 2);
} else {
- MessageLoop::current()->PostNonNestableTask(FROM_HERE, non_nestable_quit);
+ MessageLoop::current()->PostNonNestableTask(
+ FROM_HERE,
+ base::Bind(&QuitFunc, &order, 6));
}
MessageLoop::current()->Run();
// FIFO order.
- ASSERT_EQ(12U, order.size());
- EXPECT_EQ(order[ 0], TaskItem(PUMPS, 1, true));
- EXPECT_EQ(order[ 1], TaskItem(ORDERERD, 3, true));
- EXPECT_EQ(order[ 2], TaskItem(ORDERERD, 3, false));
- EXPECT_EQ(order[ 3], TaskItem(SLEEP, 4, true));
- EXPECT_EQ(order[ 4], TaskItem(SLEEP, 4, false));
- EXPECT_EQ(order[ 5], TaskItem(ORDERERD, 5, true));
- EXPECT_EQ(order[ 6], TaskItem(ORDERERD, 5, false));
- EXPECT_EQ(order[ 7], TaskItem(PUMPS, 1, false));
- EXPECT_EQ(order[ 8], TaskItem(ORDERERD, 2, true));
- EXPECT_EQ(order[ 9], TaskItem(ORDERERD, 2, false));
- EXPECT_EQ(order[10], TaskItem(QUITMESSAGELOOP, 6, true));
- EXPECT_EQ(order[11], TaskItem(QUITMESSAGELOOP, 6, false));
+ ASSERT_EQ(12U, order.Size());
+ EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true));
+ EXPECT_EQ(order.Get(1), TaskItem(ORDERERD, 3, true));
+ EXPECT_EQ(order.Get(2), TaskItem(ORDERERD, 3, false));
+ EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true));
+ EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false));
+ EXPECT_EQ(order.Get(5), TaskItem(ORDERERD, 5, true));
+ EXPECT_EQ(order.Get(6), TaskItem(ORDERERD, 5, false));
+ EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false));
+ EXPECT_EQ(order.Get(8), TaskItem(ORDERERD, 2, true));
+ EXPECT_EQ(order.Get(9), TaskItem(ORDERERD, 2, false));
+ EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true));
+ EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false));
}
#if defined(OS_WIN)
@@ -1171,18 +1112,16 @@ class DispatcherImpl : public MessageLoopForUI::Dispatcher {
int dispatch_count_;
};
+void MouseDownUp() {
+ PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
+ PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
+}
+
void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
- class MyTask : public Task {
- public:
- virtual void Run() {
- PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
- PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
- }
- };
- Task* task = new MyTask();
- MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 100);
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ base::Bind(&MouseDownUp), 100);
DispatcherImpl dispatcher;
MessageLoopForUI::current()->Run(&dispatcher);
ASSERT_EQ(2, dispatcher.dispatch_count_);
@@ -1200,15 +1139,8 @@ LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
- class MyTask : public Task {
- public:
- virtual void Run() {
- PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
- PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
- }
- };
- Task* task = new MyTask();
- MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 100);
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ base::Bind(&MouseDownUp), 100);
HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER,
MsgFilterProc,
NULL,
@@ -1271,17 +1203,6 @@ void TestIOHandler::WaitForIO() {
EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this));
}
-class IOHandlerTask : public Task {
- public:
- explicit IOHandlerTask(TestIOHandler* handler) : handler_(handler) {}
- virtual void Run() {
- handler_->Init();
- }
-
- private:
- TestIOHandler* handler_;
-};
-
void RunTest_IOHandler() {
base::win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
ASSERT_TRUE(callback_called.IsValid());
@@ -1300,8 +1221,8 @@ void RunTest_IOHandler() {
ASSERT_TRUE(NULL != thread_loop);
TestIOHandler handler(kPipeName, callback_called, false);
- IOHandlerTask* task = new IOHandlerTask(&handler);
- thread_loop->PostTask(FROM_HERE, task);
+ thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
+ base::Unretained(&handler)));
Sleep(100); // Make sure the thread runs and sleeps for lack of work.
const char buffer[] = "Hello there!";
@@ -1341,11 +1262,12 @@ void RunTest_WaitForIO() {
TestIOHandler handler1(kPipeName1, callback1_called, false);
TestIOHandler handler2(kPipeName2, callback2_called, true);
- IOHandlerTask* task1 = new IOHandlerTask(&handler1);
- IOHandlerTask* task2 = new IOHandlerTask(&handler2);
- thread_loop->PostTask(FROM_HERE, task1);
+ thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
+ base::Unretained(&handler1)));
+ // TODO(ajwong): Do we really need such long Sleeps in ths function?
Sleep(100); // Make sure the thread runs and sleeps for lack of work.
- thread_loop->PostTask(FROM_HERE, task2);
+ thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
+ base::Unretained(&handler2)));
Sleep(100);
// At this time handler1 is waiting to be called, and the thread is waiting
@@ -1376,6 +1298,12 @@ void RunTest_WaitForIO() {
// that message loops work properly in all configurations. Of course, in some
// cases, a unit test may only be for a particular type of loop.
+TEST(MessageLoopTest, PostLegacyTask) {
+ RunTest_PostLegacyTask(MessageLoop::TYPE_DEFAULT);
+ RunTest_PostLegacyTask(MessageLoop::TYPE_UI);
+ RunTest_PostLegacyTask(MessageLoop::TYPE_IO);
+}
+
TEST(MessageLoopTest, PostTask) {
RunTest_PostTask(MessageLoop::TYPE_DEFAULT);
RunTest_PostTask(MessageLoop::TYPE_UI);
@@ -1433,19 +1361,19 @@ TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
// TODO(darin): MessageLoop does not support deleting all tasks in the
// destructor.
// Fails, http://crbug.com/50272.
-TEST(MessageLoopTest, FAILS_EnsureTaskDeletion) {
- RunTest_EnsureTaskDeletion(MessageLoop::TYPE_DEFAULT);
- RunTest_EnsureTaskDeletion(MessageLoop::TYPE_UI);
- RunTest_EnsureTaskDeletion(MessageLoop::TYPE_IO);
+TEST(MessageLoopTest, FAILS_EnsureDeletion) {
+ RunTest_EnsureDeletion(MessageLoop::TYPE_DEFAULT);
+ RunTest_EnsureDeletion(MessageLoop::TYPE_UI);
+ RunTest_EnsureDeletion(MessageLoop::TYPE_IO);
}
// TODO(darin): MessageLoop does not support deleting all tasks in the
// destructor.
// Fails, http://crbug.com/50272.
-TEST(MessageLoopTest, FAILS_EnsureTaskDeletion_Chain) {
- RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_DEFAULT);
- RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_UI);
- RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_IO);
+TEST(MessageLoopTest, FAILS_EnsureDeletion_Chain) {
+ RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_DEFAULT);
+ RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_UI);
+ RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_IO);
}
#if defined(OS_WIN)
@@ -1518,23 +1446,15 @@ TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) {
RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, true);
}
-class DummyTask : public Task {
- public:
- explicit DummyTask(int num_tasks) : num_tasks_(num_tasks) {}
-
- virtual void Run() {
- if (num_tasks_ > 1) {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- new DummyTask(num_tasks_ - 1));
- } else {
- MessageLoop::current()->Quit();
- }
+void PostNTasksThenQuit(int posts_remaining) {
+ if (posts_remaining > 1) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&PostNTasksThenQuit, posts_remaining - 1));
+ } else {
+ MessageLoop::current()->Quit();
}
-
- private:
- const int num_tasks_;
-};
+}
class DummyTaskObserver : public MessageLoop::TaskObserver {
public:
@@ -1545,16 +1465,16 @@ class DummyTaskObserver : public MessageLoop::TaskObserver {
virtual ~DummyTaskObserver() {}
- virtual void WillProcessTask(const Task* task) {
+ virtual void WillProcessTask(TimeTicks time_posted) OVERRIDE {
num_tasks_started_++;
- EXPECT_TRUE(task != NULL);
+ EXPECT_TRUE(time_posted != TimeTicks());
EXPECT_LE(num_tasks_started_, num_tasks_);
EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
}
- virtual void DidProcessTask(const Task* task) {
+ virtual void DidProcessTask(TimeTicks time_posted) OVERRIDE {
num_tasks_processed_++;
- EXPECT_TRUE(task != NULL);
+ EXPECT_TRUE(time_posted != TimeTicks());
EXPECT_LE(num_tasks_started_, num_tasks_);
EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
}
@@ -1571,17 +1491,17 @@ class DummyTaskObserver : public MessageLoop::TaskObserver {
};
TEST(MessageLoopTest, TaskObserver) {
- const int kNumTasks = 6;
- DummyTaskObserver observer(kNumTasks);
+ const int kNumPosts = 6;
+ DummyTaskObserver observer(kNumPosts);
MessageLoop loop;
loop.AddTaskObserver(&observer);
- loop.PostTask(FROM_HERE, new DummyTask(kNumTasks));
+ loop.PostTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, kNumPosts));
loop.Run();
loop.RemoveTaskObserver(&observer);
- EXPECT_EQ(kNumTasks, observer.num_tasks_started());
- EXPECT_EQ(kNumTasks, observer.num_tasks_processed());
+ EXPECT_EQ(kNumPosts, observer.num_tasks_started());
+ EXPECT_EQ(kNumPosts, observer.num_tasks_processed());
}
#if defined(OS_WIN)
@@ -1612,13 +1532,15 @@ TEST(MessageLoopTest, HighResolutionTimer) {
EXPECT_FALSE(loop.high_resolution_timers_enabled());
// Post a fast task to enable the high resolution timers.
- loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kFastTimerMs);
+ loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
+ kFastTimerMs);
loop.Run();
EXPECT_TRUE(loop.high_resolution_timers_enabled());
// Post a slow task and verify high resolution timers
// are still enabled.
- loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kSlowTimerMs);
+ loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
+ kSlowTimerMs);
loop.Run();
EXPECT_TRUE(loop.high_resolution_timers_enabled());
@@ -1626,7 +1548,8 @@ TEST(MessageLoopTest, HighResolutionTimer) {
Sleep(MessageLoop::kHighResolutionTimerModeLeaseTimeMs);
// Post a slow task to disable the high resolution timers.
- loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kSlowTimerMs);
+ loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
+ kSlowTimerMs);
loop.Run();
EXPECT_FALSE(loop.high_resolution_timers_enabled());
}
@@ -1706,13 +1629,18 @@ TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
#endif // defined(OS_POSIX) && !defined(OS_NACL)
namespace {
-class RunAtDestructionTask : public Task {
+// Inject a test point for recording the destructor calls for Closure objects
+// send to MessageLoop::PostTask(). It is awkward usage since we are trying to
+// hook the actual destruction, which is not a common operation.
+class DestructionObserverProbe :
+ public base::RefCounted<DestructionObserverProbe> {
public:
- RunAtDestructionTask(bool* task_destroyed, bool* destruction_observer_called)
+ DestructionObserverProbe(bool* task_destroyed,
+ bool* destruction_observer_called)
: task_destroyed_(task_destroyed),
destruction_observer_called_(destruction_observer_called) {
}
- ~RunAtDestructionTask() {
+ virtual ~DestructionObserverProbe() {
EXPECT_FALSE(*destruction_observer_called_);
*task_destroyed_ = true;
}
@@ -1760,7 +1688,9 @@ TEST(MessageLoopTest, DestructionObserverTest) {
loop->AddDestructionObserver(&observer);
loop->PostDelayedTask(
FROM_HERE,
- new RunAtDestructionTask(&task_destroyed, &destruction_observer_called),
+ base::Bind(&DestructionObserverProbe::Run,
+ new DestructionObserverProbe(&task_destroyed,
+ &destruction_observer_called)),
kDelayMS);
delete loop;
EXPECT_TRUE(observer.task_destroyed_before_message_loop());