• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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