1 /*
2 * Copyright (c) 2023 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 #include "timer_mgr.h"
16
17 #include <unistd.h>
18 #include <sys/time.h>
19 #include <sstream>
20 #include "intell_voice_log.h"
21
22 #define LOG_TAG "TimerMgr"
23
24 using namespace std;
25
26 namespace OHOS {
27 namespace IntellVoiceUtils {
LogTime(const string & prefix)28 static void LogTime(const string &prefix)
29 {
30 struct timeval now;
31 if (gettimeofday(&now, nullptr) < 0) {
32 INTELL_VOICE_LOG_ERROR("gettimeoftoday time info error");
33 return;
34 }
35
36 struct tm *nowtm = localtime(&now.tv_sec);
37 if (nowtm == nullptr) {
38 INTELL_VOICE_LOG_ERROR("nowtm is nullptr");
39 return;
40 }
41
42 char tmbuf[64] = {0};
43 if (strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", nowtm)) {
44 INTELL_VOICE_LOG_INFO("%{public}s %{public}s.%{public}lld",
45 prefix.c_str(), tmbuf, static_cast<long long>(now.tv_usec));
46 }
47 }
48
NowTimeUs()49 static int64_t NowTimeUs()
50 {
51 struct timespec t;
52 if (clock_gettime(CLOCK_MONOTONIC, &t) < 0) {
53 INTELL_VOICE_LOG_ERROR("clock gettime failed");
54 return 0;
55 }
56 return t.tv_sec * 1000000LL + t.tv_nsec / 1000LL;
57 }
58
TimerItem(int id,int type,int cookie,int64_t delayUs,ITimerObserver * observer)59 TimerItem::TimerItem(int id, int type, int cookie, int64_t delayUs, ITimerObserver *observer)
60 : timerId(id), type(type), cookie(cookie), observer(observer)
61 {
62 tgtUs = NowTimeUs() + delayUs;
63 }
64
TimerMgr(int maxTimerNum)65 TimerMgr::TimerMgr(int maxTimerNum) : IdAllocator(maxTimerNum), status_(TimerStatus::TIMER_STATUS_INIT),
66 timerObserver_(nullptr)
67 {
68 }
69
~TimerMgr()70 TimerMgr::~TimerMgr()
71 {
72 Stop();
73 }
74
Start(const std::string & threadName,ITimerObserver * observer)75 void TimerMgr::Start(const std::string &threadName, ITimerObserver *observer)
76 {
77 std::unique_lock<ffrt::mutex> lock(timeMutex_);
78
79 if (status_ == TimerStatus::TIMER_STATUS_STARTED) {
80 return;
81 }
82
83 if (status_ != TimerStatus::TIMER_STATUS_INIT) {
84 INTELL_VOICE_LOG_ERROR("status is not init");
85 return;
86 }
87
88 if (!ThreadWrapper::Start(threadName)) {
89 INTELL_VOICE_LOG_ERROR("failed to start timer");
90 return;
91 }
92
93 timerObserver_ = observer;
94 status_ = TimerStatus::TIMER_STATUS_STARTED;
95 LogTime("start timermgr");
96 }
97
Stop()98 void TimerMgr::Stop()
99 {
100 {
101 std::lock_guard<ffrt::mutex> lock(timeMutex_);
102 if (status_ != TimerStatus::TIMER_STATUS_STARTED) {
103 INTELL_VOICE_LOG_WARN("status is not started");
104 return;
105 }
106 status_ = TimerStatus::TIMER_STATUS_TO_QUIT;
107 LogTime("stop timermgr");
108 cv_.notify_all();
109 }
110
111 ThreadWrapper::Join();
112
113 Clear();
114 }
115
SetTimer(int type,int64_t delayUs,int cookie,ITimerObserver * currObserver)116 int TimerMgr::SetTimer(int type, int64_t delayUs, int cookie, ITimerObserver *currObserver)
117 {
118 std::unique_lock<ffrt::mutex> lock(timeMutex_);
119
120 if (status_ != TimerStatus::TIMER_STATUS_STARTED) {
121 INTELL_VOICE_LOG_ERROR("timer mgr not started");
122 return INVALID_ID;
123 }
124
125 ITimerObserver* observer = currObserver == nullptr ? timerObserver_ : currObserver;
126 if (observer == nullptr) {
127 INTELL_VOICE_LOG_ERROR("observer is null");
128 return INVALID_ID;
129 }
130
131 int id = AllocId();
132 if (id == INVALID_ID) {
133 INTELL_VOICE_LOG_ERROR("no available id");
134 return INVALID_ID;
135 }
136
137 shared_ptr<TimerItem> addItem = make_shared<TimerItem>(id, type, cookie, delayUs, observer);
138 if (addItem == nullptr) {
139 INTELL_VOICE_LOG_ERROR("no avaiable memory");
140 ReleaseId(id);
141 return INVALID_ID;
142 }
143
144 auto it = itemQueue_.begin();
145 while (it != itemQueue_.end() && (*it)->tgtUs < addItem->tgtUs) {
146 ++it;
147 }
148
149 bool needNotify = (it == itemQueue_.begin());
150 itemQueue_.insert(it, addItem);
151
152 if (needNotify) {
153 cv_.notify_one();
154 }
155
156 ostringstream oss;
157 oss << "set timer id " << id << " type " << type << " delay " << delayUs << " cookie " << cookie << " time ";
158 LogTime(oss.str());
159
160 return id;
161 }
162
ResetTimer(int timerId,int type,int64_t delayUs,int cookie,ITimerObserver * currObserver)163 int TimerMgr::ResetTimer(int timerId, int type, int64_t delayUs, int cookie, ITimerObserver *currObserver)
164 {
165 {
166 std::unique_lock<ffrt::mutex> lock(timeMutex_);
167 if (itemQueue_.size() == 1) {
168 auto it = itemQueue_.begin();
169 if ((*it)->timerId != timerId) {
170 INTELL_VOICE_LOG_ERROR("id %{public}d can not correspond with timerId %{public}d",
171 (*it)->timerId, timerId);
172 return INVALID_ID;
173 }
174 (*it)->tgtUs = NowTimeUs() + delayUs;
175 cv_.notify_one();
176 return timerId;
177 }
178 }
179 KillTimer(timerId);
180 return SetTimer(type, delayUs, cookie, currObserver);
181 }
182
KillTimer(int & timerId)183 void TimerMgr::KillTimer(int &timerId)
184 {
185 std::unique_lock<ffrt::mutex> lock(timeMutex_);
186 INTELL_VOICE_LOG_INFO("kill timer %d", timerId);
187 for (auto it = itemQueue_.begin(); it != itemQueue_.end(); it++) {
188 shared_ptr<TimerItem> curItem = *it;
189 if (curItem->timerId == timerId) {
190 INTELL_VOICE_LOG_INFO("kill timer id:%{public}d, type: %{public}d, cookie:%{public}d",
191 timerId, curItem->type, curItem->cookie);
192 ReleaseId(curItem->timerId);
193 itemQueue_.erase(it);
194 timerId = INVALID_ID;
195 break;
196 }
197 }
198
199 if (timerId != INVALID_ID) {
200 INTELL_VOICE_LOG_WARN("can not find timer id:%{public}d", timerId);
201 timerId = INVALID_ID;
202 }
203 }
204
Clear()205 void TimerMgr::Clear()
206 {
207 std::lock_guard<ffrt::mutex> lock(timeMutex_);
208
209 itemQueue_.clear();
210 IdAllocator::ClearId();
211
212 status_ = TimerStatus::TIMER_STATUS_INIT;
213 timerObserver_ = nullptr;
214 }
215
Run()216 void TimerMgr::Run()
217 {
218 while (true) {
219 TimerItem item;
220 {
221 std::unique_lock<ffrt::mutex> lock(timeMutex_);
222
223 if (status_ != TimerStatus::TIMER_STATUS_STARTED) {
224 break;
225 }
226
227 if (itemQueue_.empty()) {
228 cv_.wait(lock);
229 continue;
230 }
231
232 item = *itemQueue_.front();
233 int64_t now = NowTimeUs();
234 if (now < item.tgtUs) {
235 cv_.wait_for(lock, chrono::microseconds(item.tgtUs - now));
236 continue;
237 }
238 ReleaseId(item.timerId);
239 itemQueue_.pop_front();
240 }
241
242 if (item.observer != nullptr) {
243 TimerEvent info(item.type, item.timerId, item.cookie);
244 item.observer->OnTimerEvent(info);
245 }
246 };
247
248 INTELL_VOICE_LOG_INFO("timer thread exit");
249 }
250 }
251 }
252