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