1 /* 2 * Copyright (C) 2021 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 #ifndef INCLUDE_PERFETTO_EXT_BASE_PERIODIC_TASK_H_ 18 #define INCLUDE_PERFETTO_EXT_BASE_PERIODIC_TASK_H_ 19 20 #include <functional> 21 22 #include "perfetto/ext/base/scoped_file.h" 23 #include "perfetto/ext/base/thread_checker.h" 24 #include "perfetto/ext/base/weak_ptr.h" 25 26 namespace perfetto { 27 namespace base { 28 29 class TaskRunner; 30 31 // A periodic task utility class. It wraps the logic necessary to do periodic 32 // tasks using a TaskRunner, taking care of subtleties like ensuring that 33 // outstanding tasks are cancelled after reset/dtor. 34 // Tasks are aligned on wall time (unless they are |one_shot|). This is to 35 // ensure that when using multiple periodic tasks, they happen at the same time, 36 // minimizing context switches. 37 // On Linux/Android it also supports suspend-aware mode (via timerfd). On other 38 // operating systems it falls back to PostDelayedTask, which is not 39 // suspend-aware. 40 // TODO(primiano): this should probably become a periodic timer scheduler, so we 41 // can use one FD for everything rather than one FD per task. For now we take 42 // the hit of a FD-per-task to keep this low-risk. 43 // TODO(primiano): consider renaming this class to TimerTask. When |one_shot| 44 // is set, the "Periodic" part of the class name becomes a lie. 45 class PeriodicTask { 46 public: 47 explicit PeriodicTask(base::TaskRunner*); 48 ~PeriodicTask(); // Calls Reset(). 49 50 struct Args { 51 uint32_t period_ms = 0; 52 std::function<void()> task = nullptr; 53 bool start_first_task_immediately = false; 54 bool use_suspend_aware_timer = false; 55 bool one_shot = false; 56 }; 57 58 void Start(Args); 59 60 // Safe to be called multiple times, even without calling Start(): 61 void Reset(); 62 63 // No copy or move. WeakPtr-wrapped pointers to |this| are posted on the 64 // task runner, this class is not easily movable. 65 PeriodicTask(const PeriodicTask&) = delete; 66 PeriodicTask& operator=(const PeriodicTask&) = delete; 67 PeriodicTask(PeriodicTask&&) = delete; 68 PeriodicTask& operator=(PeriodicTask&&) = delete; 69 timer_fd_for_testing()70 base::PlatformHandle timer_fd_for_testing() { return *timer_fd_; } 71 72 private: 73 static void RunTaskAndPostNext(base::WeakPtr<PeriodicTask>, 74 uint32_t generation); 75 void PostNextTask(); 76 void ResetTimerFd(); 77 78 base::TaskRunner* const task_runner_; 79 Args args_; 80 uint32_t generation_ = 0; 81 base::ScopedPlatformHandle timer_fd_; 82 83 PERFETTO_THREAD_CHECKER(thread_checker_) 84 base::WeakPtrFactory<PeriodicTask> weak_ptr_factory_; // Keep last. 85 }; 86 87 } // namespace base 88 } // namespace perfetto 89 90 #endif // INCLUDE_PERFETTO_EXT_BASE_PERIODIC_TASK_H_ 91