• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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("%s %s.%lld", prefix.c_str(), tmbuf, static_cast<long long>(now.tv_usec));
45     }
46 }
47 
NowTimeUs()48 static int64_t NowTimeUs()
49 {
50     struct timespec t;
51     if (clock_gettime(CLOCK_MONOTONIC, &t) < 0) {
52         INTELL_VOICE_LOG_ERROR("clock gettime failed");
53         return 0;
54     }
55     return t.tv_sec * 1000000LL + t.tv_nsec / 1000LL;
56 }
57 
TimerItem(int id,int type,int cookie,int64_t delayUs,ITimerObserver * observer)58 TimerItem::TimerItem(int id, int type, int cookie, int64_t delayUs, ITimerObserver* observer)
59     : timerId(id), type(type), cookie(cookie), observer(observer)
60 {
61     tgtUs = NowTimeUs() + delayUs;
62 }
63 
TimerMgr(int maxTimerNum)64 TimerMgr::TimerMgr(int maxTimerNum) : IdAllocator(maxTimerNum), status_(TimerStatus::TIMER_STATUS_INIT),
65     timerObserver_(nullptr)
66 {
67 }
68 
~TimerMgr()69 TimerMgr::~TimerMgr()
70 {
71     Stop();
72 }
73 
Start(ITimerObserver * observer)74 void TimerMgr::Start(ITimerObserver* observer)
75 {
76     unique_lock<mutex> lock(timeMutex_);
77 
78     if (status_ == TimerStatus::TIMER_STATUS_STARTED) {
79         return;
80     }
81 
82     if (status_ != TimerStatus::TIMER_STATUS_INIT) {
83         INTELL_VOICE_LOG_ERROR("status is not init");
84         return;
85     }
86 
87     workThread_ = thread(&TimerMgr::WorkThread, this);
88 
89     timerObserver_ = observer;
90     status_ = TimerStatus::TIMER_STATUS_STARTED;
91     LogTime("start timermgr");
92 }
93 
Stop()94 void TimerMgr::Stop()
95 {
96     {
97         lock_guard<mutex> lock(timeMutex_);
98         if (status_ != TimerStatus::TIMER_STATUS_STARTED) {
99             INTELL_VOICE_LOG_ERROR("status is not started");
100             return;
101         }
102         status_ = TimerStatus::TIMER_STATUS_TO_QUIT;
103         LogTime("stop timermgr");
104         cv_.notify_all();
105     }
106 
107     if (workThread_.joinable()) {
108         workThread_.join();
109     }
110 
111     Clear();
112 }
113 
SetTimer(int type,int64_t delayUs,int cookie,ITimerObserver * currObserver)114 int TimerMgr::SetTimer(int type, int64_t delayUs, int cookie, ITimerObserver* currObserver)
115 {
116     unique_lock<mutex> lock(timeMutex_);
117 
118     if (status_ != TimerStatus::TIMER_STATUS_STARTED) {
119         INTELL_VOICE_LOG_ERROR("timer mgr not started");
120         return INVALID_ID;
121     }
122 
123     ITimerObserver* observer = currObserver == nullptr ? timerObserver_ : currObserver;
124     if (observer == nullptr) {
125         INTELL_VOICE_LOG_ERROR("observer is null");
126         return INVALID_ID;
127     }
128 
129     int id = AllocId();
130     if (id == INVALID_ID) {
131         INTELL_VOICE_LOG_ERROR("no available id");
132         return INVALID_ID;
133     }
134 
135     shared_ptr<TimerItem> addItem = make_shared<TimerItem>(id, type, cookie, delayUs, observer);
136     if (addItem == nullptr) {
137         INTELL_VOICE_LOG_ERROR("no avaiable memory");
138         ReleaseId(id);
139         return INVALID_ID;
140     }
141 
142     auto it = itemQueue_.begin();
143     while (it != itemQueue_.end() && (*it)->tgtUs < addItem->tgtUs) {
144         ++it;
145     }
146 
147     bool needNotify = (it == itemQueue_.begin());
148     itemQueue_.insert(it, addItem);
149 
150     if (needNotify) {
151         cv_.notify_one();
152     }
153 
154     ostringstream oss;
155     oss << "set timer id " << id << " type " << type << " delay " << delayUs << " cookie " << cookie << " time ";
156     LogTime(oss.str());
157 
158     return id;
159 }
160 
ResetTimer(int timerId,int type,int64_t delayUs,int cookie,ITimerObserver * currObserver)161 int TimerMgr::ResetTimer(int timerId, int type, int64_t delayUs, int cookie, ITimerObserver* currObserver)
162 {
163     {
164         unique_lock<mutex> lock(timeMutex_);
165         if (itemQueue_.size() == 1) {
166             auto it = itemQueue_.begin();
167             if ((*it)->timerId != timerId) {
168                 INTELL_VOICE_LOG_ERROR("id %d can not correspond with timerId %d", (*it)->timerId, timerId);
169                 return INVALID_ID;
170             }
171             (*it)->tgtUs = NowTimeUs() + delayUs;
172             cv_.notify_one();
173             return timerId;
174         }
175     }
176     KillTimer(timerId);
177     return SetTimer(type, delayUs, cookie, currObserver);
178 }
179 
KillTimer(int & timerId)180 void TimerMgr::KillTimer(int& timerId)
181 {
182     unique_lock<mutex> lock(timeMutex_);
183     INTELL_VOICE_LOG_INFO("kill timer %d", timerId);
184     for (auto it = itemQueue_.begin(); it != itemQueue_.end(); it++) {
185         shared_ptr<TimerItem> curItem = *it;
186         if (curItem->timerId == timerId) {
187             INTELL_VOICE_LOG_INFO("kill timer id %d type %d path %d", timerId, curItem->type, curItem->cookie);
188 
189             ReleaseId(curItem->timerId);
190             itemQueue_.erase(it);
191             timerId = INVALID_ID;
192             break;
193         }
194     }
195 }
196 
Clear()197 void TimerMgr::Clear()
198 {
199     lock_guard<mutex> lock(timeMutex_);
200 
201     itemQueue_.clear();
202     IdAllocator::ClearId();
203 
204     status_ = TimerStatus::TIMER_STATUS_INIT;
205     timerObserver_ = nullptr;
206 }
207 
WorkThread()208 void TimerMgr::WorkThread()
209 {
210     while (true) {
211         TimerItem item;
212         {
213             unique_lock<mutex> lock(timeMutex_);
214 
215             if (status_ != TimerStatus::TIMER_STATUS_STARTED) {
216                 break;
217             }
218 
219             if (itemQueue_.empty()) {
220                 cv_.wait(lock);
221                 continue;
222             }
223 
224             item = *itemQueue_.front();
225             int64_t now = NowTimeUs();
226             if (now < item.tgtUs) {
227                 cv_.wait_for(lock, chrono::microseconds(item.tgtUs - now));
228                 continue;
229             }
230             ReleaseId(item.timerId);
231             itemQueue_.pop_front();
232         }
233 
234         if (item.observer != nullptr) {
235             TimerEvent info(item.type, item.timerId, item.cookie);
236             item.observer->OnTimerEvent(info);
237         }
238     };
239 
240     INTELL_VOICE_LOG_INFO("timer thread exit");
241 }
242 }
243 }
244