1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <mutex>
17 #include <chrono>
18 #include <iostream>
19 #include "sync/timer_manager.h"
20 #include "dfx/log/ffrt_log_api.h"
21
22 constexpr uint64_t MAX_TIMER_MS_COUNT = 1000ULL * 100 * 60 * 60 * 24 * 365; // 100year
23 namespace ffrt {
Instance()24 TimerManager& TimerManager::Instance()
25 {
26 static TimerManager ins;
27 return ins;
28 }
29
TimerManager()30 TimerManager::TimerManager()
31 {
32 for (int i = 0; i < QoS::MaxNum(); ++i) {
33 InitWorkQueAndCb(qos(i));
34 }
35 }
36
~TimerManager()37 TimerManager::~TimerManager()
38 {
39 std::lock_guard lock(timerMutex_);
40 teardown = true;
41 }
42
InitWorkQueAndCb(int qos)43 void TimerManager::InitWorkQueAndCb(int qos)
44 {
45 workCb[qos] = [this, qos](WaitEntry* we) {
46 {
47 std::lock_guard lock(timerMutex_);
48 if (teardown) {
49 return;
50 }
51 }
52
53 int handle = (int)reinterpret_cast<uint64_t>(we);
54 submit([this, handle]() {
55 std::unique_lock timerLock(timerMutex_);
56 if (teardown) {
57 return;
58 }
59
60 auto it = timerMap_.find(handle);
61 if (it == timerMap_.end()) {
62 // timer unregistered
63 return;
64 }
65
66 // execute timer
67 std::shared_ptr<TimerData> timerMapValue = it->second;
68 timerMapValue->state = TimerState::EXECUTING;
69 if (timerMapValue->cb != nullptr) {
70 timerLock.unlock();
71 #ifdef FFRT_ENABLE_HITRACE_CHAIN
72 if (timerMapValue->traceId.valid == HITRACE_ID_VALID) {
73 TraceChainAdapter::Instance().HiTraceChainRestoreId(&timerMapValue->traceId);
74 }
75 #endif
76 timerMapValue->cb(timerMapValue->data);
77 #ifdef FFRT_ENABLE_HITRACE_CHAIN
78 if (timerMapValue->traceId.valid == HITRACE_ID_VALID) {
79 TraceChainAdapter::Instance().HiTraceChainClearId();
80 }
81 #endif
82 timerLock.lock();
83 }
84 timerMapValue->state = TimerState::EXECUTED;
85
86 if (timerMapValue->repeat) {
87 // re-register timer data
88 RegisterTimerImpl(timerMapValue);
89 } else {
90 // delete timer data
91 timerMap_.erase(it);
92 }
93 },
94 {}, {&workQueDeps[qos]}, ffrt::task_attr().qos(qos));
95 };
96 }
97
RegisterTimer(int qos,uint64_t timeout,void * data,ffrt_timer_cb cb,bool repeat)98 ffrt_timer_t TimerManager::RegisterTimer(int qos, uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat) noexcept
99 {
100 std::lock_guard lock(timerMutex_);
101 if (teardown) {
102 return -1;
103 }
104
105 if (timeout > MAX_TIMER_MS_COUNT) {
106 FFRT_LOGW("timeout exceeds maximum allowed value %llu ms. Clamping to %llu ms.", timeout, MAX_TIMER_MS_COUNT);
107 timeout = MAX_TIMER_MS_COUNT;
108 }
109 std::shared_ptr<TimerData> timerMapValue = std::make_shared<TimerData>(data, cb, repeat, qos, timeout);
110 timerMapValue->handle = ++timerHandle_;
111 timerMapValue->state = TimerState::NOT_EXECUTED;
112 timerMap_.emplace(timerHandle_, timerMapValue);
113
114 RegisterTimerImpl(timerMapValue);
115 return timerHandle_;
116 }
117
RegisterTimerImpl(std::shared_ptr<TimerData> data)118 void TimerManager::RegisterTimerImpl(std::shared_ptr<TimerData> data)
119 {
120 TimePoint absoluteTime = std::chrono::steady_clock::now() + std::chrono::milliseconds(data->timeout);
121 if (!DelayedWakeup(absoluteTime, reinterpret_cast<WaitEntry*>(data->handle), workCb[data->qos], true)) {
122 FFRT_LOGW("timer start failed, process may be exiting now");
123 }
124 }
125
UnregisterTimer(ffrt_timer_t handle)126 int TimerManager::UnregisterTimer(ffrt_timer_t handle) noexcept
127 {
128 std::unique_lock timerLock(timerMutex_);
129 if (teardown) {
130 return -1;
131 }
132
133 if (handle > timerHandle_ || handle <= -1) { // invalid handle
134 return -1;
135 }
136
137 auto it = timerMap_.find(handle);
138 if (it == timerMap_.end()) {
139 return 0;
140 }
141
142 if (it->second->state == TimerState::NOT_EXECUTED || it->second->state == TimerState::EXECUTED) {
143 // timer not executed or executed, delete timer data
144 timerMap_.erase(it);
145 return 0;
146 }
147 if (it->second->state == TimerState::EXECUTING) {
148 // timer executing, spin wait it done
149 while (it->second->state == TimerState::EXECUTING) {
150 timerLock.unlock();
151 std::this_thread::yield();
152 timerLock.lock();
153 it = timerMap_.find(handle);
154 if (it == timerMap_.end()) {
155 // timer already erased
156 return 0;
157 }
158 }
159 // executed, delete timer data
160 timerMap_.erase(it);
161 return 0;
162 }
163 // timer already erased
164 return 0;
165 }
166
GetTimerStatus(ffrt_timer_t handle)167 ffrt_timer_query_t TimerManager::GetTimerStatus(ffrt_timer_t handle) noexcept
168 {
169 std::unique_lock timerLock(timerMutex_);
170 if (teardown) {
171 return ffrt_timer_notfound;
172 }
173
174 if (handle > timerHandle_) { // invalid handle
175 return ffrt_timer_notfound;
176 }
177
178 auto it = timerMap_.find(handle);
179 if (it == timerMap_.end()) {
180 return ffrt_timer_executed;
181 }
182
183 if (it->second->state == TimerState::NOT_EXECUTED) {
184 // timer has not been executed
185 return ffrt_timer_not_executed;
186 }
187 if (it->second->state == TimerState::EXECUTING || it->second->state == TimerState::EXECUTED) {
188 // timer executing or has been executed (don't spin wait executing)
189 // timer executing, spin wait it done
190 while (it->second->state == TimerState::EXECUTING) {
191 timerLock.unlock();
192 std::this_thread::yield();
193 timerLock.lock();
194 it = timerMap_.find(handle);
195 if (it == timerMap_.end()) {
196 // timer already erased
197 break;
198 }
199 }
200 return ffrt_timer_executed;
201 }
202 // timer has been executed or unregistered
203 return ffrt_timer_executed;
204 }
205 }
206