15490a39dSopenharmony_ci/* 25490a39dSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 35490a39dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 45490a39dSopenharmony_ci * you may not use this file except in compliance with the License. 55490a39dSopenharmony_ci * You may obtain a copy of the License at 65490a39dSopenharmony_ci * 75490a39dSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 85490a39dSopenharmony_ci * 95490a39dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 105490a39dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 115490a39dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 125490a39dSopenharmony_ci * See the License for the specific language governing permissions and 135490a39dSopenharmony_ci * limitations under the License. 145490a39dSopenharmony_ci */ 155490a39dSopenharmony_ci#include "timer_mgr.h" 165490a39dSopenharmony_ci 175490a39dSopenharmony_ci#include <unistd.h> 185490a39dSopenharmony_ci#include <sys/time.h> 195490a39dSopenharmony_ci#include <sstream> 205490a39dSopenharmony_ci#include "intell_voice_log.h" 215490a39dSopenharmony_ci 225490a39dSopenharmony_ci#define LOG_TAG "TimerMgr" 235490a39dSopenharmony_ci 245490a39dSopenharmony_ciusing namespace std; 255490a39dSopenharmony_ci 265490a39dSopenharmony_cinamespace OHOS { 275490a39dSopenharmony_cinamespace IntellVoiceUtils { 285490a39dSopenharmony_cistatic void LogTime(const string &prefix) 295490a39dSopenharmony_ci{ 305490a39dSopenharmony_ci struct timeval now; 315490a39dSopenharmony_ci if (gettimeofday(&now, nullptr) < 0) { 325490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("gettimeoftoday time info error"); 335490a39dSopenharmony_ci return; 345490a39dSopenharmony_ci } 355490a39dSopenharmony_ci 365490a39dSopenharmony_ci struct tm *nowtm = localtime(&now.tv_sec); 375490a39dSopenharmony_ci if (nowtm == nullptr) { 385490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("nowtm is nullptr"); 395490a39dSopenharmony_ci return; 405490a39dSopenharmony_ci } 415490a39dSopenharmony_ci 425490a39dSopenharmony_ci char tmbuf[64] = {0}; 435490a39dSopenharmony_ci if (strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", nowtm)) { 445490a39dSopenharmony_ci INTELL_VOICE_LOG_INFO("%{public}s %{public}s.%{public}lld", 455490a39dSopenharmony_ci prefix.c_str(), tmbuf, static_cast<long long>(now.tv_usec)); 465490a39dSopenharmony_ci } 475490a39dSopenharmony_ci} 485490a39dSopenharmony_ci 495490a39dSopenharmony_cistatic int64_t NowTimeUs() 505490a39dSopenharmony_ci{ 515490a39dSopenharmony_ci struct timespec t; 525490a39dSopenharmony_ci if (clock_gettime(CLOCK_MONOTONIC, &t) < 0) { 535490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("clock gettime failed"); 545490a39dSopenharmony_ci return 0; 555490a39dSopenharmony_ci } 565490a39dSopenharmony_ci return t.tv_sec * 1000000LL + t.tv_nsec / 1000LL; 575490a39dSopenharmony_ci} 585490a39dSopenharmony_ci 595490a39dSopenharmony_ciTimerItem::TimerItem(int id, int type, int cookie, int64_t delayUs, ITimerObserver *observer) 605490a39dSopenharmony_ci : timerId(id), type(type), cookie(cookie), observer(observer) 615490a39dSopenharmony_ci{ 625490a39dSopenharmony_ci tgtUs = NowTimeUs() + delayUs; 635490a39dSopenharmony_ci} 645490a39dSopenharmony_ci 655490a39dSopenharmony_ciTimerMgr::TimerMgr(int maxTimerNum) : IdAllocator(maxTimerNum), status_(TimerStatus::TIMER_STATUS_INIT), 665490a39dSopenharmony_ci timerObserver_(nullptr) 675490a39dSopenharmony_ci{ 685490a39dSopenharmony_ci} 695490a39dSopenharmony_ci 705490a39dSopenharmony_ciTimerMgr::~TimerMgr() 715490a39dSopenharmony_ci{ 725490a39dSopenharmony_ci Stop(); 735490a39dSopenharmony_ci} 745490a39dSopenharmony_ci 755490a39dSopenharmony_civoid TimerMgr::Start(const std::string &threadName, ITimerObserver *observer) 765490a39dSopenharmony_ci{ 775490a39dSopenharmony_ci std::unique_lock<ffrt::mutex> lock(timeMutex_); 785490a39dSopenharmony_ci 795490a39dSopenharmony_ci if (status_ == TimerStatus::TIMER_STATUS_STARTED) { 805490a39dSopenharmony_ci return; 815490a39dSopenharmony_ci } 825490a39dSopenharmony_ci 835490a39dSopenharmony_ci if (status_ != TimerStatus::TIMER_STATUS_INIT) { 845490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("status is not init"); 855490a39dSopenharmony_ci return; 865490a39dSopenharmony_ci } 875490a39dSopenharmony_ci 885490a39dSopenharmony_ci if (!ThreadWrapper::Start(threadName)) { 895490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("failed to start timer"); 905490a39dSopenharmony_ci return; 915490a39dSopenharmony_ci } 925490a39dSopenharmony_ci 935490a39dSopenharmony_ci timerObserver_ = observer; 945490a39dSopenharmony_ci status_ = TimerStatus::TIMER_STATUS_STARTED; 955490a39dSopenharmony_ci LogTime("start timermgr"); 965490a39dSopenharmony_ci} 975490a39dSopenharmony_ci 985490a39dSopenharmony_civoid TimerMgr::Stop() 995490a39dSopenharmony_ci{ 1005490a39dSopenharmony_ci { 1015490a39dSopenharmony_ci std::lock_guard<ffrt::mutex> lock(timeMutex_); 1025490a39dSopenharmony_ci if (status_ != TimerStatus::TIMER_STATUS_STARTED) { 1035490a39dSopenharmony_ci INTELL_VOICE_LOG_WARN("status is not started"); 1045490a39dSopenharmony_ci return; 1055490a39dSopenharmony_ci } 1065490a39dSopenharmony_ci status_ = TimerStatus::TIMER_STATUS_TO_QUIT; 1075490a39dSopenharmony_ci LogTime("stop timermgr"); 1085490a39dSopenharmony_ci cv_.notify_all(); 1095490a39dSopenharmony_ci } 1105490a39dSopenharmony_ci 1115490a39dSopenharmony_ci ThreadWrapper::Join(); 1125490a39dSopenharmony_ci 1135490a39dSopenharmony_ci Clear(); 1145490a39dSopenharmony_ci} 1155490a39dSopenharmony_ci 1165490a39dSopenharmony_ciint TimerMgr::SetTimer(int type, int64_t delayUs, int cookie, ITimerObserver *currObserver) 1175490a39dSopenharmony_ci{ 1185490a39dSopenharmony_ci std::unique_lock<ffrt::mutex> lock(timeMutex_); 1195490a39dSopenharmony_ci 1205490a39dSopenharmony_ci if (status_ != TimerStatus::TIMER_STATUS_STARTED) { 1215490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("timer mgr not started"); 1225490a39dSopenharmony_ci return INVALID_ID; 1235490a39dSopenharmony_ci } 1245490a39dSopenharmony_ci 1255490a39dSopenharmony_ci ITimerObserver* observer = currObserver == nullptr ? timerObserver_ : currObserver; 1265490a39dSopenharmony_ci if (observer == nullptr) { 1275490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("observer is null"); 1285490a39dSopenharmony_ci return INVALID_ID; 1295490a39dSopenharmony_ci } 1305490a39dSopenharmony_ci 1315490a39dSopenharmony_ci int id = AllocId(); 1325490a39dSopenharmony_ci if (id == INVALID_ID) { 1335490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("no available id"); 1345490a39dSopenharmony_ci return INVALID_ID; 1355490a39dSopenharmony_ci } 1365490a39dSopenharmony_ci 1375490a39dSopenharmony_ci shared_ptr<TimerItem> addItem = make_shared<TimerItem>(id, type, cookie, delayUs, observer); 1385490a39dSopenharmony_ci if (addItem == nullptr) { 1395490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("no avaiable memory"); 1405490a39dSopenharmony_ci ReleaseId(id); 1415490a39dSopenharmony_ci return INVALID_ID; 1425490a39dSopenharmony_ci } 1435490a39dSopenharmony_ci 1445490a39dSopenharmony_ci auto it = itemQueue_.begin(); 1455490a39dSopenharmony_ci while (it != itemQueue_.end() && (*it)->tgtUs < addItem->tgtUs) { 1465490a39dSopenharmony_ci ++it; 1475490a39dSopenharmony_ci } 1485490a39dSopenharmony_ci 1495490a39dSopenharmony_ci bool needNotify = (it == itemQueue_.begin()); 1505490a39dSopenharmony_ci itemQueue_.insert(it, addItem); 1515490a39dSopenharmony_ci 1525490a39dSopenharmony_ci if (needNotify) { 1535490a39dSopenharmony_ci cv_.notify_one(); 1545490a39dSopenharmony_ci } 1555490a39dSopenharmony_ci 1565490a39dSopenharmony_ci ostringstream oss; 1575490a39dSopenharmony_ci oss << "set timer id " << id << " type " << type << " delay " << delayUs << " cookie " << cookie << " time "; 1585490a39dSopenharmony_ci LogTime(oss.str()); 1595490a39dSopenharmony_ci 1605490a39dSopenharmony_ci return id; 1615490a39dSopenharmony_ci} 1625490a39dSopenharmony_ci 1635490a39dSopenharmony_ciint TimerMgr::ResetTimer(int timerId, int type, int64_t delayUs, int cookie, ITimerObserver *currObserver) 1645490a39dSopenharmony_ci{ 1655490a39dSopenharmony_ci { 1665490a39dSopenharmony_ci std::unique_lock<ffrt::mutex> lock(timeMutex_); 1675490a39dSopenharmony_ci if (itemQueue_.size() == 1) { 1685490a39dSopenharmony_ci auto it = itemQueue_.begin(); 1695490a39dSopenharmony_ci if ((*it)->timerId != timerId) { 1705490a39dSopenharmony_ci INTELL_VOICE_LOG_ERROR("id %{public}d can not correspond with timerId %{public}d", 1715490a39dSopenharmony_ci (*it)->timerId, timerId); 1725490a39dSopenharmony_ci return INVALID_ID; 1735490a39dSopenharmony_ci } 1745490a39dSopenharmony_ci (*it)->tgtUs = NowTimeUs() + delayUs; 1755490a39dSopenharmony_ci cv_.notify_one(); 1765490a39dSopenharmony_ci return timerId; 1775490a39dSopenharmony_ci } 1785490a39dSopenharmony_ci } 1795490a39dSopenharmony_ci KillTimer(timerId); 1805490a39dSopenharmony_ci return SetTimer(type, delayUs, cookie, currObserver); 1815490a39dSopenharmony_ci} 1825490a39dSopenharmony_ci 1835490a39dSopenharmony_civoid TimerMgr::KillTimer(int &timerId) 1845490a39dSopenharmony_ci{ 1855490a39dSopenharmony_ci std::unique_lock<ffrt::mutex> lock(timeMutex_); 1865490a39dSopenharmony_ci INTELL_VOICE_LOG_INFO("kill timer %{public}d", timerId); 1875490a39dSopenharmony_ci for (auto it = itemQueue_.begin(); it != itemQueue_.end(); it++) { 1885490a39dSopenharmony_ci shared_ptr<TimerItem> curItem = *it; 1895490a39dSopenharmony_ci if (curItem->timerId == timerId) { 1905490a39dSopenharmony_ci INTELL_VOICE_LOG_INFO("kill timer id:%{public}d, type: %{public}d, cookie:%{public}d", 1915490a39dSopenharmony_ci timerId, curItem->type, curItem->cookie); 1925490a39dSopenharmony_ci ReleaseId(curItem->timerId); 1935490a39dSopenharmony_ci itemQueue_.erase(it); 1945490a39dSopenharmony_ci timerId = INVALID_ID; 1955490a39dSopenharmony_ci break; 1965490a39dSopenharmony_ci } 1975490a39dSopenharmony_ci } 1985490a39dSopenharmony_ci 1995490a39dSopenharmony_ci if (timerId != INVALID_ID) { 2005490a39dSopenharmony_ci INTELL_VOICE_LOG_WARN("can not find timer id:%{public}d", timerId); 2015490a39dSopenharmony_ci timerId = INVALID_ID; 2025490a39dSopenharmony_ci } 2035490a39dSopenharmony_ci} 2045490a39dSopenharmony_ci 2055490a39dSopenharmony_civoid TimerMgr::Clear() 2065490a39dSopenharmony_ci{ 2075490a39dSopenharmony_ci std::lock_guard<ffrt::mutex> lock(timeMutex_); 2085490a39dSopenharmony_ci 2095490a39dSopenharmony_ci itemQueue_.clear(); 2105490a39dSopenharmony_ci IdAllocator::ClearId(); 2115490a39dSopenharmony_ci 2125490a39dSopenharmony_ci status_ = TimerStatus::TIMER_STATUS_INIT; 2135490a39dSopenharmony_ci timerObserver_ = nullptr; 2145490a39dSopenharmony_ci} 2155490a39dSopenharmony_ci 2165490a39dSopenharmony_civoid TimerMgr::Run() 2175490a39dSopenharmony_ci{ 2185490a39dSopenharmony_ci while (true) { 2195490a39dSopenharmony_ci TimerItem item; 2205490a39dSopenharmony_ci { 2215490a39dSopenharmony_ci std::unique_lock<ffrt::mutex> lock(timeMutex_); 2225490a39dSopenharmony_ci 2235490a39dSopenharmony_ci if (status_ != TimerStatus::TIMER_STATUS_STARTED) { 2245490a39dSopenharmony_ci break; 2255490a39dSopenharmony_ci } 2265490a39dSopenharmony_ci 2275490a39dSopenharmony_ci if (itemQueue_.empty()) { 2285490a39dSopenharmony_ci cv_.wait(lock); 2295490a39dSopenharmony_ci continue; 2305490a39dSopenharmony_ci } 2315490a39dSopenharmony_ci 2325490a39dSopenharmony_ci item = *itemQueue_.front(); 2335490a39dSopenharmony_ci int64_t now = NowTimeUs(); 2345490a39dSopenharmony_ci if (now < item.tgtUs) { 2355490a39dSopenharmony_ci cv_.wait_for(lock, chrono::microseconds(item.tgtUs - now)); 2365490a39dSopenharmony_ci continue; 2375490a39dSopenharmony_ci } 2385490a39dSopenharmony_ci ReleaseId(item.timerId); 2395490a39dSopenharmony_ci itemQueue_.pop_front(); 2405490a39dSopenharmony_ci } 2415490a39dSopenharmony_ci 2425490a39dSopenharmony_ci if (item.observer != nullptr) { 2435490a39dSopenharmony_ci TimerEvent info(item.type, item.timerId, item.cookie); 2445490a39dSopenharmony_ci item.observer->OnTimerEvent(info); 2455490a39dSopenharmony_ci } 2465490a39dSopenharmony_ci }; 2475490a39dSopenharmony_ci 2485490a39dSopenharmony_ci INTELL_VOICE_LOG_INFO("timer thread exit"); 2495490a39dSopenharmony_ci} 2505490a39dSopenharmony_ci} 2515490a39dSopenharmony_ci} 252