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