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 // TaskRunner implementation: 73 void PostTask(std::function<void()>) override; 74 void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override; 75 void AddFileDescriptorWatch(PlatformHandle, std::function<void()>) override; 76 void RemoveFileDescriptorWatch(PlatformHandle) override; 77 bool RunsTasksOnCurrentThread() const override; 78 79 // Returns true if the task runner is quitting, or has quit and hasn't been 80 // restarted since. Exposed primarily for ThreadTaskRunner, not necessary for 81 // normal use of this class. 82 bool QuitCalled(); 83 84 private: 85 void WakeUp(); 86 void UpdateWatchTasksLocked(); 87 int GetDelayMsToNextTaskLocked() const; 88 void RunImmediateAndDelayedTask(); 89 void PostFileDescriptorWatches(uint64_t windows_wait_result); 90 void RunFileDescriptorWatch(PlatformHandle); 91 92 ThreadChecker thread_checker_; 93 PlatformThreadId created_thread_id_ = GetThreadId(); 94 95 EventFd event_; 96 97 // The array of fds/handles passed to poll(2) / WaitForMultipleObjects(). 98 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) 99 std::vector<PlatformHandle> poll_fds_; 100 #else 101 std::vector<struct pollfd> poll_fds_; 102 #endif 103 104 // --- Begin lock-protected members --- 105 106 std::mutex lock_; 107 108 std::deque<std::function<void()>> immediate_tasks_; 109 std::multimap<TimeMillis, std::function<void()>> delayed_tasks_; 110 bool quit_ = false; 111 112 struct WatchTask { 113 std::function<void()> callback; 114 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) 115 // On UNIX systems we make the FD number negative in |poll_fds_| to avoid 116 // polling it again until the queued task runs. On Windows we can't do that. 117 // Instead we keep track of its state here. 118 bool pending = false; 119 #else 120 size_t poll_fd_index; // Index into |poll_fds_|. 121 #endif 122 }; 123 124 std::map<PlatformHandle, WatchTask> watch_tasks_; 125 bool watch_tasks_changed_ = false; 126 127 // --- End lock-protected members --- 128 }; 129 130 } // namespace base 131 } // namespace perfetto 132 133 #endif // INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_ 134