perfetto_task_runner_unittest.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/tracing/perfetto_task_runner.h"
  5. #include <memory>
  6. #include <utility>
  7. #include <vector>
  8. #include "base/files/scoped_file.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/memory/weak_ptr.h"
  11. #include "base/task/thread_pool.h"
  12. #include "base/test/bind.h"
  13. #include "base/test/task_environment.h"
  14. #include "base/threading/simple_thread.h"
  15. #include "build/build_config.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
  18. #include <sys/socket.h>
  19. #include <sys/types.h>
  20. #include "base/posix/eintr_wrapper.h"
  21. #endif
  22. namespace base {
  23. namespace tracing {
  24. namespace {
  25. class TaskDestination {
  26. public:
  27. TaskDestination(size_t number_of_sequences,
  28. size_t expected_tasks,
  29. base::OnceClosure on_complete)
  30. : expected_tasks_(expected_tasks),
  31. on_complete_(std::move(on_complete)),
  32. last_task_id_(number_of_sequences) {}
  33. size_t tasks_run() const { return tasks_run_; }
  34. void TestTask(int n, size_t sequence_number = 0) {
  35. EXPECT_LT(sequence_number, last_task_id_.size());
  36. EXPECT_GT(expected_tasks_, tasks_run_);
  37. EXPECT_GE(n, last_task_id_[sequence_number]);
  38. last_task_id_[sequence_number] = n;
  39. if (++tasks_run_ == expected_tasks_) {
  40. std::move(on_complete_).Run();
  41. }
  42. }
  43. base::WeakPtr<TaskDestination> GetWeakPtr() {
  44. return weak_ptr_factory_.GetWeakPtr();
  45. }
  46. private:
  47. const size_t expected_tasks_;
  48. base::OnceClosure on_complete_;
  49. std::vector<int> last_task_id_;
  50. size_t tasks_run_ = 0;
  51. base::WeakPtrFactory<TaskDestination> weak_ptr_factory_{this};
  52. };
  53. class PosterThread : public base::SimpleThread {
  54. public:
  55. PosterThread(PerfettoTaskRunner* task_runner,
  56. base::WeakPtr<TaskDestination> weak_ptr,
  57. int n,
  58. size_t sequence_number)
  59. : SimpleThread("TaskPostThread"),
  60. task_runner_(task_runner),
  61. weak_ptr_(weak_ptr),
  62. n_(n),
  63. sequence_number_(sequence_number) {}
  64. ~PosterThread() override {}
  65. // base::SimpleThread overrides.
  66. void BeforeStart() override {}
  67. void BeforeJoin() override {}
  68. void Run() override {
  69. for (int i = 0; i < n_; ++i) {
  70. auto weak_ptr = weak_ptr_;
  71. auto sequence_number = sequence_number_;
  72. task_runner_->PostTask([weak_ptr, i, sequence_number]() {
  73. weak_ptr->TestTask(i, sequence_number);
  74. });
  75. }
  76. }
  77. private:
  78. raw_ptr<PerfettoTaskRunner> task_runner_;
  79. base::WeakPtr<TaskDestination> weak_ptr_;
  80. const int n_;
  81. const size_t sequence_number_;
  82. };
  83. class PerfettoTaskRunnerTest : public testing::Test {
  84. public:
  85. void SetUp() override {
  86. sequenced_task_runner_ = CreateNewTaskrunner();
  87. task_runner_ = std::make_unique<PerfettoTaskRunner>(sequenced_task_runner_);
  88. }
  89. scoped_refptr<base::SequencedTaskRunner> CreateNewTaskrunner() {
  90. return base::ThreadPool::CreateSingleThreadTaskRunner(
  91. {base::MayBlock()}, base::SingleThreadTaskRunnerThreadMode::DEDICATED);
  92. }
  93. void SetTaskExpectations(base::OnceClosure on_complete,
  94. size_t expected_tasks,
  95. size_t number_of_sequences = 1) {
  96. task_destination_ = std::make_unique<TaskDestination>(
  97. number_of_sequences, expected_tasks, std::move(on_complete));
  98. }
  99. void TearDown() override {
  100. sequenced_task_runner_->DeleteSoon(FROM_HERE, std::move(task_runner_));
  101. }
  102. PerfettoTaskRunner* task_runner() { return task_runner_.get(); }
  103. TaskDestination* destination() { return task_destination_.get(); }
  104. base::test::TaskEnvironment& task_environment() { return task_environment_; }
  105. private:
  106. base::test::TaskEnvironment task_environment_;
  107. scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
  108. std::unique_ptr<PerfettoTaskRunner> task_runner_;
  109. std::unique_ptr<TaskDestination> task_destination_;
  110. };
  111. TEST_F(PerfettoTaskRunnerTest, SequentialTasks) {
  112. base::RunLoop wait_for_tasks;
  113. SetTaskExpectations(wait_for_tasks.QuitClosure(), 3);
  114. auto weak_ptr = destination()->GetWeakPtr();
  115. for (int i = 1; i <= 3; ++i) {
  116. task_runner()->PostTask([=]() mutable {
  117. auto* dest = weak_ptr.get();
  118. // The weak pointer must be reset before TestTask() is called, otherwise
  119. // there will be a race where the factory could be destructed on main
  120. // thread while still bound to the task runner sequence.
  121. weak_ptr.reset();
  122. dest->TestTask(i);
  123. });
  124. }
  125. wait_for_tasks.Run();
  126. }
  127. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
  128. // Tests file descriptor reuse that causes crashes.
  129. TEST_F(PerfettoTaskRunnerTest, FileDescriptorReuse) {
  130. int sockets[2];
  131. // Use sockets because we need a FD that supports epoll().
  132. ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sockets));
  133. base::ScopedFD fd(sockets[0]), write_fd(sockets[1]);
  134. ASSERT_TRUE(fd.is_valid());
  135. constexpr int data_value = 0x12ab34cd;
  136. bool run_callback_1 = false, run_callback_2 = false;
  137. int data = data_value;
  138. constexpr ssize_t data_size = static_cast<ssize_t>(sizeof(data));
  139. // Trigger the file descriptor watcher callback.
  140. ASSERT_EQ(data_size, HANDLE_EINTR(write(write_fd.get(), &data, data_size)));
  141. data = 0;
  142. base::RunLoop run_loop;
  143. task_runner()->GetOrCreateTaskRunner()->PostTask(
  144. FROM_HERE, base::BindLambdaForTesting([&]() {
  145. // The 1st add operation posts a task.
  146. task_runner()->AddFileDescriptorWatch(fd.get(), [&]() {
  147. run_callback_1 = true;
  148. ASSERT_EQ(data_size, HANDLE_EINTR(read(fd.get(), &data, data_size)));
  149. run_loop.Quit();
  150. });
  151. // Remove so the 2nd add operation can succeed.
  152. task_runner()->RemoveFileDescriptorWatch(fd.get());
  153. // Simulate FD reuse. The 2nd add operation also posts a task.
  154. task_runner()->AddFileDescriptorWatch(fd.get(), [&]() {
  155. run_callback_2 = true;
  156. ASSERT_EQ(data_size, HANDLE_EINTR(read(fd.get(), &data, data_size)));
  157. run_loop.Quit();
  158. });
  159. }));
  160. // Make all posted tasks run.
  161. run_loop.Run();
  162. ASSERT_FALSE(run_callback_1);
  163. ASSERT_TRUE(run_callback_2);
  164. ASSERT_EQ(data, data_value);
  165. task_runner()->GetOrCreateTaskRunner()->PostTask(
  166. FROM_HERE, base::BindLambdaForTesting([&]() {
  167. // Cleanup the FD watcher.
  168. task_runner()->RemoveFileDescriptorWatch(fd.get());
  169. }));
  170. task_environment().RunUntilIdle();
  171. }
  172. #endif
  173. } // namespace
  174. } // namespace tracing
  175. } // namespace base