1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "perfetto/base/unix_task_runner.h" 18 19 #include "gtest/gtest.h" 20 #include "perfetto/base/build_config.h" 21 #include "perfetto/base/scoped_file.h" 22 23 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \ 24 !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD) 25 #include "perfetto/base/android_task_runner.h" 26 #endif 27 28 #include <thread> 29 30 namespace perfetto { 31 namespace base { 32 namespace { 33 34 template <typename T> 35 class TaskRunnerTest : public ::testing::Test { 36 public: 37 T task_runner; 38 }; 39 40 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \ 41 !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD) 42 using TaskRunnerTypes = ::testing::Types<AndroidTaskRunner, UnixTaskRunner>; 43 #else 44 using TaskRunnerTypes = ::testing::Types<UnixTaskRunner>; 45 #endif 46 TYPED_TEST_CASE(TaskRunnerTest, TaskRunnerTypes); 47 48 struct Pipe { 49 Pipe() { 50 int pipe_fds[2]; 51 PERFETTO_DCHECK(pipe(pipe_fds) == 0); 52 read_fd.reset(pipe_fds[0]); 53 write_fd.reset(pipe_fds[1]); 54 // Make the pipe initially readable. 55 Write(); 56 } 57 58 void Read() { 59 char b; 60 PERFETTO_DCHECK(read(read_fd.get(), &b, 1) == 1); 61 } 62 63 void Write() { 64 const char b = '?'; 65 PERFETTO_DCHECK(write(write_fd.get(), &b, 1) == 1); 66 } 67 68 ScopedFile read_fd; 69 ScopedFile write_fd; 70 }; 71 72 TYPED_TEST(TaskRunnerTest, PostImmediateTask) { 73 auto& task_runner = this->task_runner; 74 int counter = 0; 75 task_runner.PostTask([&counter] { counter = (counter << 4) | 1; }); 76 task_runner.PostTask([&counter] { counter = (counter << 4) | 2; }); 77 task_runner.PostTask([&counter] { counter = (counter << 4) | 3; }); 78 task_runner.PostTask([&counter] { counter = (counter << 4) | 4; }); 79 task_runner.PostTask([&task_runner] { task_runner.Quit(); }); 80 task_runner.Run(); 81 EXPECT_EQ(0x1234, counter); 82 } 83 84 TYPED_TEST(TaskRunnerTest, PostDelayedTask) { 85 auto& task_runner = this->task_runner; 86 int counter = 0; 87 task_runner.PostDelayedTask([&counter] { counter = (counter << 4) | 1; }, 5); 88 task_runner.PostDelayedTask([&counter] { counter = (counter << 4) | 2; }, 10); 89 task_runner.PostDelayedTask([&counter] { counter = (counter << 4) | 3; }, 15); 90 task_runner.PostDelayedTask([&counter] { counter = (counter << 4) | 4; }, 15); 91 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 20); 92 task_runner.Run(); 93 EXPECT_EQ(0x1234, counter); 94 } 95 96 TYPED_TEST(TaskRunnerTest, PostImmediateTaskFromTask) { 97 auto& task_runner = this->task_runner; 98 task_runner.PostTask([&task_runner] { 99 task_runner.PostTask([&task_runner] { task_runner.Quit(); }); 100 }); 101 task_runner.Run(); 102 } 103 104 TYPED_TEST(TaskRunnerTest, PostDelayedTaskFromTask) { 105 auto& task_runner = this->task_runner; 106 task_runner.PostTask([&task_runner] { 107 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10); 108 }); 109 task_runner.Run(); 110 } 111 112 TYPED_TEST(TaskRunnerTest, PostImmediateTaskFromOtherThread) { 113 auto& task_runner = this->task_runner; 114 ThreadChecker thread_checker; 115 int counter = 0; 116 std::thread thread([&task_runner, &counter, &thread_checker] { 117 task_runner.PostTask([&thread_checker] { 118 EXPECT_TRUE(thread_checker.CalledOnValidThread()); 119 }); 120 task_runner.PostTask([&counter] { counter = (counter << 4) | 1; }); 121 task_runner.PostTask([&counter] { counter = (counter << 4) | 2; }); 122 task_runner.PostTask([&counter] { counter = (counter << 4) | 3; }); 123 task_runner.PostTask([&counter] { counter = (counter << 4) | 4; }); 124 task_runner.PostTask([&task_runner] { task_runner.Quit(); }); 125 }); 126 task_runner.Run(); 127 thread.join(); 128 EXPECT_EQ(0x1234, counter); 129 } 130 131 TYPED_TEST(TaskRunnerTest, PostDelayedTaskFromOtherThread) { 132 auto& task_runner = this->task_runner; 133 std::thread thread([&task_runner] { 134 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10); 135 }); 136 task_runner.Run(); 137 thread.join(); 138 } 139 140 TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatch) { 141 auto& task_runner = this->task_runner; 142 Pipe pipe; 143 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(), 144 [&task_runner] { task_runner.Quit(); }); 145 task_runner.Run(); 146 } 147 148 TYPED_TEST(TaskRunnerTest, RemoveFileDescriptorWatch) { 149 auto& task_runner = this->task_runner; 150 Pipe pipe; 151 152 bool watch_ran = false; 153 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(), 154 [&watch_ran] { watch_ran = true; }); 155 task_runner.RemoveFileDescriptorWatch(pipe.read_fd.get()); 156 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10); 157 task_runner.Run(); 158 159 EXPECT_FALSE(watch_ran); 160 } 161 162 TYPED_TEST(TaskRunnerTest, RemoveFileDescriptorWatchFromTask) { 163 auto& task_runner = this->task_runner; 164 Pipe pipe; 165 166 bool watch_ran = false; 167 task_runner.PostTask([&task_runner, &pipe] { 168 task_runner.RemoveFileDescriptorWatch(pipe.read_fd.get()); 169 }); 170 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(), 171 [&watch_ran] { watch_ran = true; }); 172 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10); 173 task_runner.Run(); 174 175 EXPECT_FALSE(watch_ran); 176 } 177 178 TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatchFromAnotherWatch) { 179 auto& task_runner = this->task_runner; 180 Pipe pipe; 181 Pipe pipe2; 182 183 task_runner.AddFileDescriptorWatch( 184 pipe.read_fd.get(), [&task_runner, &pipe, &pipe2] { 185 pipe.Read(); 186 task_runner.AddFileDescriptorWatch( 187 pipe2.read_fd.get(), [&task_runner] { task_runner.Quit(); }); 188 }); 189 task_runner.Run(); 190 } 191 192 TYPED_TEST(TaskRunnerTest, RemoveFileDescriptorWatchFromAnotherWatch) { 193 auto& task_runner = this->task_runner; 194 Pipe pipe; 195 Pipe pipe2; 196 197 bool watch_ran = false; 198 task_runner.AddFileDescriptorWatch( 199 pipe.read_fd.get(), [&task_runner, &pipe, &pipe2] { 200 pipe.Read(); 201 task_runner.RemoveFileDescriptorWatch(pipe2.read_fd.get()); 202 }); 203 task_runner.AddFileDescriptorWatch(pipe2.read_fd.get(), 204 [&watch_ran] { watch_ran = true; }); 205 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10); 206 task_runner.Run(); 207 208 EXPECT_FALSE(watch_ran); 209 } 210 211 TYPED_TEST(TaskRunnerTest, ReplaceFileDescriptorWatchFromAnotherWatch) { 212 auto& task_runner = this->task_runner; 213 Pipe pipe; 214 Pipe pipe2; 215 216 bool watch_ran = false; 217 task_runner.AddFileDescriptorWatch( 218 pipe.read_fd.get(), [&task_runner, &pipe2] { 219 task_runner.RemoveFileDescriptorWatch(pipe2.read_fd.get()); 220 task_runner.AddFileDescriptorWatch( 221 pipe2.read_fd.get(), [&task_runner] { task_runner.Quit(); }); 222 }); 223 task_runner.AddFileDescriptorWatch(pipe2.read_fd.get(), 224 [&watch_ran] { watch_ran = true; }); 225 task_runner.Run(); 226 227 EXPECT_FALSE(watch_ran); 228 } 229 230 TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatchFromAnotherThread) { 231 auto& task_runner = this->task_runner; 232 Pipe pipe; 233 234 std::thread thread([&task_runner, &pipe] { 235 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(), 236 [&task_runner] { task_runner.Quit(); }); 237 }); 238 task_runner.Run(); 239 thread.join(); 240 } 241 242 TYPED_TEST(TaskRunnerTest, FileDescriptorWatchWithMultipleEvents) { 243 auto& task_runner = this->task_runner; 244 Pipe pipe; 245 246 int event_count = 0; 247 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(), 248 [&task_runner, &pipe, &event_count] { 249 if (++event_count == 3) { 250 task_runner.Quit(); 251 return; 252 } 253 pipe.Read(); 254 }); 255 task_runner.PostTask([&pipe] { pipe.Write(); }); 256 task_runner.PostTask([&pipe] { pipe.Write(); }); 257 task_runner.Run(); 258 } 259 260 TYPED_TEST(TaskRunnerTest, FileDescriptorClosedEvent) { 261 auto& task_runner = this->task_runner; 262 int pipe_fds[2]; 263 PERFETTO_DCHECK(pipe(pipe_fds) == 0); 264 ScopedFile read_fd(pipe_fds[0]); 265 ScopedFile write_fd(pipe_fds[1]); 266 267 write_fd.reset(); 268 task_runner.AddFileDescriptorWatch(read_fd.get(), 269 [&task_runner] { task_runner.Quit(); }); 270 task_runner.Run(); 271 } 272 273 TYPED_TEST(TaskRunnerTest, PostManyDelayedTasks) { 274 // Check that PostTask doesn't start failing if there are too many scheduled 275 // wake-ups. 276 auto& task_runner = this->task_runner; 277 for (int i = 0; i < 0x1000; i++) 278 task_runner.PostDelayedTask([] {}, 0); 279 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10); 280 task_runner.Run(); 281 } 282 283 TYPED_TEST(TaskRunnerTest, RunAgain) { 284 auto& task_runner = this->task_runner; 285 int counter = 0; 286 task_runner.PostTask([&task_runner, &counter] { 287 counter++; 288 task_runner.Quit(); 289 }); 290 task_runner.Run(); 291 task_runner.PostTask([&task_runner, &counter] { 292 counter++; 293 task_runner.Quit(); 294 }); 295 task_runner.Run(); 296 EXPECT_EQ(2, counter); 297 } 298 299 template <typename TaskRunner> 300 void RepeatingTask(TaskRunner* task_runner) { 301 task_runner->PostTask(std::bind(&RepeatingTask<TaskRunner>, task_runner)); 302 } 303 304 TYPED_TEST(TaskRunnerTest, FileDescriptorWatchesNotStarved) { 305 auto& task_runner = this->task_runner; 306 Pipe pipe; 307 task_runner.PostTask(std::bind(&RepeatingTask<TypeParam>, &task_runner)); 308 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(), 309 [&task_runner] { task_runner.Quit(); }); 310 task_runner.Run(); 311 } 312 313 template <typename TaskRunner> 314 void CountdownTask(TaskRunner* task_runner, int* counter) { 315 if (!--(*counter)) { 316 task_runner->Quit(); 317 return; 318 } 319 task_runner->PostTask( 320 std::bind(&CountdownTask<TaskRunner>, task_runner, counter)); 321 } 322 323 TYPED_TEST(TaskRunnerTest, NoDuplicateFileDescriptorWatchCallbacks) { 324 auto& task_runner = this->task_runner; 325 Pipe pipe; 326 bool watch_called = 0; 327 int counter = 10; 328 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(), 329 [&pipe, &watch_called] { 330 ASSERT_FALSE(watch_called); 331 pipe.Read(); 332 watch_called = true; 333 }); 334 task_runner.PostTask( 335 std::bind(&CountdownTask<TypeParam>, &task_runner, &counter)); 336 task_runner.Run(); 337 } 338 339 TYPED_TEST(TaskRunnerTest, ReplaceFileDescriptorWatchFromOtherThread) { 340 auto& task_runner = this->task_runner; 341 Pipe pipe; 342 343 // The two watch tasks here race each other. We don't particularly care which 344 // wins as long as one of them runs. 345 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(), 346 [&task_runner] { task_runner.Quit(); }); 347 348 std::thread thread([&task_runner, &pipe] { 349 task_runner.RemoveFileDescriptorWatch(pipe.read_fd.get()); 350 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(), 351 [&task_runner] { task_runner.Quit(); }); 352 }); 353 354 task_runner.Run(); 355 thread.join(); 356 } 357 358 TYPED_TEST(TaskRunnerTest, IsIdleForTesting) { 359 auto& task_runner = this->task_runner; 360 task_runner.PostTask( 361 [&task_runner] { EXPECT_FALSE(task_runner.IsIdleForTesting()); }); 362 task_runner.PostTask([&task_runner] { 363 EXPECT_TRUE(task_runner.IsIdleForTesting()); 364 task_runner.Quit(); 365 }); 366 task_runner.Run(); 367 } 368 369 } // namespace 370 } // namespace base 371 } // namespace perfetto 372