| // 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 |