blob: 38e277cf625e225f005c2996258b262f36bcaacd [file] [log] [blame]
Kevin DuBoiscc27b502019-11-13 09:40:07 -08001/*
2 * Copyright 2019 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#undef LOG_TAG
18#define LOG_TAG "SchedulerTimer"
19#define ATRACE_TAG ATRACE_TAG_GRAPHICS
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070020
21#include <chrono>
22#include <cstdint>
23
Kevin DuBoiscc27b502019-11-13 09:40:07 -080024#include <sys/epoll.h>
25#include <sys/timerfd.h>
26#include <sys/unistd.h>
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070027
Dominik Laskowski62eff352021-12-06 09:59:41 -080028#include <ftl/concat.h>
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070029#include <ftl/enum.h>
30#include <log/log.h>
Kevin DuBoiscc27b502019-11-13 09:40:07 -080031#include <utils/Trace.h>
Kevin DuBoiscc27b502019-11-13 09:40:07 -080032
33#include "Timer.h"
34
35namespace android::scheduler {
36
37static constexpr size_t kReadPipe = 0;
38static constexpr size_t kWritePipe = 1;
39
Ady Abraham75398722020-04-07 14:08:45 -070040Timer::Timer() {
41 reset();
42 mDispatchThread = std::thread([this]() { threadMain(); });
Kevin DuBoiscc27b502019-11-13 09:40:07 -080043}
44
45Timer::~Timer() {
46 endDispatch();
47 mDispatchThread.join();
Ady Abraham75398722020-04-07 14:08:45 -070048 cleanup();
49}
Kevin DuBoiscc27b502019-11-13 09:40:07 -080050
Ady Abraham75398722020-04-07 14:08:45 -070051void Timer::reset() {
Ady Abraham3a3815a2021-12-23 14:32:07 -080052 std::function<void()> cb;
53 {
54 std::lock_guard lock(mMutex);
55 if (mExpectingCallback && mCallback) {
56 cb = mCallback;
57 }
58
59 cleanup();
60 mTimerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
61 mEpollFd = epoll_create1(EPOLL_CLOEXEC);
62 if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
63 ALOGE("could not create TimerDispatch mPipes");
64 }
65 }
66 if (cb) {
67 setDebugState(DebugState::InCallback);
68 cb();
69 setDebugState(DebugState::Running);
70 }
Ady Abraham75398722020-04-07 14:08:45 -070071 setDebugState(DebugState::Reset);
72}
73
74void Timer::cleanup() {
75 if (mTimerFd != -1) {
76 close(mTimerFd);
77 mTimerFd = -1;
78 }
79
80 if (mEpollFd != -1) {
81 close(mEpollFd);
82 mEpollFd = -1;
83 }
84
85 if (mPipes[kReadPipe] != -1) {
86 close(mPipes[kReadPipe]);
87 mPipes[kReadPipe] = -1;
88 }
89
90 if (mPipes[kWritePipe] != -1) {
91 close(mPipes[kWritePipe]);
92 mPipes[kWritePipe] = -1;
93 }
Ady Abraham3a3815a2021-12-23 14:32:07 -080094 mExpectingCallback = false;
95 mCallback = {};
Kevin DuBoiscc27b502019-11-13 09:40:07 -080096}
97
98void Timer::endDispatch() {
99 static constexpr unsigned char end = 'e';
100 write(mPipes[kWritePipe], &end, sizeof(end));
101}
102
103nsecs_t Timer::now() const {
104 return systemTime(SYSTEM_TIME_MONOTONIC);
105}
106
Ady Abrahamb491c902020-08-15 15:47:56 -0700107void Timer::alarmAt(std::function<void()> const& cb, nsecs_t time) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700108 std::lock_guard lock(mMutex);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800109 using namespace std::literals;
110 static constexpr int ns_per_s =
111 std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
112
113 mCallback = cb;
Ady Abraham3a3815a2021-12-23 14:32:07 -0800114 mExpectingCallback = true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800115
116 struct itimerspec old_timer;
117 struct itimerspec new_timer {
118 .it_interval = {.tv_sec = 0, .tv_nsec = 0},
Ady Abrahamb491c902020-08-15 15:47:56 -0700119 .it_value = {.tv_sec = static_cast<long>(time / ns_per_s),
120 .tv_nsec = static_cast<long>(time % ns_per_s)},
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800121 };
122
Ady Abrahamb491c902020-08-15 15:47:56 -0700123 if (timerfd_settime(mTimerFd, TFD_TIMER_ABSTIME, &new_timer, &old_timer)) {
Kevin DuBois127a2d92019-12-04 13:52:52 -0800124 ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800125 }
126}
127
128void Timer::alarmCancel() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700129 std::lock_guard lock(mMutex);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800130
131 struct itimerspec old_timer;
132 struct itimerspec new_timer {
133 .it_interval = {.tv_sec = 0, .tv_nsec = 0},
134 .it_value = {
135 .tv_sec = 0,
136 .tv_nsec = 0,
137 },
138 };
139
140 if (timerfd_settime(mTimerFd, 0, &new_timer, &old_timer)) {
141 ALOGW("Failed to disarm timerfd");
142 }
143}
144
Ady Abraham75398722020-04-07 14:08:45 -0700145void Timer::threadMain() {
146 while (dispatch()) {
147 reset();
148 }
149}
150
151bool Timer::dispatch() {
152 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800153 struct sched_param param = {0};
154 param.sched_priority = 2;
155 if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
156 ALOGW("Failed to set SCHED_FIFO on dispatch thread");
157 }
158
159 if (pthread_setname_np(pthread_self(), "TimerDispatch")) {
160 ALOGW("Failed to set thread name on dispatch thread");
161 }
162
163 enum DispatchType : uint32_t { TIMER, TERMINATE, MAX_DISPATCH_TYPE };
164 epoll_event timerEvent;
165 timerEvent.events = EPOLLIN;
166 timerEvent.data.u32 = DispatchType::TIMER;
167 if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mTimerFd, &timerEvent) == -1) {
168 ALOGE("Error adding timer fd to epoll dispatch loop");
Ady Abraham75398722020-04-07 14:08:45 -0700169 return true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800170 }
171
172 epoll_event terminateEvent;
173 terminateEvent.events = EPOLLIN;
174 terminateEvent.data.u32 = DispatchType::TERMINATE;
175 if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mPipes[kReadPipe], &terminateEvent) == -1) {
176 ALOGE("Error adding control fd to dispatch loop");
Ady Abraham75398722020-04-07 14:08:45 -0700177 return true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800178 }
179
180 uint64_t iteration = 0;
Ady Abraham75398722020-04-07 14:08:45 -0700181
182 while (true) {
183 setDebugState(DebugState::Waiting);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800184 epoll_event events[DispatchType::MAX_DISPATCH_TYPE];
185 int nfds = epoll_wait(mEpollFd, events, DispatchType::MAX_DISPATCH_TYPE, -1);
186
Ady Abraham75398722020-04-07 14:08:45 -0700187 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800188 if (ATRACE_ENABLED()) {
Dominik Laskowski62eff352021-12-06 09:59:41 -0800189 ftl::Concat trace("TimerIteration #", iteration++);
190 ATRACE_NAME(trace.c_str());
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800191 }
192
193 if (nfds == -1) {
194 if (errno != EINTR) {
Ady Abraham75398722020-04-07 14:08:45 -0700195 ALOGE("Error waiting on epoll: %s", strerror(errno));
196 return true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800197 }
198 }
199
200 for (auto i = 0; i < nfds; i++) {
201 if (events[i].data.u32 == DispatchType::TIMER) {
202 static uint64_t mIgnored = 0;
Ady Abraham75398722020-04-07 14:08:45 -0700203 setDebugState(DebugState::Reading);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800204 read(mTimerFd, &mIgnored, sizeof(mIgnored));
Ady Abraham75398722020-04-07 14:08:45 -0700205 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800206 std::function<void()> cb;
207 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700208 std::lock_guard lock(mMutex);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800209 cb = mCallback;
Ady Abraham3a3815a2021-12-23 14:32:07 -0800210 mExpectingCallback = false;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800211 }
212 if (cb) {
Ady Abraham75398722020-04-07 14:08:45 -0700213 setDebugState(DebugState::InCallback);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800214 cb();
Ady Abraham75398722020-04-07 14:08:45 -0700215 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800216 }
217 }
218 if (events[i].data.u32 == DispatchType::TERMINATE) {
Ady Abraham75398722020-04-07 14:08:45 -0700219 ALOGE("Terminated");
220 setDebugState(DebugState::Running);
221 return false;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800222 }
223 }
224 }
225}
226
Ady Abraham75398722020-04-07 14:08:45 -0700227void Timer::setDebugState(DebugState state) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700228 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700229 mDebugState = state;
230}
231
Ady Abraham75398722020-04-07 14:08:45 -0700232void Timer::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700233 std::lock_guard lock(mMutex);
Dominik Laskowski62eff352021-12-06 09:59:41 -0800234 result.append("\t\tDebugState: ");
235 result.append(ftl::enum_string(mDebugState));
236 result.push_back('\n');
Ady Abraham75398722020-04-07 14:08:45 -0700237}
238
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800239} // namespace android::scheduler