diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-28 19:30:19 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-28 19:30:19 +0000 |
commit | 1ecc13d670d806f3442947f15a760e4e8b0facc1 (patch) | |
tree | c5db32e986f8b11c56f4cee4ff95c55bfafc8749 /base/message_loop | |
parent | 254e209e90d221d654050237f2d1061c56f3f973 (diff) | |
download | chromium_src-1ecc13d670d806f3442947f15a760e4e8b0facc1.zip chromium_src-1ecc13d670d806f3442947f15a760e4e8b0facc1.tar.gz chromium_src-1ecc13d670d806f3442947f15a760e4e8b0facc1.tar.bz2 |
libevent message-pump: Fix a particular case of nested message-loop runs.
If Quit() is called on the message-pump to terminate a nested loop, followed
by a call to Run() again to start another nested loop, in the same iteration
of the loop, then make sure it all works correctly.
We have this scenario with nested menus, modal dialogs, drag-drop etc. in
the browser UI. So this is a prerequisite fix to be able to use the
libevent based message-pump on Chrome OS (and get rid of glib dep).
BUG=240715
R=sky@chromium.org
TBR=darin@chromium.org
Review URL: https://codereview.chromium.org/245923005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266628 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/message_loop')
-rw-r--r-- | base/message_loop/message_pump_libevent.cc | 6 | ||||
-rw-r--r-- | base/message_loop/message_pump_libevent_unittest.cc | 43 |
2 files changed, 45 insertions, 4 deletions
diff --git a/base/message_loop/message_pump_libevent.cc b/base/message_loop/message_pump_libevent.cc index 26be687..d52025a 100644 --- a/base/message_loop/message_pump_libevent.cc +++ b/base/message_loop/message_pump_libevent.cc @@ -217,7 +217,7 @@ static void timer_callback(int fd, short events, void *context) // Reentrant! void MessagePumpLibevent::Run(Delegate* delegate) { - DCHECK(keep_running_) << "Quit must have been called outside of Run!"; + AutoReset<bool> auto_reset_keep_running(&keep_running_, true); AutoReset<bool> auto_reset_in_run(&in_run_, true); // event_base_loopexit() + EVLOOP_ONCE is leaky, see http://crbug.com/25641. @@ -275,12 +275,10 @@ void MessagePumpLibevent::Run(Delegate* delegate) { } } } - - keep_running_ = true; } void MessagePumpLibevent::Quit() { - DCHECK(in_run_); + DCHECK(in_run_) << "Quit was called outside of Run!"; // Tell both libevent and Run that they should break out of their loops. keep_running_ = false; ScheduleWork(); diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc index 4530e188..9298d68 100644 --- a/base/message_loop/message_pump_libevent_unittest.cc +++ b/base/message_loop/message_pump_libevent_unittest.cc @@ -6,8 +6,10 @@ #include <unistd.h> +#include "base/bind.h" #include "base/message_loop/message_loop.h" #include "base/posix/eintr_wrapper.h" +#include "base/run_loop.h" #include "base/threading/thread.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/libevent/event.h" @@ -81,6 +83,12 @@ TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) { "watch_file_descriptor_caller_checker_.CalledOnValidThread\\(\\)"); } +TEST_F(MessagePumpLibeventTest, QuitOutsideOfRun) { + scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); + ASSERT_DEATH(pump->Quit(), "Check failed: in_run_. " + "Quit was called outside of Run!"); +} + #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) class BaseWatcher : public MessagePumpLibevent::Watcher { @@ -157,6 +165,41 @@ TEST_F(MessagePumpLibeventTest, StopWatcher) { OnLibeventNotification(pump.get(), &watcher); } +void QuitMessageLoopAndStart(const Closure& quit_closure) { + quit_closure.Run(); + + MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); + RunLoop runloop; + MessageLoop::current()->PostTask(FROM_HERE, runloop.QuitClosure()); + runloop.Run(); +} + +class NestedPumpWatcher : public MessagePumpLibevent::Watcher { + public: + NestedPumpWatcher() {} + virtual ~NestedPumpWatcher() {} + + virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE { + RunLoop runloop; + MessageLoop::current()->PostTask(FROM_HERE, Bind(&QuitMessageLoopAndStart, + runloop.QuitClosure())); + runloop.Run(); + } + + virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {} +}; + +TEST_F(MessagePumpLibeventTest, NestedPumpWatcher) { + scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); + MessagePumpLibevent::FileDescriptorWatcher watcher; + NestedPumpWatcher delegate; + pump->WatchFileDescriptor(pipefds_[1], + false, MessagePumpLibevent::WATCH_READ, &watcher, &delegate); + + // Spoof a libevent notification. + OnLibeventNotification(pump.get(), &watcher); +} + } // namespace } // namespace base |