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