|  | // Copyright 2017 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/message_loop/message_loop.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/compiler_specific.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/files/scoped_file.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/message_loop/message_loop_current.h" | 
|  | #include "base/message_loop/message_pump_for_io.h" | 
|  | #include "base/posix/eintr_wrapper.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/test/gtest_util.h" | 
|  | #include "build/build_config.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | #if !defined(OS_NACL) | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class MessageLoopForIoPosixTest : public testing::Test { | 
|  | public: | 
|  | MessageLoopForIoPosixTest() = default; | 
|  |  | 
|  | // testing::Test interface. | 
|  | void SetUp() override { | 
|  | // Create a file descriptor.  Doesn't need to be readable or writable, | 
|  | // as we don't need to actually get any notifications. | 
|  | // pipe() is just the easiest way to do it. | 
|  | int pipefds[2]; | 
|  | int err = pipe(pipefds); | 
|  | ASSERT_EQ(0, err); | 
|  | read_fd_ = ScopedFD(pipefds[0]); | 
|  | write_fd_ = ScopedFD(pipefds[1]); | 
|  | } | 
|  |  | 
|  | void TriggerReadEvent() { | 
|  | // Write from the other end of the pipe to trigger the event. | 
|  | char c = '\0'; | 
|  | EXPECT_EQ(1, HANDLE_EINTR(write(write_fd_.get(), &c, 1))); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | ScopedFD read_fd_; | 
|  | ScopedFD write_fd_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MessageLoopForIoPosixTest); | 
|  | }; | 
|  |  | 
|  | class TestHandler : public MessagePumpForIO::FdWatcher { | 
|  | public: | 
|  | void OnFileCanReadWithoutBlocking(int fd) override { | 
|  | watcher_to_delete_ = nullptr; | 
|  | is_readable_ = true; | 
|  | RunLoop::QuitCurrentWhenIdleDeprecated(); | 
|  | } | 
|  | void OnFileCanWriteWithoutBlocking(int fd) override { | 
|  | watcher_to_delete_ = nullptr; | 
|  | is_writable_ = true; | 
|  | RunLoop::QuitCurrentWhenIdleDeprecated(); | 
|  | } | 
|  |  | 
|  | bool is_readable_ = false; | 
|  | bool is_writable_ = false; | 
|  |  | 
|  | // If set then the contained watcher will be deleted on notification. | 
|  | std::unique_ptr<MessagePumpForIO::FdWatchController> watcher_to_delete_; | 
|  | }; | 
|  |  | 
|  | // Watcher that calls specified closures when read/write events occur. Verifies | 
|  | // that each non-null closure passed to this class is called once and only once. | 
|  | // Also resets the read event by reading from the FD. | 
|  | class CallClosureHandler : public MessagePumpForIO::FdWatcher { | 
|  | public: | 
|  | CallClosureHandler(OnceClosure read_closure, OnceClosure write_closure) | 
|  | : read_closure_(std::move(read_closure)), | 
|  | write_closure_(std::move(write_closure)) {} | 
|  |  | 
|  | ~CallClosureHandler() override { | 
|  | EXPECT_TRUE(read_closure_.is_null()); | 
|  | EXPECT_TRUE(write_closure_.is_null()); | 
|  | } | 
|  |  | 
|  | void SetReadClosure(OnceClosure read_closure) { | 
|  | EXPECT_TRUE(read_closure_.is_null()); | 
|  | read_closure_ = std::move(read_closure); | 
|  | } | 
|  |  | 
|  | void SetWriteClosure(OnceClosure write_closure) { | 
|  | EXPECT_TRUE(write_closure_.is_null()); | 
|  | write_closure_ = std::move(write_closure); | 
|  | } | 
|  |  | 
|  | // base:MessagePumpFuchsia::Watcher interface. | 
|  | void OnFileCanReadWithoutBlocking(int fd) override { | 
|  | // Empty the pipe buffer to reset the event. Otherwise libevent | 
|  | // implementation of MessageLoop may call the event handler again even if | 
|  | // |read_closure_| below quits the RunLoop. | 
|  | char c; | 
|  | int result = HANDLE_EINTR(read(fd, &c, 1)); | 
|  | if (result == -1) { | 
|  | PLOG(ERROR) << "read"; | 
|  | FAIL(); | 
|  | } | 
|  | EXPECT_EQ(result, 1); | 
|  |  | 
|  | ASSERT_FALSE(read_closure_.is_null()); | 
|  | std::move(read_closure_).Run(); | 
|  | } | 
|  |  | 
|  | void OnFileCanWriteWithoutBlocking(int fd) override { | 
|  | ASSERT_FALSE(write_closure_.is_null()); | 
|  | std::move(write_closure_).Run(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | OnceClosure read_closure_; | 
|  | OnceClosure write_closure_; | 
|  | }; | 
|  |  | 
|  | TEST_F(MessageLoopForIoPosixTest, FileDescriptorWatcherOutlivesMessageLoop) { | 
|  | // Simulate a MessageLoop that dies before an FileDescriptorWatcher. | 
|  | // This could happen when people use the Singleton pattern or atexit. | 
|  |  | 
|  | // Arrange for watcher to live longer than message loop. | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  | TestHandler handler; | 
|  | { | 
|  | MessageLoopForIO message_loop; | 
|  |  | 
|  | MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE, &watcher, | 
|  | &handler); | 
|  | // Don't run the message loop, just destroy it. | 
|  | } | 
|  |  | 
|  | ASSERT_FALSE(handler.is_readable_); | 
|  | ASSERT_FALSE(handler.is_writable_); | 
|  | } | 
|  |  | 
|  | TEST_F(MessageLoopForIoPosixTest, FileDescriptorWatcherDoubleStop) { | 
|  | // Verify that it's ok to call StopWatchingFileDescriptor(). | 
|  |  | 
|  | // Arrange for message loop to live longer than watcher. | 
|  | MessageLoopForIO message_loop; | 
|  | { | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  |  | 
|  | TestHandler handler; | 
|  | MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE, &watcher, | 
|  | &handler); | 
|  | ASSERT_TRUE(watcher.StopWatchingFileDescriptor()); | 
|  | ASSERT_TRUE(watcher.StopWatchingFileDescriptor()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(MessageLoopForIoPosixTest, FileDescriptorWatcherDeleteInCallback) { | 
|  | // Verify that it is OK to delete the FileDescriptorWatcher from within a | 
|  | // callback. | 
|  | MessageLoopForIO message_loop; | 
|  |  | 
|  | TestHandler handler; | 
|  | handler.watcher_to_delete_ = | 
|  | std::make_unique<MessagePumpForIO::FdWatchController>(FROM_HERE); | 
|  |  | 
|  | MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE, | 
|  | handler.watcher_to_delete_.get(), &handler); | 
|  | RunLoop().Run(); | 
|  | } | 
|  |  | 
|  | // Verify that basic readable notification works. | 
|  | TEST_F(MessageLoopForIoPosixTest, WatchReadable) { | 
|  | MessageLoopForIO message_loop; | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  | TestHandler handler; | 
|  |  | 
|  | // Watch the pipe for readability. | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, | 
|  | &watcher, &handler)); | 
|  |  | 
|  | // The pipe should not be readable when first created. | 
|  | RunLoop().RunUntilIdle(); | 
|  | ASSERT_FALSE(handler.is_readable_); | 
|  | ASSERT_FALSE(handler.is_writable_); | 
|  |  | 
|  | TriggerReadEvent(); | 
|  |  | 
|  | // We don't want to assume that the read fd becomes readable the | 
|  | // instant a bytes is written, so Run until quit by an event. | 
|  | RunLoop().Run(); | 
|  |  | 
|  | ASSERT_TRUE(handler.is_readable_); | 
|  | ASSERT_FALSE(handler.is_writable_); | 
|  | } | 
|  |  | 
|  | // Verify that watching a file descriptor for writability succeeds. | 
|  | TEST_F(MessageLoopForIoPosixTest, WatchWritable) { | 
|  | MessageLoopForIO message_loop; | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  | TestHandler handler; | 
|  |  | 
|  | // Watch the pipe for writability. | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | write_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_WRITE, | 
|  | &watcher, &handler)); | 
|  |  | 
|  | // We should not receive a writable notification until we process events. | 
|  | ASSERT_FALSE(handler.is_readable_); | 
|  | ASSERT_FALSE(handler.is_writable_); | 
|  |  | 
|  | // The pipe should be writable immediately, but wait for the quit closure | 
|  | // anyway, to be sure. | 
|  | RunLoop().Run(); | 
|  |  | 
|  | ASSERT_FALSE(handler.is_readable_); | 
|  | ASSERT_TRUE(handler.is_writable_); | 
|  | } | 
|  |  | 
|  | // Verify that RunUntilIdle() receives IO notifications. | 
|  | TEST_F(MessageLoopForIoPosixTest, RunUntilIdle) { | 
|  | MessageLoopForIO message_loop; | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  | TestHandler handler; | 
|  |  | 
|  | // Watch the pipe for readability. | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, | 
|  | &watcher, &handler)); | 
|  |  | 
|  | // The pipe should not be readable when first created. | 
|  | RunLoop().RunUntilIdle(); | 
|  | ASSERT_FALSE(handler.is_readable_); | 
|  |  | 
|  | TriggerReadEvent(); | 
|  |  | 
|  | while (!handler.is_readable_) | 
|  | RunLoop().RunUntilIdle(); | 
|  | } | 
|  |  | 
|  | void StopWatching(MessagePumpForIO::FdWatchController* controller, | 
|  | RunLoop* run_loop) { | 
|  | controller->StopWatchingFileDescriptor(); | 
|  | run_loop->Quit(); | 
|  | } | 
|  |  | 
|  | // Verify that StopWatchingFileDescriptor() works from an event handler. | 
|  | TEST_F(MessageLoopForIoPosixTest, StopFromHandler) { | 
|  | MessageLoopForIO message_loop; | 
|  | RunLoop run_loop; | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  | CallClosureHandler handler(BindOnce(&StopWatching, &watcher, &run_loop), | 
|  | OnceClosure()); | 
|  |  | 
|  | // Create persistent watcher. | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ, | 
|  | &watcher, &handler)); | 
|  |  | 
|  | TriggerReadEvent(); | 
|  | run_loop.Run(); | 
|  |  | 
|  | // Trigger the event again. The event handler should not be called again. | 
|  | TriggerReadEvent(); | 
|  | RunLoop().RunUntilIdle(); | 
|  | } | 
|  |  | 
|  | // Verify that non-persistent watcher is called only once. | 
|  | TEST_F(MessageLoopForIoPosixTest, NonPersistentWatcher) { | 
|  | MessageLoopForIO message_loop; | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  |  | 
|  | RunLoop run_loop; | 
|  | CallClosureHandler handler(run_loop.QuitClosure(), OnceClosure()); | 
|  |  | 
|  | // Create a non-persistent watcher. | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, | 
|  | &watcher, &handler)); | 
|  |  | 
|  | TriggerReadEvent(); | 
|  | run_loop.Run(); | 
|  |  | 
|  | // Trigger the event again. handler should not be called again. | 
|  | TriggerReadEvent(); | 
|  | RunLoop().RunUntilIdle(); | 
|  | } | 
|  |  | 
|  | // Verify that persistent watcher is called every time the event is triggered. | 
|  | TEST_F(MessageLoopForIoPosixTest, PersistentWatcher) { | 
|  | MessageLoopForIO message_loop; | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  |  | 
|  | RunLoop run_loop1; | 
|  | CallClosureHandler handler(run_loop1.QuitClosure(), OnceClosure()); | 
|  |  | 
|  | // Create persistent watcher. | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ, | 
|  | &watcher, &handler)); | 
|  |  | 
|  | TriggerReadEvent(); | 
|  | run_loop1.Run(); | 
|  |  | 
|  | RunLoop run_loop2; | 
|  | handler.SetReadClosure(run_loop2.QuitClosure()); | 
|  |  | 
|  | // Trigger the event again. handler should be called now, which will quit | 
|  | // run_loop2. | 
|  | TriggerReadEvent(); | 
|  | run_loop2.Run(); | 
|  | } | 
|  |  | 
|  | void StopWatchingAndWatchAgain(MessagePumpForIO::FdWatchController* controller, | 
|  | int fd, | 
|  | MessagePumpForIO::FdWatcher* new_handler, | 
|  | RunLoop* run_loop) { | 
|  | controller->StopWatchingFileDescriptor(); | 
|  |  | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | fd, /*persistent=*/true, MessagePumpForIO::WATCH_READ, controller, | 
|  | new_handler)); | 
|  |  | 
|  | run_loop->Quit(); | 
|  | } | 
|  |  | 
|  | // Verify that a watcher can be stopped and reused from an event handler. | 
|  | TEST_F(MessageLoopForIoPosixTest, StopAndRestartFromHandler) { | 
|  | MessageLoopForIO message_loop; | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  |  | 
|  | RunLoop run_loop1; | 
|  | RunLoop run_loop2; | 
|  | CallClosureHandler handler2(run_loop2.QuitClosure(), OnceClosure()); | 
|  | CallClosureHandler handler1(BindOnce(&StopWatchingAndWatchAgain, &watcher, | 
|  | read_fd_.get(), &handler2, &run_loop1), | 
|  | OnceClosure()); | 
|  |  | 
|  | // Create persistent watcher. | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ, | 
|  | &watcher, &handler1)); | 
|  |  | 
|  | TriggerReadEvent(); | 
|  | run_loop1.Run(); | 
|  |  | 
|  | // Trigger the event again. handler2 should be called now, which will quit | 
|  | // run_loop2 | 
|  | TriggerReadEvent(); | 
|  | run_loop2.Run(); | 
|  | } | 
|  |  | 
|  | // Verify that the pump properly handles a delayed task after an IO event. | 
|  | TEST_F(MessageLoopForIoPosixTest, IoEventThenTimer) { | 
|  | MessageLoopForIO message_loop; | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  |  | 
|  | RunLoop timer_run_loop; | 
|  | message_loop.task_runner()->PostDelayedTask( | 
|  | FROM_HERE, timer_run_loop.QuitClosure(), | 
|  | base::TimeDelta::FromMilliseconds(10)); | 
|  |  | 
|  | RunLoop watcher_run_loop; | 
|  | CallClosureHandler handler(watcher_run_loop.QuitClosure(), OnceClosure()); | 
|  |  | 
|  | // Create a non-persistent watcher. | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, | 
|  | &watcher, &handler)); | 
|  |  | 
|  | TriggerReadEvent(); | 
|  |  | 
|  | // Normally the IO event will be received before the delayed task is | 
|  | // executed, so this run loop will first handle the IO event and then quit on | 
|  | // the timer. | 
|  | timer_run_loop.Run(); | 
|  |  | 
|  | // Run watcher_run_loop in case the IO event wasn't received before the | 
|  | // delayed task. | 
|  | watcher_run_loop.Run(); | 
|  | } | 
|  |  | 
|  | // Verify that the pipe can handle an IO event after a delayed task. | 
|  | TEST_F(MessageLoopForIoPosixTest, TimerThenIoEvent) { | 
|  | MessageLoopForIO message_loop; | 
|  | MessagePumpForIO::FdWatchController watcher(FROM_HERE); | 
|  |  | 
|  | // Trigger read event from a delayed task. | 
|  | message_loop.task_runner()->PostDelayedTask( | 
|  | FROM_HERE, | 
|  | BindOnce(&MessageLoopForIoPosixTest::TriggerReadEvent, Unretained(this)), | 
|  | TimeDelta::FromMilliseconds(1)); | 
|  |  | 
|  | RunLoop run_loop; | 
|  | CallClosureHandler handler(run_loop.QuitClosure(), OnceClosure()); | 
|  |  | 
|  | // Create a non-persistent watcher. | 
|  | ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( | 
|  | read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, | 
|  | &watcher, &handler)); | 
|  |  | 
|  | run_loop.Run(); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | #endif  // !defined(OS_NACL) | 
|  |  | 
|  | }  // namespace base |