• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_
18 #define INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_
19 
20 #include "perfetto/base/build_config.h"
21 #include "perfetto/base/task_runner.h"
22 #include "perfetto/base/thread_annotations.h"
23 #include "perfetto/base/thread_utils.h"
24 #include "perfetto/base/time.h"
25 #include "perfetto/ext/base/event_fd.h"
26 #include "perfetto/ext/base/scoped_file.h"
27 #include "perfetto/ext/base/thread_checker.h"
28 
29 #include <chrono>
30 #include <deque>
31 #include <map>
32 #include <mutex>
33 #include <vector>
34 
35 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
36 #include <poll.h>
37 #endif
38 
39 namespace perfetto {
40 namespace base {
41 
42 // Runs a task runner on the current thread.
43 //
44 // Implementation note: we currently assume (and enforce in debug builds) that
45 // Run() is called from the thread that constructed the UnixTaskRunner. This is
46 // not strictly necessary, and we could instead track the thread that invokes
47 // Run(). However, a related property that *might* be important to enforce is
48 // that the destructor runs on the task-running thread. Otherwise, if there are
49 // still-pending tasks at the time of destruction, we would destroy those
50 // outside of the task thread (which might be unexpected to the caller). On the
51 // other hand, the std::function task interface discourages use of any
52 // resource-owning tasks (as the callable needs to be copyable), so this might
53 // not be important in practice.
54 //
55 // TODO(rsavitski): consider adding a thread-check in the destructor, after
56 // auditing existing usages.
57 // TODO(primiano): rename this to TaskRunnerImpl. The "Unix" part is misleading
58 // now as it supports also Windows.
59 class UnixTaskRunner : public TaskRunner {
60  public:
61   UnixTaskRunner();
62   ~UnixTaskRunner() override;
63 
64   // Start executing tasks. Doesn't return until Quit() is called. Run() may be
65   // called multiple times on the same task runner.
66   void Run();
67   void Quit();
68 
69   // Checks whether there are any pending immediate tasks to run. Note that
70   // delayed tasks don't count even if they are due to run.
71   bool IsIdleForTesting();
72 
73   // Pretends (for the purposes of running delayed tasks) that time advanced by
74   // `ms`.
75   void AdvanceTimeForTesting(uint32_t ms);
76 
77   // TaskRunner implementation:
78   void PostTask(std::function<void()>) override;
79   void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override;
80   void AddFileDescriptorWatch(PlatformHandle, std::function<void()>) override;
81   void RemoveFileDescriptorWatch(PlatformHandle) override;
82   bool RunsTasksOnCurrentThread() const override;
83 
84   // Returns true if the task runner is quitting, or has quit and hasn't been
85   // restarted since. Exposed primarily for ThreadTaskRunner, not necessary for
86   // normal use of this class.
87   bool QuitCalled();
88 
89  private:
90   void WakeUp();
91   void UpdateWatchTasksLocked() PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(lock_);
92   int GetDelayMsToNextTaskLocked() const
93       PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(lock_);
94   void RunImmediateAndDelayedTask();
95   void PostFileDescriptorWatches(uint64_t windows_wait_result);
96   void RunFileDescriptorWatch(PlatformHandle);
97 
98   ThreadChecker thread_checker_;
99   std::atomic<PlatformThreadId> created_thread_id_ = GetThreadId();
100 
101   EventFd event_;
102 
103 // The array of fds/handles passed to poll(2) / WaitForMultipleObjects().
104 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
105   std::vector<PlatformHandle> poll_fds_;
106 #else
107   std::vector<struct pollfd> poll_fds_;
108 #endif
109 
110   std::mutex lock_;
111 
112   std::deque<std::function<void()>> immediate_tasks_ PERFETTO_GUARDED_BY(lock_);
113   std::multimap<TimeMillis, std::function<void()>> delayed_tasks_
114       PERFETTO_GUARDED_BY(lock_);
115   bool quit_ PERFETTO_GUARDED_BY(lock_) = false;
116   TimeMillis advanced_time_for_testing_ PERFETTO_GUARDED_BY(lock_) =
117       TimeMillis(0);
118 
119   struct WatchTask {
120     std::function<void()> callback;
121 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
122     // On UNIX systems we make the FD number negative in |poll_fds_| to avoid
123     // polling it again until the queued task runs. On Windows we can't do that.
124     // Instead we keep track of its state here.
125     bool pending = false;
126 #else
127     size_t poll_fd_index;  // Index into |poll_fds_|.
128 #endif
129   };
130 
131   std::map<PlatformHandle, WatchTask> watch_tasks_ PERFETTO_GUARDED_BY(lock_);
132   bool watch_tasks_changed_ PERFETTO_GUARDED_BY(lock_) = false;
133 };
134 
135 }  // namespace base
136 }  // namespace perfetto
137 
138 #endif  // INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_
139