diff options
-rw-r--r-- | base/build/base.vcproj | 8 | ||||
-rw-r--r-- | base/idle_timer.cc | 2 | ||||
-rw-r--r-- | base/idletimer_unittest.cc | 15 | ||||
-rw-r--r-- | base/message_loop.cc | 72 | ||||
-rw-r--r-- | base/message_loop.h | 136 | ||||
-rw-r--r-- | base/message_loop_unittest.cc | 224 | ||||
-rw-r--r-- | base/object_watcher_unittest.cc | 32 | ||||
-rw-r--r-- | base/run_all_unittests.cc | 6 | ||||
-rw-r--r-- | base/test_suite.h | 34 | ||||
-rw-r--r-- | base/thread.cc | 67 | ||||
-rw-r--r-- | base/thread.h | 49 | ||||
-rw-r--r-- | base/thread_unittest.cc | 8 | ||||
-rw-r--r-- | base/timer_unittest.cc | 73 | ||||
-rw-r--r-- | net/base/listen_socket_unittest.h | 4 | ||||
-rw-r--r-- | net/base/run_all_unittests.cc | 58 | ||||
-rw-r--r-- | net/build/net_unittests.vcproj | 2 | ||||
-rw-r--r-- | net/proxy/proxy_service.cc | 2 | ||||
-rw-r--r-- | net/proxy/proxy_service.h | 4 | ||||
-rw-r--r-- | net/url_request/url_request.cc | 7 | ||||
-rw-r--r-- | net/url_request/url_request_file_job.cc | 6 | ||||
-rw-r--r-- | net/url_request/url_request_file_job.h | 2 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.h | 63 | ||||
-rw-r--r-- | webkit/default_plugin/plugin_install_job_monitor.h | 2 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_resource_loader_bridge.cc | 10 |
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); } //----------------------------------------------------------------------------- |