• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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