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