blob: eeb9c60d156e36ede9c40383203ddc48e722c75a [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"
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070019
20#include <chrono>
21#include <cstdint>
22
Kevin DuBoiscc27b502019-11-13 09:40:07 -080023#include <sys/epoll.h>
24#include <sys/timerfd.h>
25#include <sys/unistd.h>
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070026
Dominik Laskowski62eff352021-12-06 09:59:41 -080027#include <ftl/concat.h>
Dominik Laskowskif5d0ea52021-09-26 17:27:01 -070028#include <ftl/enum.h>
29#include <log/log.h>
Kevin DuBoiscc27b502019-11-13 09:40:07 -080030#include <utils/Trace.h>
Kevin DuBoiscc27b502019-11-13 09:40:07 -080031
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080032#include <scheduler/Timer.h>
Kevin DuBoiscc27b502019-11-13 09:40:07 -080033
34namespace android::scheduler {
35
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080036constexpr size_t kReadPipe = 0;
37constexpr size_t kWritePipe = 1;
38
39Clock::~Clock() = default;
40TimeKeeper::~TimeKeeper() = default;
Kevin DuBoiscc27b502019-11-13 09:40:07 -080041
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() {
Ady Abraham3a3815a2021-12-23 14:32:07 -080054 std::function<void()> cb;
55 {
56 std::lock_guard lock(mMutex);
57 if (mExpectingCallback && mCallback) {
58 cb = mCallback;
59 }
60
61 cleanup();
62 mTimerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
63 mEpollFd = epoll_create1(EPOLL_CLOEXEC);
64 if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
65 ALOGE("could not create TimerDispatch mPipes");
66 }
67 }
68 if (cb) {
69 setDebugState(DebugState::InCallback);
70 cb();
71 setDebugState(DebugState::Running);
72 }
Ady Abraham75398722020-04-07 14:08:45 -070073 setDebugState(DebugState::Reset);
74}
75
76void Timer::cleanup() {
77 if (mTimerFd != -1) {
78 close(mTimerFd);
79 mTimerFd = -1;
80 }
81
82 if (mEpollFd != -1) {
83 close(mEpollFd);
84 mEpollFd = -1;
85 }
86
87 if (mPipes[kReadPipe] != -1) {
88 close(mPipes[kReadPipe]);
89 mPipes[kReadPipe] = -1;
90 }
91
92 if (mPipes[kWritePipe] != -1) {
93 close(mPipes[kWritePipe]);
94 mPipes[kWritePipe] = -1;
95 }
Alec Mouriaa20c582023-10-11 19:44:54 +000096
97 setCallback({});
Kevin DuBoiscc27b502019-11-13 09:40:07 -080098}
99
100void Timer::endDispatch() {
101 static constexpr unsigned char end = 'e';
102 write(mPipes[kWritePipe], &end, sizeof(end));
103}
104
105nsecs_t Timer::now() const {
106 return systemTime(SYSTEM_TIME_MONOTONIC);
107}
108
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800109void Timer::alarmAt(std::function<void()> callback, nsecs_t time) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700110 std::lock_guard lock(mMutex);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800111 using namespace std::literals;
112 static constexpr int ns_per_s =
113 std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
114
Alec Mouriaa20c582023-10-11 19:44:54 +0000115 setCallback(std::move(callback));
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800116
117 struct itimerspec old_timer;
118 struct itimerspec new_timer {
119 .it_interval = {.tv_sec = 0, .tv_nsec = 0},
Ady Abrahamb491c902020-08-15 15:47:56 -0700120 .it_value = {.tv_sec = static_cast<long>(time / ns_per_s),
121 .tv_nsec = static_cast<long>(time % ns_per_s)},
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800122 };
123
Ady Abrahamb491c902020-08-15 15:47:56 -0700124 if (timerfd_settime(mTimerFd, TFD_TIMER_ABSTIME, &new_timer, &old_timer)) {
Kevin DuBois127a2d92019-12-04 13:52:52 -0800125 ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800126 }
127}
128
129void Timer::alarmCancel() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700130 std::lock_guard lock(mMutex);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800131
132 struct itimerspec old_timer;
133 struct itimerspec new_timer {
134 .it_interval = {.tv_sec = 0, .tv_nsec = 0},
135 .it_value = {
136 .tv_sec = 0,
137 .tv_nsec = 0,
138 },
139 };
140
141 if (timerfd_settime(mTimerFd, 0, &new_timer, &old_timer)) {
142 ALOGW("Failed to disarm timerfd");
143 }
Alec Mouriaa20c582023-10-11 19:44:54 +0000144
145 setCallback({});
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800146}
147
Ady Abraham75398722020-04-07 14:08:45 -0700148void Timer::threadMain() {
149 while (dispatch()) {
150 reset();
151 }
152}
153
154bool Timer::dispatch() {
155 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800156 struct sched_param param = {0};
157 param.sched_priority = 2;
158 if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
159 ALOGW("Failed to set SCHED_FIFO on dispatch thread");
160 }
161
Yifei Zhang133684c2024-02-06 14:49:04 -0800162 if (pthread_setname_np(pthread_self(), "TimerDispatch") != 0) {
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800163 ALOGW("Failed to set thread name on dispatch thread");
164 }
165
166 enum DispatchType : uint32_t { TIMER, TERMINATE, MAX_DISPATCH_TYPE };
167 epoll_event timerEvent;
168 timerEvent.events = EPOLLIN;
169 timerEvent.data.u32 = DispatchType::TIMER;
170 if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mTimerFd, &timerEvent) == -1) {
171 ALOGE("Error adding timer fd to epoll dispatch loop");
Ady Abraham75398722020-04-07 14:08:45 -0700172 return true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800173 }
174
175 epoll_event terminateEvent;
176 terminateEvent.events = EPOLLIN;
177 terminateEvent.data.u32 = DispatchType::TERMINATE;
178 if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mPipes[kReadPipe], &terminateEvent) == -1) {
179 ALOGE("Error adding control fd to dispatch loop");
Ady Abraham75398722020-04-07 14:08:45 -0700180 return true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800181 }
182
183 uint64_t iteration = 0;
Ady Abraham75398722020-04-07 14:08:45 -0700184
185 while (true) {
186 setDebugState(DebugState::Waiting);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800187 epoll_event events[DispatchType::MAX_DISPATCH_TYPE];
188 int nfds = epoll_wait(mEpollFd, events, DispatchType::MAX_DISPATCH_TYPE, -1);
189
Ady Abraham75398722020-04-07 14:08:45 -0700190 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800191 if (ATRACE_ENABLED()) {
Dominik Laskowski62eff352021-12-06 09:59:41 -0800192 ftl::Concat trace("TimerIteration #", iteration++);
193 ATRACE_NAME(trace.c_str());
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800194 }
195
196 if (nfds == -1) {
197 if (errno != EINTR) {
Ady Abraham75398722020-04-07 14:08:45 -0700198 ALOGE("Error waiting on epoll: %s", strerror(errno));
199 return true;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800200 }
201 }
202
203 for (auto i = 0; i < nfds; i++) {
204 if (events[i].data.u32 == DispatchType::TIMER) {
205 static uint64_t mIgnored = 0;
Ady Abraham75398722020-04-07 14:08:45 -0700206 setDebugState(DebugState::Reading);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800207 read(mTimerFd, &mIgnored, sizeof(mIgnored));
Ady Abraham75398722020-04-07 14:08:45 -0700208 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800209 std::function<void()> cb;
210 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700211 std::lock_guard lock(mMutex);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800212 cb = mCallback;
Ady Abraham3a3815a2021-12-23 14:32:07 -0800213 mExpectingCallback = false;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800214 }
215 if (cb) {
Ady Abraham75398722020-04-07 14:08:45 -0700216 setDebugState(DebugState::InCallback);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800217 cb();
Ady Abraham75398722020-04-07 14:08:45 -0700218 setDebugState(DebugState::Running);
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800219 }
220 }
221 if (events[i].data.u32 == DispatchType::TERMINATE) {
Ady Abraham75398722020-04-07 14:08:45 -0700222 ALOGE("Terminated");
223 setDebugState(DebugState::Running);
224 return false;
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800225 }
226 }
227 }
228}
229
Ady Abraham75398722020-04-07 14:08:45 -0700230void Timer::setDebugState(DebugState state) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700231 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700232 mDebugState = state;
233}
234
Alec Mouriaa20c582023-10-11 19:44:54 +0000235void Timer::setCallback(std::function<void()>&& callback) {
236 mExpectingCallback = bool(callback);
237 mCallback = std::move(callback);
238}
239
Ady Abraham75398722020-04-07 14:08:45 -0700240void Timer::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700241 std::lock_guard lock(mMutex);
Dominik Laskowski62eff352021-12-06 09:59:41 -0800242 result.append("\t\tDebugState: ");
243 result.append(ftl::enum_string(mDebugState));
244 result.push_back('\n');
Ady Abraham75398722020-04-07 14:08:45 -0700245}
246
Kevin DuBoiscc27b502019-11-13 09:40:07 -0800247} // namespace android::scheduler