|  | // Copyright 2016 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/task_scheduler/task_tracker_posix.h" | 
|  |  | 
|  | #include <unistd.h> | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/bind_helpers.h" | 
|  | #include "base/files/file_descriptor_watcher_posix.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "base/message_loop/message_loop.h" | 
|  | #include "base/posix/eintr_wrapper.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/sequence_token.h" | 
|  | #include "base/task_scheduler/task.h" | 
|  | #include "base/task_scheduler/task_traits.h" | 
|  | #include "base/task_scheduler/test_utils.h" | 
|  | #include "base/test/null_task_runner.h" | 
|  | #include "base/threading/thread.h" | 
|  | #include "base/time/time.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace internal { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class TaskSchedulerTaskTrackerPosixTest : public testing::Test { | 
|  | public: | 
|  | TaskSchedulerTaskTrackerPosixTest() : service_thread_("ServiceThread") { | 
|  | Thread::Options service_thread_options; | 
|  | service_thread_options.message_loop_type = MessageLoop::TYPE_IO; | 
|  | service_thread_.StartWithOptions(service_thread_options); | 
|  | tracker_.set_watch_file_descriptor_message_loop( | 
|  | static_cast<MessageLoopForIO*>(service_thread_.message_loop())); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | Thread service_thread_; | 
|  | TaskTrackerPosix tracker_ = {"Test"}; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerPosixTest); | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // Verify that TaskTrackerPosix runs a Task it receives. | 
|  | TEST_F(TaskSchedulerTaskTrackerPosixTest, RunTask) { | 
|  | bool did_run = false; | 
|  | Task task(FROM_HERE, | 
|  | Bind([](bool* did_run) { *did_run = true; }, Unretained(&did_run)), | 
|  | TaskTraits(), TimeDelta()); | 
|  |  | 
|  | EXPECT_TRUE(tracker_.WillPostTask(task)); | 
|  |  | 
|  | auto sequence = test::CreateSequenceWithTask(std::move(task)); | 
|  | EXPECT_EQ(sequence, tracker_.WillScheduleSequence(sequence, nullptr)); | 
|  | // Expect RunAndPopNextTask to return nullptr since |sequence| is empty after | 
|  | // popping a task from it. | 
|  | EXPECT_FALSE(tracker_.RunAndPopNextTask(sequence, nullptr)); | 
|  |  | 
|  | EXPECT_TRUE(did_run); | 
|  | } | 
|  |  | 
|  | // Verify that FileDescriptorWatcher::WatchReadable() can be called from a task | 
|  | // running in TaskTrackerPosix without a crash. | 
|  | TEST_F(TaskSchedulerTaskTrackerPosixTest, FileDescriptorWatcher) { | 
|  | int fds[2]; | 
|  | ASSERT_EQ(0, pipe(fds)); | 
|  | Task task(FROM_HERE, | 
|  | Bind(IgnoreResult(&FileDescriptorWatcher::WatchReadable), fds[0], | 
|  | DoNothing()), | 
|  | TaskTraits(), TimeDelta()); | 
|  | // FileDescriptorWatcher::WatchReadable needs a SequencedTaskRunnerHandle. | 
|  | task.sequenced_task_runner_ref = MakeRefCounted<NullTaskRunner>(); | 
|  |  | 
|  | EXPECT_TRUE(tracker_.WillPostTask(task)); | 
|  |  | 
|  | auto sequence = test::CreateSequenceWithTask(std::move(task)); | 
|  | EXPECT_EQ(sequence, tracker_.WillScheduleSequence(sequence, nullptr)); | 
|  | // Expect RunAndPopNextTask to return nullptr since |sequence| is empty after | 
|  | // popping a task from it. | 
|  | EXPECT_FALSE(tracker_.RunAndPopNextTask(sequence, nullptr)); | 
|  |  | 
|  | // Join the service thread to make sure that the read watch is registered and | 
|  | // unregistered before file descriptors are closed. | 
|  | service_thread_.Stop(); | 
|  |  | 
|  | EXPECT_EQ(0, IGNORE_EINTR(close(fds[0]))); | 
|  | EXPECT_EQ(0, IGNORE_EINTR(close(fds[1]))); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace base |