blob: 22c3a709deb937aa6622c66ff5b8dc8bd3090f8c [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
28#include <android-base/stringprintf.h>
29#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
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080033#include "SchedulerUtils.h"
Kevin DuBoiscc27b502019-11-13 09:40:07 -080034#include "Timer.h"
35
36namespace android::scheduler {
Ady Abraham75398722020-04-07 14:08:45 -070037using base::StringAppendF;
Kevin DuBoiscc27b502019-11-13 09:40:07 -080038
39static constexpr size_t kReadPipe = 0;
40static constexpr size_t kWritePipe = 1;
41
Ady Abraham75398722020-04-07 14:08:45 -070042Timer::Timer() {
43 reset();
44 mDispatchThread = std::thread([this]() { threadMain(); });
Kevin DuBoiscc27b502019-11-13 09:40:07 -080045}
46
47Timer::~Timer() {
48 endDispatch();
49 mDispatchThread.join();
Ady Abraham75398722020-04-07 14:08:45 -070050 cleanup();
51}
Kevin DuBoiscc27b502019-11-13 09:40:07 -080052
Ady Abraham75398722020-04-07 14:08:45 -070053void Timer::reset() {
54 cleanup();
55 mTimerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
56 mEpollFd = epoll_create1(EPOLL_CLOEXEC);
57 if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
58 ALOGE("could not create TimerDispatch mPipes");
59 return;
60 };
61 setDebugState(DebugState::Reset);
62}
63
64void Timer::cleanup() {
65 if (mTimerFd != -1) {
66 close(mTimerFd);
67 mTimerFd = -1;
68 }
69
70 if (mEpollFd != -1) {
71 close(mEpollFd);
72 mEpollFd = -1;
73 }
74
75 if (mPipes[kReadPipe] != -1) {
76 close(mPipes[kReadPipe]);
77 mPipes[kReadPipe] = -1;
78 }
79
80 if (mPipes[kWritePipe] != -1) {
81 close(mPipes[kWritePipe]);
82 mPipes[kWritePipe] = -1;
83 }
Kevin DuBoiscc27b502019-11-13 09:40:07 -080084}
85
86void Timer::endDispatch() {
87 static constexpr unsigned char end = 'e';
88 write(mPipes[kWritePipe], &end, sizeof(end));
89}
90
91nsecs_t Timer::now() const {
92 return systemTime(SYSTEM_TIME_MONOTONIC);
93}
94
Ady Abrahamb491c902020-08-15 15:47:56 -070095void Timer::alarmAt(std::function<void()> const& cb, nsecs_t time) {
Ady Abraham8cb21882020-08-26 18:22:05 -070096 std::lock_guard lock(mMutex);
Kevin DuBoiscc27b502019-11-13 09:40:07 -080097 using namespace std::literals;
98 static constexpr int ns_per_s =
99 std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
100
101 mCallback = cb;
102
103 struct itimerspec old_timer;
104 struct itimerspec new_timer {
105 .it_interval = {.tv_sec = 0, .tv_nsec = 0},
Ady Abrahamb491c902020-08-15 15:47:56 -0700106 .it_value = {.tv_sec = static_cast<long>(time / ns_per_s),
107 .tv_nsec = static_cast<long>(time % ns_per_s)},
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800108 };
109
Ady Abrahamb491c902020-08-15 15:47:56 -0700110 if (timerfd_settime(mTimerFd, TFD_TIMER_ABSTIME, &new_timer, &old_timer)) {
Kevin DuBois127a2d92019-12-04 13:52:52 -0800111 ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800112 }
113}
114
115void Timer::alarmCancel() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700116 std::lock_guard lock(mMutex);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800117
118 struct itimerspec old_timer;
119 struct itimerspec new_timer {
120 .it_interval = {.tv_sec = 0, .tv_nsec = 0},
121 .it_value = {
122 .tv_sec = 0,
123 .tv_nsec = 0,
124 },
125 };
126
127 if (timerfd_settime(mTimerFd, 0, &new_timer, &old_timer)) {
128 ALOGW("Failed to disarm timerfd");
129 }
130}
131
Ady Abraham75398722020-04-07 14:08:45 -0700132void Timer::threadMain() {
133 while (dispatch()) {
134 reset();
135 }
136}
137
138bool Timer::dispatch() {
139 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800140 struct sched_param param = {0};
141 param.sched_priority = 2;
142 if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
143 ALOGW("Failed to set SCHED_FIFO on dispatch thread");
144 }
145
146 if (pthread_setname_np(pthread_self(), "TimerDispatch")) {
147 ALOGW("Failed to set thread name on dispatch thread");
148 }
149
150 enum DispatchType : uint32_t { TIMER, TERMINATE, MAX_DISPATCH_TYPE };
151 epoll_event timerEvent;
152 timerEvent.events = EPOLLIN;
153 timerEvent.data.u32 = DispatchType::TIMER;
154 if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mTimerFd, &timerEvent) == -1) {
155 ALOGE("Error adding timer fd to epoll dispatch loop");
Ady Abraham75398722020-04-07 14:08:45 -0700156 return true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800157 }
158
159 epoll_event terminateEvent;
160 terminateEvent.events = EPOLLIN;
161 terminateEvent.data.u32 = DispatchType::TERMINATE;
162 if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mPipes[kReadPipe], &terminateEvent) == -1) {
163 ALOGE("Error adding control fd to dispatch loop");
Ady Abraham75398722020-04-07 14:08:45 -0700164 return true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800165 }
166
167 uint64_t iteration = 0;
168 char const traceNamePrefix[] = "TimerIteration #";
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800169 static constexpr size_t maxlen = arrayLen(traceNamePrefix) + max64print;
170 std::array<char, maxlen> str_buffer;
Ady Abraham75398722020-04-07 14:08:45 -0700171
172 while (true) {
173 setDebugState(DebugState::Waiting);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800174 epoll_event events[DispatchType::MAX_DISPATCH_TYPE];
175 int nfds = epoll_wait(mEpollFd, events, DispatchType::MAX_DISPATCH_TYPE, -1);
176
Ady Abraham75398722020-04-07 14:08:45 -0700177 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800178 if (ATRACE_ENABLED()) {
179 snprintf(str_buffer.data(), str_buffer.size(), "%s%" PRIu64, traceNamePrefix,
180 iteration++);
181 ATRACE_NAME(str_buffer.data());
182 }
183
184 if (nfds == -1) {
185 if (errno != EINTR) {
Ady Abraham75398722020-04-07 14:08:45 -0700186 ALOGE("Error waiting on epoll: %s", strerror(errno));
187 return true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800188 }
189 }
190
191 for (auto i = 0; i < nfds; i++) {
192 if (events[i].data.u32 == DispatchType::TIMER) {
193 static uint64_t mIgnored = 0;
Ady Abraham75398722020-04-07 14:08:45 -0700194 setDebugState(DebugState::Reading);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800195 read(mTimerFd, &mIgnored, sizeof(mIgnored));
Ady Abraham75398722020-04-07 14:08:45 -0700196 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800197 std::function<void()> cb;
198 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700199 std::lock_guard lock(mMutex);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800200 cb = mCallback;
201 }
202 if (cb) {
Ady Abraham75398722020-04-07 14:08:45 -0700203 setDebugState(DebugState::InCallback);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800204 cb();
Ady Abraham75398722020-04-07 14:08:45 -0700205 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800206 }
207 }
208 if (events[i].data.u32 == DispatchType::TERMINATE) {
Ady Abraham75398722020-04-07 14:08:45 -0700209 ALOGE("Terminated");
210 setDebugState(DebugState::Running);
211 return false;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800212 }
213 }
214 }
215}
216
Ady Abraham75398722020-04-07 14:08:45 -0700217void Timer::setDebugState(DebugState state) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700218 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700219 mDebugState = state;
220}
221
Ady Abraham75398722020-04-07 14:08:45 -0700222void Timer::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700223 std::lock_guard lock(mMutex);
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -0700224 StringAppendF(&result, "\t\tDebugState: %s\n", ftl::enum_string(mDebugState).c_str());
Ady Abraham75398722020-04-07 14:08:45 -0700225}
226
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800227} // namespace android::scheduler