summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/build/base.vcproj8
-rw-r--r--base/idle_timer.cc2
-rw-r--r--base/idletimer_unittest.cc15
-rw-r--r--base/message_loop.cc72
-rw-r--r--base/message_loop.h136
-rw-r--r--base/message_loop_unittest.cc224
-rw-r--r--base/object_watcher_unittest.cc32
-rw-r--r--base/run_all_unittests.cc6
-rw-r--r--base/test_suite.h34
-rw-r--r--base/thread.cc67
-rw-r--r--base/thread.h49
-rw-r--r--base/thread_unittest.cc8
-rw-r--r--base/timer_unittest.cc73
-rw-r--r--net/base/listen_socket_unittest.h4
-rw-r--r--net/base/run_all_unittests.cc58
-rw-r--r--net/build/net_unittests.vcproj2
-rw-r--r--net/proxy/proxy_service.cc2
-rw-r--r--net/proxy/proxy_service.h4
-rw-r--r--net/url_request/url_request.cc7
-rw-r--r--net/url_request/url_request_file_job.cc6
-rw-r--r--net/url_request/url_request_file_job.h2
-rw-r--r--net/url_request/url_request_unittest.h63
-rw-r--r--webkit/default_plugin/plugin_install_job_monitor.h2
-rw-r--r--webkit/tools/test_shell/simple_resource_loader_bridge.cc10
24 files changed, 632 insertions, 254 deletions
diff --git a/base/build/base.vcproj b/base/build/base.vcproj
index 7105b1b..a58c0a2 100644
--- a/base/build/base.vcproj
+++ b/base/build/base.vcproj
@@ -426,6 +426,14 @@
>
</File>
<File
+ RelativePath="..\message_pump_default.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\message_pump_default.h"
+ >
+ </File>
+ <File
RelativePath="..\message_pump_win.cc"
>
</File>
diff --git a/base/idle_timer.cc b/base/idle_timer.cc
index fa5e1cc..39b9bd4 100644
--- a/base/idle_timer.cc
+++ b/base/idle_timer.cc
@@ -13,6 +13,8 @@ IdleTimerTask::IdleTimerTask(TimeDelta idle_time, bool repeat)
: idle_interval_(idle_time),
repeat_(repeat),
get_last_input_info_fn_(GetLastInputInfo) {
+ DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()) <<
+ "Requires a thread that processes Windows UI events";
}
IdleTimerTask::~IdleTimerTask() {
diff --git a/base/idletimer_unittest.cc b/base/idletimer_unittest.cc
index 613adad..ea53854 100644
--- a/base/idletimer_unittest.cc
+++ b/base/idletimer_unittest.cc
@@ -8,6 +8,9 @@
namespace {
class IdleTimerTest : public testing::Test {
+ private:
+ // IdleTimer requires a UI message loop on the current thread.
+ MessageLoopForUI message_loop_;
};
};
@@ -63,7 +66,7 @@ class ResetIdleTask : public Task {
// A non-repeating idle timer will fire once on idle, and
// then will not fire again unless it goes non-idle first.
-TEST(IdleTimerTest, NoRepeatIdle) {
+TEST_F(IdleTimerTest, NoRepeatIdle) {
// Create an IdleTimer, which should fire once after 100ms.
// Create a Quit timer which will fire after 1s.
// Verify that we fired exactly once.
@@ -80,7 +83,7 @@ TEST(IdleTimerTest, NoRepeatIdle) {
delete t;
}
-TEST(IdleTimerTest, NoRepeatFlipIdleOnce) {
+TEST_F(IdleTimerTest, NoRepeatFlipIdleOnce) {
// Create an IdleTimer, which should fire once after 100ms.
// Create a Quit timer which will fire after 1s.
// Create a timer to reset once, idle after 500ms.
@@ -101,7 +104,7 @@ TEST(IdleTimerTest, NoRepeatFlipIdleOnce) {
delete t2;
}
-TEST(IdleTimerTest, NoRepeatNotIdle) {
+TEST_F(IdleTimerTest, NoRepeatNotIdle) {
// Create an IdleTimer, which should fire once after 100ms.
// Create a Quit timer which will fire after 1s.
// Create a timer to reset idle every 50ms.
@@ -129,7 +132,7 @@ TEST(IdleTimerTest, NoRepeatNotIdle) {
// as it has been idle. So, if the machine remains idle, it will continue
// firing over and over.
-TEST(IdleTimerTest, Repeat) {
+TEST_F(IdleTimerTest, Repeat) {
// Create an IdleTimer, which should fire repeatedly after 100ms.
// Create a Quit timer which will fire after 1.05s.
// Verify that we fired 10 times.
@@ -149,7 +152,7 @@ TEST(IdleTimerTest, Repeat) {
delete t;
}
-TEST(IdleTimerTest, RepeatIdleReset) {
+TEST_F(IdleTimerTest, RepeatIdleReset) {
// Create an IdleTimer, which should fire repeatedly after 100ms.
// Create a Quit timer which will fire after 1s.
// Create a reset timer, which fires after 550ms
@@ -173,7 +176,7 @@ TEST(IdleTimerTest, RepeatIdleReset) {
delete t2;
}
-TEST(IdleTimerTest, RepeatNotIdle) {
+TEST_F(IdleTimerTest, RepeatNotIdle) {
// Create an IdleTimer, which should fire repeatedly after 100ms.
// Create a Quit timer which will fire after 1s.
// Create a timer to reset idle every 50ms.
diff --git a/base/message_loop.cc b/base/message_loop.cc
index a84b3b5..4528b93 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -55,19 +55,30 @@ static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
//------------------------------------------------------------------------------
-MessageLoop::MessageLoop()
- : ALLOW_THIS_IN_INITIALIZER_LIST(timer_manager_(this)),
+MessageLoop::MessageLoop(Type type)
+ : type_(type),
+ ALLOW_THIS_IN_INITIALIZER_LIST(timer_manager_(this)),
nestable_tasks_allowed_(true),
exception_restoration_(false),
state_(NULL) {
- DCHECK(!current()) << "should only have one message loop per thread";
+ DCHECK(!tls_index_.Get()) << "should only have one message loop per thread";
tls_index_.Set(this);
- // TODO(darin): Generalize this to support instantiating different pumps.
+
+ switch (type) {
+ case TYPE_DEFAULT:
+ pump_ = new base::MessagePumpDefault();
+ break;
+ case TYPE_UI:
+ case TYPE_IO:
+ // TODO(darin): Use a special pumps for UI and IO, and figure out what to
+ // do for non-Windows platforms.
#if defined(OS_WIN)
- pump_ = new base::MessagePumpWin();
+ pump_ = new base::MessagePumpWin();
#else
- pump_ = new base::MessagePumpDefault();
+ pump_ = new base::MessagePumpDefault();
#endif
+ break;
+ }
}
MessageLoop::~MessageLoop() {
@@ -106,14 +117,6 @@ void MessageLoop::Run() {
RunHandler();
}
-#if defined(OS_WIN)
-void MessageLoop::Run(base::MessagePumpWin::Dispatcher* dispatcher) {
- AutoRunState save_state(this);
- state_->dispatcher = dispatcher;
- RunHandler();
-}
-#endif
-
void MessageLoop::RunAllPending() {
AutoRunState save_state(this);
state_->quit_received = true; // Means run until we would otherwise block.
@@ -560,3 +563,44 @@ const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
{-1, NULL} // The list must be null terminated, per API to histogram.
};
+//------------------------------------------------------------------------------
+// MessageLoopForUI
+
+#if defined(OS_WIN)
+
+void MessageLoopForUI::Run(Dispatcher* dispatcher) {
+ AutoRunState save_state(this);
+ state_->dispatcher = dispatcher;
+ RunHandler();
+}
+
+void MessageLoopForUI::AddObserver(Observer* observer) {
+ pump_win()->AddObserver(observer);
+}
+
+void MessageLoopForUI::RemoveObserver(Observer* observer) {
+ pump_win()->RemoveObserver(observer);
+}
+
+void MessageLoopForUI::WillProcessMessage(const MSG& message) {
+ pump_win()->WillProcessMessage(message);
+}
+void MessageLoopForUI::DidProcessMessage(const MSG& message) {
+ pump_win()->DidProcessMessage(message);
+}
+void MessageLoopForUI::PumpOutPendingPaintMessages() {
+ pump_win()->PumpOutPendingPaintMessages();
+}
+
+#endif // defined(OS_WIN)
+
+//------------------------------------------------------------------------------
+// MessageLoopForIO
+
+#if defined(OS_WIN)
+
+void MessageLoopForIO::WatchObject(HANDLE object, Watcher* watcher) {
+ pump_win()->WatchObject(object, watcher);
+}
+
+#endif // defined(OS_WIN)
diff --git a/base/message_loop.h b/base/message_loop.h
index d014bc1..43faf4a 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -155,11 +155,34 @@ class MessageLoop : public base::MessagePump::Delegate {
}
};
+ // A MessageLoop has a particular type, which indicates the set of
+ // asynchronous events it may process in addition to tasks and timers.
+ //
+ // TYPE_DEFAULT
+ // This type of ML only supports tasks and timers.
+ //
+ // TYPE_UI
+ // This type of ML also supports native UI events (e.g., Windows messages).
+ // See also MessageLoopForUI.
+ //
+ // TYPE_IO
+ // This type of ML also supports asynchronous IO. See also
+ // MessageLoopForIO.
+ //
+ enum Type {
+ TYPE_DEFAULT,
+ TYPE_UI,
+ TYPE_IO
+ };
+
// Normally, it is not necessary to instantiate a MessageLoop. Instead, it
// is typical to make use of the current thread's MessageLoop instance.
- MessageLoop();
+ explicit MessageLoop(Type type = TYPE_DEFAULT);
~MessageLoop();
+ // Returns the type passed to the constructor.
+ Type type() const { return type_; }
+
// Optional call to connect the thread name with this loop.
void set_thread_name(const std::string& thread_name) {
DCHECK(thread_name_.empty()) << "Should not rename this thread!";
@@ -169,7 +192,9 @@ class MessageLoop : public base::MessagePump::Delegate {
// Returns the MessageLoop object for the current thread, or null if none.
static MessageLoop* current() {
- return static_cast<MessageLoop*>(tls_index_.Get());
+ MessageLoop* loop = static_cast<MessageLoop*>(tls_index_.Get());
+ DCHECK(loop) << "Ouch, did you forget to initialize me?";
+ return loop;
}
// Returns the TimerManager object for the current thread.
@@ -201,39 +226,9 @@ class MessageLoop : public base::MessagePump::Delegate {
exception_restoration_ = restore;
}
- //----------------------------------------------------------------------------
-#if defined(OS_WIN)
- // Backwards-compat for the old Windows-specific MessageLoop API. These APIs
- // are deprecated.
-
- typedef base::MessagePumpWin::Dispatcher Dispatcher;
- typedef base::MessagePumpWin::Observer Observer;
- typedef base::MessagePumpWin::Watcher Watcher;
-
- void Run(Dispatcher* dispatcher);
-
- void WatchObject(HANDLE object, Watcher* watcher) {
- pump_win()->WatchObject(object, watcher);
- }
- void AddObserver(Observer* observer) {
- pump_win()->AddObserver(observer);
- }
- void RemoveObserver(Observer* observer) {
- pump_win()->RemoveObserver(observer);
- }
- void WillProcessMessage(const MSG& message) {
- pump_win()->WillProcessMessage(message);
- }
- void DidProcessMessage(const MSG& message) {
- pump_win()->DidProcessMessage(message);
- }
- void PumpOutPendingPaintMessages() {
- pump_win()->PumpOutPendingPaintMessages();
- }
-#endif // defined(OS_WIN)
//----------------------------------------------------------------------------
- private:
+ protected:
friend class TimerManager; // So it can call DidChangeNextTimerExpiry
struct RunState {
@@ -406,6 +401,8 @@ class MessageLoop : public base::MessagePump::Delegate {
static const LinearHistogram::DescriptionPair event_descriptions_[];
static bool enable_histogrammer_;
+ Type type_;
+
TimerManager timer_manager_;
// A list of tasks that need to be processed by this instance. Note that this
@@ -448,5 +445,76 @@ class MessageLoop : public base::MessagePump::Delegate {
DISALLOW_COPY_AND_ASSIGN(MessageLoop);
};
-#endif // BASE_MESSAGE_LOOP_H_
+//-----------------------------------------------------------------------------
+// MessageLoopForUI extends MessageLoop with methods that are particular to a
+// MessageLoop instantiated with TYPE_UI.
+//
+// This class is typically used like so:
+// MessageLoopForUI::current()->...call some method...
+//
+class MessageLoopForUI : public MessageLoop {
+ public:
+ MessageLoopForUI() : MessageLoop(TYPE_UI) {
+ }
+
+ // Returns the MessageLoopForUI of the current thread.
+ static MessageLoopForUI* current() {
+ MessageLoop* loop = MessageLoop::current();
+ DCHECK_EQ(MessageLoop::TYPE_UI, loop->type());
+ return static_cast<MessageLoopForUI*>(loop);
+ }
+
+#if defined(OS_WIN)
+ typedef base::MessagePumpWin::Dispatcher Dispatcher;
+ typedef base::MessagePumpWin::Observer Observer;
+ // Please see MessagePumpWin for definitions of these methods.
+ void Run(Dispatcher* dispatcher);
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+ void WillProcessMessage(const MSG& message);
+ void DidProcessMessage(const MSG& message);
+ void PumpOutPendingPaintMessages();
+#endif // defined(OS_WIN)
+};
+
+// Do not add any member variables to MessageLoopForUI! This is important b/c
+// MessageLoopForUI is often allocated via MessageLoop(TYPE_UI). Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
+ MessageLoopForUI_should_not_have_extra_member_variables);
+
+//-----------------------------------------------------------------------------
+// MessageLoopForIO extends MessageLoop with methods that are particular to a
+// MessageLoop instantiated with TYPE_IO.
+//
+// This class is typically used like so:
+// MessageLoopForIO::current()->...call some method...
+//
+class MessageLoopForIO : public MessageLoop {
+ public:
+ MessageLoopForIO() : MessageLoop(TYPE_IO) {
+ }
+
+ // Returns the MessageLoopForIO of the current thread.
+ static MessageLoopForIO* current() {
+ MessageLoop* loop = MessageLoop::current();
+ DCHECK_EQ(MessageLoop::TYPE_IO, loop->type());
+ return static_cast<MessageLoopForIO*>(loop);
+ }
+
+#if defined(OS_WIN)
+ typedef base::MessagePumpWin::Watcher Watcher;
+
+ // Please see MessagePumpWin for definitions of these methods.
+ void WatchObject(HANDLE object, Watcher* watcher);
+#endif // defined(OS_WIN)
+};
+
+// Do not add any member variables to MessageLoopForIO! This is important b/c
+// MessageLoopForIO is often allocated via MessageLoop(TYPE_IO). Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
+ MessageLoopForIO_should_not_have_extra_member_variables);
+
+#endif // BASE_MESSAGE_LOOP_H_
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
index ca84f60..4fcde2f 100644
--- a/base/message_loop_unittest.cc
+++ b/base/message_loop_unittest.cc
@@ -14,28 +14,14 @@
#include "base/scoped_handle.h"
#endif
-//
-// TODO(darin): This file needs to be re-organized into acceptance tests that
-// apply to a MessageLoop configured to use any MessagePump. Then, those tests
-// need to be run against all MessagePump types supported by a platform.
-//
-// Finally, platform-specific MessageLoop tests should be grouped together to
-// avoid the chopping this file up with so many #ifdefs.
-//
+using base::Thread;
+
+// TODO(darin): Platform-specific MessageLoop tests should be grouped together
+// to avoid chopping this file up with so many #ifdefs.
namespace {
-class MessageLoopTest : public testing::Test {
- public:
- virtual void SetUp() {
- enable_recursive_task_ = MessageLoop::current()->NestableTasksAllowed();
- }
- virtual void TearDown() {
- MessageLoop::current()->SetNestableTasksAllowed(enable_recursive_task_);
- }
- private:
- bool enable_recursive_task_;
-};
+class MessageLoopTest : public testing::Test {};
class Foo : public base::RefCounted<Foo> {
public:
@@ -87,9 +73,9 @@ class QuitMsgLoop : public base::RefCounted<QuitMsgLoop> {
}
};
-} // namespace
+void RunTest_PostTask(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
-TEST(MessageLoopTest, PostTask) {
// Add tests to message loop
scoped_refptr<Foo> foo = new Foo();
std::string a("a"), b("b"), c("c"), d("d");
@@ -118,7 +104,9 @@ TEST(MessageLoopTest, PostTask) {
EXPECT_EQ(foo->result(), "abacad");
}
-TEST(MessageLoopTest, InvokeLater_SEH) {
+void RunTest_PostTask_SEH(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");
@@ -149,8 +137,6 @@ TEST(MessageLoopTest, InvokeLater_SEH) {
EXPECT_EQ(foo->result(), "abacad");
}
-namespace {
-
class NestingTest : public Task {
public:
explicit NestingTest(int* depth) : depth_(depth) {
@@ -246,14 +232,9 @@ LONG WINAPI HandleCrasherTaskException(EXCEPTION_POINTERS *ex_info) {
return EXCEPTION_CONTINUE_EXECUTION;
}
-#endif // defined(OS_WIN)
-
-} // namespace
-
+void RunTest_Crasher(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
-#if defined(OS_WIN)
-
-TEST(MessageLoopTest, Crasher) {
if (::IsDebuggerPresent())
return;
@@ -268,7 +249,9 @@ TEST(MessageLoopTest, Crasher) {
::SetUnhandledExceptionFilter(old_SEH_filter);
}
-TEST(MessageLoopTest, CrasherNasty) {
+void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
if (::IsDebuggerPresent())
return;
@@ -285,16 +268,15 @@ TEST(MessageLoopTest, CrasherNasty) {
#endif // defined(OS_WIN)
+void RunTest_Nesting(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
-TEST(MessageLoopTest, Nesting) {
int depth = 100;
MessageLoop::current()->PostTask(FROM_HERE, new NestingTest(&depth));
MessageLoop::current()->Run();
EXPECT_EQ(depth, 0);
}
-namespace {
-
const wchar_t* const kMessageBoxTitle = L"MessageLoop Unit Test";
enum TaskType {
@@ -542,9 +524,9 @@ class Recursive2Tasks : public Task {
#endif // defined(OS_WIN)
-} // namespace
+void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
-TEST(MessageLoop, RecursiveDenial1) {
EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
TaskList order;
MessageLoop::current()->PostTask(FROM_HERE,
@@ -573,8 +555,9 @@ TEST(MessageLoop, RecursiveDenial1) {
EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false));
}
-
-TEST(MessageLoop, RecursiveSupport1) {
+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));
@@ -608,9 +591,13 @@ TEST(MessageLoop, RecursiveSupport1) {
// message loop functionality.
// A side effect of this test is the generation a beep. Sorry.
-TEST(MessageLoop, RecursiveDenial2) {
+void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
Thread worker("RecursiveDenial2_worker");
- ASSERT_EQ(true, worker.Start());
+ Thread::Options options;
+ options.message_loop_type = message_loop_type;
+ ASSERT_EQ(true, worker.StartWithOptions(options));
TaskList order;
ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
worker.message_loop()->PostTask(FROM_HERE,
@@ -645,10 +632,15 @@ TEST(MessageLoop, RecursiveDenial2) {
EXPECT_EQ(order[16], TaskItem(RECURSIVE, 3, false));
}
-// A side effect of this test is the generation a beep. Sorry.
-TEST(MessageLoop, RecursiveSupport2) {
+// A side effect of this test is the generation a beep. Sorry. This test also
+// needs to process windows messages on the current thread.
+void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
Thread worker("RecursiveSupport2_worker");
- ASSERT_EQ(true, worker.Start());
+ Thread::Options options;
+ options.message_loop_type = message_loop_type;
+ ASSERT_EQ(true, worker.StartWithOptions(options));
TaskList order;
ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
worker.message_loop()->PostTask(FROM_HERE,
@@ -704,13 +696,12 @@ class TaskThatPumps : public OrderedTasks {
MessageLoop::current()->SetNestableTasksAllowed(old_state);
RunEnd();
}
-
- private:
};
-
// Tests that non nestable tasks run in FIFO if there are no nested loops.
-TEST(MessageLoop, NonNestableWithNoNesting) {
+void RunTest_NonNestableWithNoNesting(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
TaskList order;
Task* task = new OrderedTasks(&order, 1);
@@ -731,7 +722,9 @@ TEST(MessageLoop, NonNestableWithNoNesting) {
}
// Tests that non nestable tasks don't run when there's code in the call stack.
-TEST(MessageLoop, NonNestableInNestedLoop) {
+void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
TaskList order;
MessageLoop::current()->PostTask(FROM_HERE,
@@ -745,7 +738,6 @@ TEST(MessageLoop, NonNestableInNestedLoop) {
non_nestable_quit->set_nestable(false);
MessageLoop::current()->PostTask(FROM_HERE, non_nestable_quit);
-
MessageLoop::current()->Run();
// FIFO order.
@@ -764,41 +756,36 @@ TEST(MessageLoop, NonNestableInNestedLoop) {
#if defined(OS_WIN)
-namespace {
-
-class AutoresetWatcher : public MessageLoop::Watcher {
+class AutoresetWatcher : public MessageLoopForIO::Watcher {
public:
- AutoresetWatcher(HANDLE signal, MessageLoop* message_loop)
- : signal_(signal),
- message_loop_(message_loop) {
+ AutoresetWatcher(HANDLE signal) : signal_(signal) {
}
virtual void OnObjectSignaled(HANDLE object);
private:
HANDLE signal_;
- MessageLoop* message_loop_;
};
void AutoresetWatcher::OnObjectSignaled(HANDLE object) {
- message_loop_->WatchObject(object, NULL);
+ MessageLoopForIO::current()->WatchObject(object, NULL);
ASSERT_TRUE(SetEvent(signal_));
}
class AutoresetTask : public Task {
public:
- AutoresetTask(HANDLE object, MessageLoop::Watcher* watcher)
+ AutoresetTask(HANDLE object, MessageLoopForIO::Watcher* watcher)
: object_(object), watcher_(watcher) {}
virtual void Run() {
- MessageLoop::current()->WatchObject(object_, watcher_);
+ MessageLoopForIO::current()->WatchObject(object_, watcher_);
}
private:
HANDLE object_;
- MessageLoop::Watcher* watcher_;
+ MessageLoopForIO::Watcher* watcher_;
};
-} // namespace
+void RunTest_AutoresetEvents(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
-TEST(MessageLoop, AutoresetEvents) {
SECURITY_ATTRIBUTES attributes;
attributes.nLength = sizeof(attributes);
attributes.bInheritHandle = false;
@@ -811,14 +798,16 @@ TEST(MessageLoop, AutoresetEvents) {
ASSERT_TRUE(NULL != callback_called);
Thread thread("Autoreset test");
- ASSERT_TRUE(thread.Start());
+ Thread::Options options;
+ options.message_loop_type = message_loop_type;
+ ASSERT_TRUE(thread.StartWithOptions(options));
- MessageLoop* message_loop = thread.message_loop();
- ASSERT_TRUE(NULL != message_loop);
+ MessageLoop* thread_loop = thread.message_loop();
+ ASSERT_TRUE(NULL != thread_loop);
- AutoresetWatcher watcher(callback_called, message_loop);
+ AutoresetWatcher watcher(callback_called);
AutoresetTask* task = new AutoresetTask(autoreset, &watcher);
- message_loop->PostTask(FROM_HERE, task);
+ thread_loop->PostTask(FROM_HERE, task);
Sleep(100); // Make sure the thread runs and sleeps for lack of work.
ASSERT_TRUE(SetEvent(autoreset));
@@ -829,9 +818,7 @@ TEST(MessageLoop, AutoresetEvents) {
thread.Stop();
}
-namespace {
-
-class DispatcherImpl : public MessageLoop::Dispatcher {
+class DispatcherImpl : public MessageLoopForUI::Dispatcher {
public:
DispatcherImpl() : dispatch_count_(0) {}
@@ -844,9 +831,9 @@ class DispatcherImpl : public MessageLoop::Dispatcher {
int dispatch_count_;
};
-} // namespace
+void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
-TEST(MessageLoop, Dispatcher) {
class MyTask : public Task {
public:
virtual void Run() {
@@ -857,9 +844,96 @@ TEST(MessageLoop, Dispatcher) {
Task* task = new MyTask();
MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 100);
DispatcherImpl dispatcher;
- MessageLoop::current()->Run(&dispatcher);
+ MessageLoopForUI::current()->Run(&dispatcher);
ASSERT_EQ(2, dispatcher.dispatch_count_);
}
-#endif
+#endif // defined(OS_WIN)
+
+} // namespace
+
+//-----------------------------------------------------------------------------
+// Each test is run against each type of MessageLoop. That way we are sure
+// 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, PostTask) {
+ RunTest_PostTask(MessageLoop::TYPE_DEFAULT);
+ RunTest_PostTask(MessageLoop::TYPE_UI);
+ RunTest_PostTask(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, PostTask_SEH) {
+ RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT);
+ RunTest_PostTask_SEH(MessageLoop::TYPE_UI);
+ RunTest_PostTask_SEH(MessageLoop::TYPE_IO);
+}
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, Crasher) {
+ RunTest_Crasher(MessageLoop::TYPE_DEFAULT);
+ RunTest_Crasher(MessageLoop::TYPE_UI);
+ RunTest_Crasher(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, CrasherNasty) {
+ RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT);
+ RunTest_CrasherNasty(MessageLoop::TYPE_UI);
+ RunTest_CrasherNasty(MessageLoop::TYPE_IO);
+}
+#endif // defined(OS_WIN)
+
+TEST(MessageLoopTest, Nesting) {
+ RunTest_Nesting(MessageLoop::TYPE_DEFAULT);
+ RunTest_Nesting(MessageLoop::TYPE_UI);
+ RunTest_Nesting(MessageLoop::TYPE_IO);
+}
+TEST(MessageLoopTest, RecursiveDenial1) {
+ RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT);
+ RunTest_RecursiveDenial1(MessageLoop::TYPE_UI);
+ RunTest_RecursiveDenial1(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RecursiveSupport1) {
+ RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT);
+ RunTest_RecursiveSupport1(MessageLoop::TYPE_UI);
+ RunTest_RecursiveSupport1(MessageLoop::TYPE_IO);
+}
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, RecursiveDenial2) {
+ RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
+ RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
+ RunTest_RecursiveDenial2(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RecursiveSupport2) {
+ // This test requires a UI loop
+ RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
+}
+#endif // defined(OS_WIN)
+
+TEST(MessageLoopTest, NonNestableWithNoNesting) {
+ RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT);
+ RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI);
+ RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, NonNestableInNestedLoop) {
+ RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT);
+ RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI);
+ RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO);
+}
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, AutoresetEvents) {
+ // This test requires an IO loop
+ RunTest_AutoresetEvents(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, Dispatcher) {
+ // This test requires a UI loop
+ RunTest_Dispatcher(MessageLoop::TYPE_UI);
+}
+#endif // defined(OS_WIN)
diff --git a/base/object_watcher_unittest.cc b/base/object_watcher_unittest.cc
index 1598d76..d830dfc 100644
--- a/base/object_watcher_unittest.cc
+++ b/base/object_watcher_unittest.cc
@@ -9,6 +9,7 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace {
+
typedef testing::Test ObjectWatcherTest;
class QuitDelegate : public base::ObjectWatcher::Delegate {
@@ -29,9 +30,11 @@ class DecrementCountDelegate : public base::ObjectWatcher::Delegate {
int* counter_;
};
-}
+} // namespace
TEST(ObjectWatcherTest, BasicSignal) {
+ MessageLoop message_loop;
+
base::ObjectWatcher watcher;
// A manual-reset event that is not yet signaled.
@@ -49,6 +52,8 @@ TEST(ObjectWatcherTest, BasicSignal) {
}
TEST(ObjectWatcherTest, BasicCancel) {
+ MessageLoop message_loop;
+
base::ObjectWatcher watcher;
// A manual-reset event that is not yet signaled.
@@ -65,6 +70,8 @@ TEST(ObjectWatcherTest, BasicCancel) {
TEST(ObjectWatcherTest, CancelAfterSet) {
+ MessageLoop message_loop;
+
base::ObjectWatcher watcher;
int counter = 1;
@@ -91,10 +98,10 @@ TEST(ObjectWatcherTest, CancelAfterSet) {
CloseHandle(event);
}
-// Used so we can simulate a MessageLoop that dies before an ObjectWatcher.
-// This ordinarily doesn't happen when people use the Thread class, but it can
-// happen when people use the Singleton pattern or atexit.
-static unsigned __stdcall ThreadFunc(void* param) {
+TEST(ObjectWatcherTest, OutlivesMessageLoop) {
+ // Simulate a MessageLoop that dies before an ObjectWatcher. This ordinarily
+ // doesn't happen when people use the Thread class, but it can happen when
+ // people use the Singleton pattern or atexit.
HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); // not signaled
{
base::ObjectWatcher watcher;
@@ -106,19 +113,4 @@ static unsigned __stdcall ThreadFunc(void* param) {
}
}
CloseHandle(event);
- return 0;
}
-
-TEST(ObjectWatcherTest, OutlivesMessageLoop) {
- unsigned int thread_id;
- HANDLE thread = reinterpret_cast<HANDLE>(
- _beginthreadex(NULL,
- 0,
- ThreadFunc,
- NULL,
- 0,
- &thread_id));
- WaitForSingleObject(thread, INFINITE);
- CloseHandle(thread);
-}
-
diff --git a/base/run_all_unittests.cc b/base/run_all_unittests.cc
index 7b469e2..c0b131f 100644
--- a/base/run_all_unittests.cc
+++ b/base/run_all_unittests.cc
@@ -2,15 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/at_exit.h"
#include "base/test_suite.h"
int main(int argc, char** argv) {
- // Set up an AtExitManager so Singleton objects will be destroyed.
- base::AtExitManager at_exit_manager;
-
- CommandLine::SetArgcArgv(argc, argv);
-
return TestSuite(argc, argv).Run();
}
diff --git a/base/test_suite.h b/base/test_suite.h
index 8a163ec..ae5faf1 100644
--- a/base/test_suite.h
+++ b/base/test_suite.h
@@ -9,13 +9,11 @@
// instantiate this class in your main function and call its Run method to run
// any gtest based tests that are linked into your executable.
-#include "build/build_config.h"
-
+#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/debug_on_start.h"
#include "base/icu_util.h"
#include "base/logging.h"
-#include "base/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
@@ -26,23 +24,18 @@
class TestSuite {
public:
TestSuite(int argc, char** argv) {
+ CommandLine::SetArgcArgv(argc, argv);
testing::InitGoogleTest(&argc, argv);
}
- virtual ~TestSuite() {
- // Flush any remaining messages. This ensures that any accumulated Task
- // objects get destroyed before we exit, which avoids noise in purify
- // leak-test results.
- message_loop_.RunAllPending();
- }
+ virtual ~TestSuite() {}
int Run() {
Initialize();
#if defined(OS_WIN)
// Check to see if we are being run as a client process.
- std::wstring client_func =
- parsed_command_line_.GetSwitchValue(kRunClientProcess);
+ std::wstring client_func = CommandLine().GetSwitchValue(kRunClientProcess);
if (!client_func.empty()) {
// Convert our function name to a usable string for GetProcAddress.
std::string func_name(client_func.begin(), client_func.end());
@@ -57,7 +50,11 @@ class TestSuite {
return -1;
}
#endif
- return RUN_ALL_TESTS();
+
+ int result = RUN_ALL_TESTS();
+
+ Shutdown();
+ return result;
}
protected:
@@ -80,11 +77,14 @@ class TestSuite {
}
#endif
+ // Override these for custom initialization and shutdown handling. Use these
+ // instead of putting complex code in your constructor/destructor.
+
virtual void Initialize() {
#if defined(OS_WIN)
// In some cases, we do not want to see standard error dialogs.
if (!IsDebuggerPresent() &&
- !parsed_command_line_.HasSwitch(L"show-error-dialogs")) {
+ !CommandLine().HasSwitch(L"show-error-dialogs")) {
SuppressErrorDialogs();
logging::SetLogAssertHandler(UnitTestAssertHandler);
}
@@ -93,8 +93,12 @@ class TestSuite {
icu_util::Initialize();
}
- CommandLine parsed_command_line_;
- MessageLoop message_loop_;
+ virtual void Shutdown() {
+ }
+
+ // Make sure that we setup an AtExitManager so Singleton objects will be
+ // destroyed.
+ base::AtExitManager at_exit_manager_;
};
#endif // BASE_TEST_SUITE_H_
diff --git a/base/thread.cc b/base/thread.cc
index 0fe023a..d411ae9 100644
--- a/base/thread.cc
+++ b/base/thread.cc
@@ -4,10 +4,11 @@
#include "base/thread.h"
-#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
+namespace base {
+
// This task is used to trigger the message loop to exit.
class ThreadQuitTask : public Task {
public:
@@ -17,11 +18,24 @@ class ThreadQuitTask : public Task {
}
};
+// Used to pass data to ThreadMain. This structure is allocated on the stack
+// from within StartWithOptions.
+struct Thread::StartupData {
+ // We get away with a const reference here because of how we are allocated.
+ const Thread::Options& options;
+
+ // Used to synchronize thread startup.
+ WaitableEvent event;
+
+ StartupData(const Options& opt) : options(opt), event(false, false) {}
+};
+
Thread::Thread(const char *name)
- : message_loop_(NULL),
- startup_event_(NULL),
- name_(name),
- thread_created_(false) {
+ : startup_data_(NULL),
+ thread_(NULL),
+ message_loop_(NULL),
+ thread_id_(0),
+ name_(name) {
}
Thread::~Thread() {
@@ -52,59 +66,62 @@ bool Thread::GetThreadWasQuitProperly() {
}
bool Thread::Start() {
- return StartWithStackSize(0);
+ return StartWithOptions(Options());
}
-bool Thread::StartWithStackSize(size_t stack_size) {
+bool Thread::StartWithOptions(const Options& options) {
DCHECK(!message_loop_);
SetThreadWasQuitProperly(false);
- base::WaitableEvent event(false, false);
- startup_event_ = &event;
+ StartupData startup_data(options);
+ startup_data_ = &startup_data;
- if (!PlatformThread::Create(stack_size, this, &thread_)) {
+ if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
DLOG(ERROR) << "failed to create thread";
+ startup_data_ = NULL; // Record that we failed to start.
return false;
}
// Wait for the thread to start and initialize message_loop_
- startup_event_->Wait();
- startup_event_ = NULL;
+ startup_data.event.Wait();
DCHECK(message_loop_);
return true;
}
void Thread::Stop() {
- if (!thread_created_)
+ if (!thread_was_started())
return;
- DCHECK_NE(thread_id_, PlatformThread::CurrentId()) <<
- "Can't call Stop() on the currently executing thread";
+ // We should only be called on the same thread that started us.
+ DCHECK_NE(thread_id_, PlatformThread::CurrentId());
- // If StopSoon was called, then we won't have a message loop anymore, but
- // more importantly, we won't need to tell the thread to stop.
+ // StopSoon may have already been called.
if (message_loop_)
message_loop_->PostTask(FROM_HERE, new ThreadQuitTask());
- // Wait for the thread to exit. It should already have terminated but make
+ // Wait for the thread to exit. It should already have terminated but make
// sure this assumption is valid.
+ //
+ // TODO(darin): Unfortunately, we need to keep message_loop_ around until
+ // the thread exits. Some consumers are abusing the API. Make them stop.
+ //
PlatformThread::Join(thread_);
// The thread can't receive messages anymore.
message_loop_ = NULL;
// The thread no longer needs to be joined.
- thread_created_ = false;
+ startup_data_ = NULL;
}
void Thread::StopSoon() {
if (!message_loop_)
return;
- DCHECK_NE(thread_id_, PlatformThread::CurrentId()) <<
- "Can't call StopSoon() on the currently executing thread";
+ // We should only be called on the same thread that started us.
+ DCHECK_NE(thread_id_, PlatformThread::CurrentId());
// We had better have a message loop at this point! If we do not, then it
// most likely means that the thread terminated unexpectedly, probably due
@@ -119,17 +136,16 @@ void Thread::StopSoon() {
void Thread::ThreadMain() {
// The message loop for this thread.
- MessageLoop message_loop;
+ MessageLoop message_loop(startup_data_->options.message_loop_type);
// Complete the initialization of our Thread object.
thread_id_ = PlatformThread::CurrentId();
PlatformThread::SetName(name_.c_str());
message_loop.set_thread_name(name_);
message_loop_ = &message_loop;
- thread_created_ = true;
- startup_event_->Signal();
- // startup_event_ can't be touched anymore since the starting thread is now
+ startup_data_->event.Signal();
+ // startup_data_ can't be touched anymore since the starting thread is now
// unlocked.
// Let the thread do extra initialization.
@@ -147,3 +163,4 @@ void Thread::ThreadMain() {
message_loop_ = NULL;
}
+} // namespace base
diff --git a/base/thread.h b/base/thread.h
index 1b3ba14..619d2b7 100644
--- a/base/thread.h
+++ b/base/thread.h
@@ -7,14 +7,11 @@
#include <string>
+#include "base/message_loop.h"
#include "base/platform_thread.h"
#include "base/thread_local_storage.h"
-class MessageLoop;
-
namespace base {
-class WaitableEvent;
-}
// A simple thread abstraction that establishes a MessageLoop on a new thread.
// The consumer uses the MessageLoop of the thread to cause code to execute on
@@ -23,12 +20,27 @@ class WaitableEvent;
// before the thread is terminated.
class Thread : PlatformThread::Delegate {
public:
+ struct Options {
+ // Specifies the type of message loop that will be allocated on the thread.
+ MessageLoop::Type message_loop_type;
+
+ // Specifies the maximum stack size that the thread is allowed to use.
+ // This does not necessarily correspond to the thread's initial stack size.
+ // A value of 0 indicates that the default maximum should be used.
+ size_t stack_size;
+
+ Options() : message_loop_type(MessageLoop::TYPE_DEFAULT), stack_size(0) {}
+ };
+
// Constructor.
// name is a display string to identify the thread.
explicit Thread(const char *name);
// Destroys the thread, stopping it if necessary.
//
+ // NOTE: If you are subclassing from Thread, and you wish for your CleanUp
+ // method to be called, then you need to call Stop() from your destructor.
+ //
virtual ~Thread();
// Starts the thread. Returns true if the thread was successfully started;
@@ -41,13 +53,12 @@ class Thread : PlatformThread::Delegate {
bool Start();
// Starts the thread. Behaves exactly like Start in addition to allow to
- // override the default process stack size. This is not the initial stack size
- // but the maximum stack size that thread is allowed to use.
+ // override the default options.
//
// Note: This function can't be called on Windows with the loader lock held;
// i.e. during a DllMain, global object construction or destruction, atexit()
// callback.
- bool StartWithStackSize(size_t stack_size);
+ bool StartWithOptions(const Options& options);
// Signals the thread to exit and returns once the thread has exited. After
// this method returns, the Thread object is completely reset and may be used
@@ -93,10 +104,10 @@ class Thread : PlatformThread::Delegate {
protected:
// Called just prior to starting the message loop
- virtual void Init() { }
+ virtual void Init() {}
// Called just after the message loop ends
- virtual void CleanUp() { }
+ virtual void CleanUp() {}
static void SetThreadWasQuitProperly(bool flag);
static bool GetThreadWasQuitProperly();
@@ -105,25 +116,27 @@ class Thread : PlatformThread::Delegate {
// PlatformThread::Delegate methods:
virtual void ThreadMain();
+ // We piggy-back on the startup_data_ member to know if we successfully
+ // started the thread. This way we know that we need to call Join.
+ bool thread_was_started() const { return startup_data_ != NULL; }
+
+ // Used to pass data to ThreadMain.
+ struct StartupData;
+ StartupData* startup_data_;
+
// The thread's handle.
PlatformThreadHandle thread_;
- // The thread's ID. Used for debugging purposes.
- int thread_id_;
-
// The thread's message loop. Valid only while the thread is alive. Set
// by the created thread.
MessageLoop* message_loop_;
- // Used to synchronize thread startup.
- base::WaitableEvent* startup_event_;
+ // Our thread's ID. Used for debugging purposes.
+ int thread_id_;
// The name of the thread. Used for debugging purposes.
std::string name_;
- // This flag indicates if we created a thread that needs to be joined.
- bool thread_created_;
-
static TLSSlot tls_index_;
friend class ThreadQuitTask;
@@ -131,5 +144,7 @@ class Thread : PlatformThread::Delegate {
DISALLOW_COPY_AND_ASSIGN(Thread);
};
+} // namespace base
+
#endif // BASE_THREAD_H_
diff --git a/base/thread_unittest.cc b/base/thread_unittest.cc
index c570e91..cad346f 100644
--- a/base/thread_unittest.cc
+++ b/base/thread_unittest.cc
@@ -8,6 +8,8 @@
#include "base/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::Thread;
+
namespace {
class ToggleValue : public Task {
@@ -50,11 +52,13 @@ TEST(ThreadTest, Restart) {
EXPECT_FALSE(a.message_loop());
}
-TEST(ThreadTest, StartWithStackSize) {
+TEST(ThreadTest, StartWithOptions_StackSize) {
Thread a("StartWithStackSize");
// Ensure that the thread can work with only 12 kb and still process a
// message.
- EXPECT_TRUE(a.StartWithStackSize(12*1024));
+ Thread::Options options;
+ options.stack_size = 12*1024;
+ EXPECT_TRUE(a.StartWithOptions(options));
EXPECT_TRUE(a.message_loop());
bool was_invoked = false;
diff --git a/base/timer_unittest.cc b/base/timer_unittest.cc
index 3fa85f5..ab13c08 100644
--- a/base/timer_unittest.cc
+++ b/base/timer_unittest.cc
@@ -8,9 +8,8 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace {
- class TimerTest : public testing::Test {
- };
-};
+
+class TimerTest : public testing::Test {};
// A base class timer task that sanity-checks timer functionality and counts
// the number of times it has run. Handles all message loop and memory
@@ -196,7 +195,12 @@ void RunTimerTest() {
EXPECT_EQ(10, task3.iterations());
}
-TEST(TimerTest, TimerComparison) {
+//-----------------------------------------------------------------------------
+// The timer test cases:
+
+void RunTest_TimerComparison(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
// Make sure TimerComparison sorts correctly.
const TimerTask task1(10, false);
const Timer* timer1 = task1.timer();
@@ -207,11 +211,15 @@ TEST(TimerTest, TimerComparison) {
EXPECT_TRUE(comparison(timer2, timer1));
}
-TEST(TimerTest, TimerCase) {
+void RunTest_BasicTimer(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
RunTimerTest();
}
-TEST(TimerTest, BrokenTimerCase) {
+void RunTest_BrokenTimer(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
// Simulate faulty early-firing timers. The tasks in RunTimerTest should
// nevertheless be invoked after their specified delays, regardless of when
// WM_TIMER fires.
@@ -221,7 +229,9 @@ TEST(TimerTest, BrokenTimerCase) {
manager->set_use_broken_delay(false);
}
-TEST(TimerTest, DeleteFromRun) {
+void RunTest_DeleteFromRun(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
// Make sure TimerManager correctly handles a Task that deletes itself when
// run.
new DeletingTask(50, true);
@@ -231,7 +241,9 @@ TEST(TimerTest, DeleteFromRun) {
EXPECT_EQ(1, timer_task.iterations());
}
-TEST(TimerTest, Reset) {
+void RunTest_Reset(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
// Make sure resetting a timer after it has fired works.
TimerTask timer_task1(250, false);
TimerTask timer_task2(100, true);
@@ -253,7 +265,9 @@ TEST(TimerTest, Reset) {
EXPECT_EQ(0, timer_task4.iterations());
}
-TEST(TimerTest, FifoOrder) {
+void RunTest_FifoOrder(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
// Creating timers with the same timeout should
// always compare to result in FIFO ordering.
@@ -309,3 +323,44 @@ TEST(TimerTest, FifoOrder) {
EXPECT_GT(new_id, last_id);
}
+} // namespace
+
+//-----------------------------------------------------------------------------
+// Each test is run against each type of MessageLoop. That way we are sure
+// that timers work properly in all configurations.
+
+TEST(TimerTest, TimerComparison) {
+ RunTest_TimerComparison(MessageLoop::TYPE_DEFAULT);
+ RunTest_TimerComparison(MessageLoop::TYPE_UI);
+ RunTest_TimerComparison(MessageLoop::TYPE_IO);
+}
+
+TEST(TimerTest, BasicTimer) {
+ RunTest_BasicTimer(MessageLoop::TYPE_DEFAULT);
+ RunTest_BasicTimer(MessageLoop::TYPE_UI);
+ RunTest_BasicTimer(MessageLoop::TYPE_IO);
+}
+
+TEST(TimerTest, BrokenTimer) {
+ RunTest_BrokenTimer(MessageLoop::TYPE_DEFAULT);
+ RunTest_BrokenTimer(MessageLoop::TYPE_UI);
+ RunTest_BrokenTimer(MessageLoop::TYPE_IO);
+}
+
+TEST(TimerTest, DeleteFromRun) {
+ RunTest_DeleteFromRun(MessageLoop::TYPE_DEFAULT);
+ RunTest_DeleteFromRun(MessageLoop::TYPE_UI);
+ RunTest_DeleteFromRun(MessageLoop::TYPE_IO);
+}
+
+TEST(TimerTest, Reset) {
+ RunTest_Reset(MessageLoop::TYPE_DEFAULT);
+ RunTest_Reset(MessageLoop::TYPE_UI);
+ RunTest_Reset(MessageLoop::TYPE_IO);
+}
+
+TEST(TimerTest, FifoOrder) {
+ RunTest_FifoOrder(MessageLoop::TYPE_DEFAULT);
+ RunTest_FifoOrder(MessageLoop::TYPE_UI);
+ RunTest_FifoOrder(MessageLoop::TYPE_IO);
+}
diff --git a/net/base/listen_socket_unittest.h b/net/base/listen_socket_unittest.h
index 8c5cb6d..36af167 100644
--- a/net/base/listen_socket_unittest.h
+++ b/net/base/listen_socket_unittest.h
@@ -77,7 +77,7 @@ class ListenSocketTester :
server_ = NULL;
net::WinsockInit::Init();
- thread_.reset(new Thread("socketio_test"));
+ thread_.reset(new base::Thread("socketio_test"));
thread_->Start();
loop_ = thread_->message_loop();
@@ -251,7 +251,7 @@ class ListenSocketTester :
ASSERT_EQ(buf, HELLO_WORLD);
}
- scoped_ptr<Thread> thread_;
+ scoped_ptr<base::Thread> thread_;
MessageLoop* loop_;
ListenSocket* server_;
ListenSocket* connection_;
diff --git a/net/base/run_all_unittests.cc b/net/base/run_all_unittests.cc
new file mode 100644
index 0000000..a1bae81
--- /dev/null
+++ b/net/base/run_all_unittests.cc
@@ -0,0 +1,58 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/message_loop.h"
+#include "base/test_suite.h"
+
+class NetTestSuite : public TestSuite {
+ public:
+ NetTestSuite(int argc, char** argv) : TestSuite(argc, argv) {
+ }
+
+ virtual void Initialize() {
+ TestSuite::Initialize();
+
+ message_loop_.reset(new MessageLoopForIO());
+ }
+
+ virtual void CleanUp() {
+ // We want to destroy this here before the TestSuite continues to tear down
+ // the environment.
+ message_loop_.reset();
+
+ TestSuite::Shutdown();
+ }
+
+ private:
+ scoped_ptr<MessageLoop> message_loop_;
+};
+
+int main(int argc, char** argv) {
+ return NetTestSuite(argc, argv).Run();
+}
diff --git a/net/build/net_unittests.vcproj b/net/build/net_unittests.vcproj
index 1619e5c..d1d720d 100644
--- a/net/build/net_unittests.vcproj
+++ b/net/build/net_unittests.vcproj
@@ -172,7 +172,7 @@
>
</File>
<File
- RelativePath="..\..\base\run_all_unittests.cc"
+ RelativePath="..\base\run_all_unittests.cc"
>
</File>
</Filter>
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index 1d48090..ec4fdd6 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -325,7 +325,7 @@ int ProxyService::ResolveProxy(const GURL& url, ProxyInfo* result,
if (callback) {
// Create PAC thread for asynchronous mode.
if (!pac_thread_.get()) {
- pac_thread_.reset(new Thread("pac-thread"));
+ pac_thread_.reset(new base::Thread("pac-thread"));
pac_thread_->Start();
}
} else {
diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h
index 94e8235..5ca41e8 100644
--- a/net/proxy/proxy_service.h
+++ b/net/proxy/proxy_service.h
@@ -129,7 +129,7 @@ class ProxyService {
friend class PacRequest;
ProxyResolver* resolver() { return resolver_; }
- Thread* pac_thread() { return pac_thread_.get(); }
+ base::Thread* pac_thread() { return pac_thread_.get(); }
// Identifies the proxy configuration.
ProxyConfig::ID config_id() const { return config_.id(); }
@@ -151,7 +151,7 @@ class ProxyService {
bool ShouldBypassProxyForURL(const GURL& url);
ProxyResolver* resolver_;
- scoped_ptr<Thread> pac_thread_;
+ scoped_ptr<base::Thread> pac_thread_;
// We store the IE proxy config and a counter that is incremented each time
// the config changes.
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 6547e38..8c6d5f3 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -5,6 +5,7 @@
#include "net/url_request/url_request.h"
#include "base/basictypes.h"
+#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/singleton.h"
#include "base/stats_counters.h"
@@ -47,6 +48,12 @@ URLRequest::URLRequest(const GURL& url, Delegate* delegate)
URLREQUEST_COUNT_CTOR();
SIMPLE_STATS_COUNTER(L"URLRequestCount");
origin_pid_ = process_util::GetCurrentProcId();
+
+ // Sanity check out environment.
+ DCHECK(MessageLoop::current()) <<
+ "The current MessageLoop must exist";
+ DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
+ "The current MessageLoop must be TYPE_IO";
}
URLRequest::~URLRequest() {
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index 2ceaed3..4e23d78 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -140,7 +140,7 @@ void URLRequestFileJob::Start() {
void URLRequestFileJob::Kill() {
// If we are killed while waiting for an overlapped result...
if (is_waiting_) {
- MessageLoop::current()->WatchObject(overlapped_.hEvent, NULL);
+ MessageLoopForIO::current()->WatchObject(overlapped_.hEvent, NULL);
is_waiting_ = false;
Release();
}
@@ -178,7 +178,7 @@ bool URLRequestFileJob::ReadRawData(char* dest, int dest_size,
DWORD err = GetLastError();
if (err == ERROR_IO_PENDING) {
// OK, wait for the object to become signaled
- MessageLoop::current()->WatchObject(overlapped_.hEvent, this);
+ MessageLoopForIO::current()->WatchObject(overlapped_.hEvent, this);
is_waiting_ = true;
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
AddRef();
@@ -261,7 +261,7 @@ void URLRequestFileJob::OnObjectSignaled(HANDLE object) {
// We'll resume watching this handle if need be when we do
// another IO.
- MessageLoop::current()->WatchObject(object, NULL);
+ MessageLoopForIO::current()->WatchObject(object, NULL);
is_waiting_ = false;
DWORD bytes_read = 0;
diff --git a/net/url_request/url_request_file_job.h b/net/url_request/url_request_file_job.h
index f5999d3..638f4ff 100644
--- a/net/url_request/url_request_file_job.h
+++ b/net/url_request/url_request_file_job.h
@@ -14,7 +14,7 @@
// A request job that handles reading file URLs
class URLRequestFileJob : public URLRequestJob,
- protected MessageLoop::Watcher {
+ protected MessageLoopForIO::Watcher {
public:
URLRequestFileJob(URLRequest* request);
virtual ~URLRequestFileJob();
diff --git a/net/url_request/url_request_unittest.h b/net/url_request/url_request_unittest.h
index ea9b68e..f17e7fc 100644
--- a/net/url_request/url_request_unittest.h
+++ b/net/url_request/url_request_unittest.h
@@ -13,6 +13,8 @@
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_util.h"
+#include "base/thread.h"
+#include "base/waitable_event.h"
#include "net/base/net_errors.h"
#include "net/http/http_network_layer.h"
#include "net/url_request/url_request.h"
@@ -113,7 +115,7 @@ class TestDelegate : public URLRequest::Delegate {
request->Cancel();
}
- void OnResponseCompleted(URLRequest* request) {
+ virtual void OnResponseCompleted(URLRequest* request) {
if (quit_on_complete_)
MessageLoop::current()->Quit();
}
@@ -183,8 +185,7 @@ class TestDelegate : public URLRequest::Delegate {
class TestServer : public process_util::ProcessFilter {
public:
TestServer(const std::wstring& document_root)
- : context_(new TestURLRequestContext),
- process_handle_(NULL),
+ : process_handle_(NULL),
is_shutdown_(true) {
Init(kDefaultHostName, kDefaultPort, document_root, std::wstring());
}
@@ -213,16 +214,23 @@ class TestServer : public process_util::ProcessFilter {
// A subclass may wish to send the request in a different manner
virtual bool MakeGETRequest(const std::string& page_name) {
- TestDelegate d;
- URLRequest r(TestServerPage(page_name), &d);
- r.set_context(context_);
- r.set_method("GET");
- r.Start();
- EXPECT_TRUE(r.is_pending());
-
- MessageLoop::current()->Run();
-
- return r.status().is_success();
+ const GURL& url = TestServerPage(page_name);
+
+ // Spin up a background thread for this request so that we have access to
+ // an IO message loop, and in cases where this thread already has an IO
+ // message loop, we also want to avoid spinning a nested message loop.
+
+ SyncTestDelegate d;
+ {
+ base::Thread io_thread("MakeGETRequest");
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ io_thread.StartWithOptions(options);
+ io_thread.message_loop()->PostTask(FROM_HERE, NewRunnableFunction(
+ &TestServer::StartGETRequest, url, &d));
+ d.Wait();
+ }
+ return d.did_succeed();
}
protected:
@@ -232,8 +240,7 @@ class TestServer : public process_util::ProcessFilter {
// constructed. The subclass should call Init once it is ready (usually in
// its constructor).
TestServer(ManualInit)
- : context_(new TestURLRequestContext),
- process_handle_(NULL),
+ : process_handle_(NULL),
is_shutdown_(true) {
}
@@ -334,7 +341,31 @@ class TestServer : public process_util::ProcessFilter {
}
private:
- scoped_refptr<TestURLRequestContext> context_;
+ // Used by MakeGETRequest to implement sync load behavior.
+ class SyncTestDelegate : public TestDelegate {
+ public:
+ SyncTestDelegate() : event_(false, false), success_(false) {
+ }
+ virtual void OnResponseCompleted(URLRequest* request) {
+ MessageLoop::current()->DeleteSoon(FROM_HERE, request);
+ success_ = request->status().is_success();
+ event_.Signal();
+ }
+ void Wait() { event_.Wait(); }
+ bool did_succeed() const { return success_; }
+ private:
+ base::WaitableEvent event_;
+ bool success_;
+ DISALLOW_COPY_AND_ASSIGN(SyncTestDelegate);
+ };
+ static void StartGETRequest(const GURL& url, URLRequest::Delegate* delegate) {
+ URLRequest* request = new URLRequest(url, delegate);
+ request->set_context(new TestURLRequestContext());
+ request->set_method("GET");
+ request->Start();
+ EXPECT_TRUE(request->is_pending());
+ }
+
std::string base_address_;
std::wstring python_runtime_;
HANDLE process_handle_;
diff --git a/webkit/default_plugin/plugin_install_job_monitor.h b/webkit/default_plugin/plugin_install_job_monitor.h
index 97b5c79..825c2e2 100644
--- a/webkit/default_plugin/plugin_install_job_monitor.h
+++ b/webkit/default_plugin/plugin_install_job_monitor.h
@@ -14,7 +14,7 @@
// The PluginInstallationJobMonitorThread class represents a background
// thread which monitors the install job completion port which is associated
// with the job when an instance of this class is initialized.
-class PluginInstallationJobMonitorThread : public Thread {
+class PluginInstallationJobMonitorThread : public base::Thread {
public:
PluginInstallationJobMonitorThread();
virtual ~PluginInstallationJobMonitorThread();
diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.cc b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
index 2e69ce8..4c58b34 100644
--- a/webkit/tools/test_shell/simple_resource_loader_bridge.cc
+++ b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
@@ -51,11 +51,11 @@ namespace {
//-----------------------------------------------------------------------------
URLRequestContext* request_context = NULL;
-Thread* io_thread = NULL;
+base::Thread* io_thread = NULL;
-class IOThread : public Thread {
+class IOThread : public base::Thread {
public:
- IOThread() : Thread("IOThread") {
+ IOThread() : base::Thread("IOThread") {
}
~IOThread() {
@@ -80,7 +80,9 @@ bool EnsureIOThread() {
SimpleResourceLoaderBridge::Init(NULL);
io_thread = new IOThread();
- return io_thread->Start();
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ return io_thread->StartWithOptions(options);
}
//-----------------------------------------------------------------------------