13f4cbf05Sopenharmony_ci/* 23f4cbf05Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 33f4cbf05Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43f4cbf05Sopenharmony_ci * you may not use this file except in compliance with the License. 53f4cbf05Sopenharmony_ci * You may obtain a copy of the License at 63f4cbf05Sopenharmony_ci * 73f4cbf05Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83f4cbf05Sopenharmony_ci * 93f4cbf05Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103f4cbf05Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113f4cbf05Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123f4cbf05Sopenharmony_ci * See the License for the specific language governing permissions and 133f4cbf05Sopenharmony_ci * limitations under the License. 143f4cbf05Sopenharmony_ci */ 153f4cbf05Sopenharmony_ci 163f4cbf05Sopenharmony_ci#include "timer.h" 173f4cbf05Sopenharmony_ci#include "event_reactor.h" 183f4cbf05Sopenharmony_ci 193f4cbf05Sopenharmony_ci#include <algorithm> 203f4cbf05Sopenharmony_ci#include "common_timer_errors.h" 213f4cbf05Sopenharmony_ci#include <atomic> 223f4cbf05Sopenharmony_ci#include <sys/prctl.h> 233f4cbf05Sopenharmony_ci#include "timer_event_handler.h" /* for INVALID_TIMER_FD */ 243f4cbf05Sopenharmony_ci#include "utils_log.h" 253f4cbf05Sopenharmony_cinamespace OHOS { 263f4cbf05Sopenharmony_cinamespace Utils { 273f4cbf05Sopenharmony_ci 283f4cbf05Sopenharmony_ciTimer::Timer(const std::string& name, int timeoutMs) : name_(name), timeoutMs_(timeoutMs), 293f4cbf05Sopenharmony_ci reactor_(new EventReactor()) 303f4cbf05Sopenharmony_ci{ 313f4cbf05Sopenharmony_ci} 323f4cbf05Sopenharmony_ci 333f4cbf05Sopenharmony_ciTimer::~Timer() 343f4cbf05Sopenharmony_ci{ 353f4cbf05Sopenharmony_ci delete reactor_; 363f4cbf05Sopenharmony_ci} 373f4cbf05Sopenharmony_ci 383f4cbf05Sopenharmony_ciuint32_t Timer::Setup() 393f4cbf05Sopenharmony_ci{ 403f4cbf05Sopenharmony_ci if (thread_.joinable()) { // avoid double assign to an active thread 413f4cbf05Sopenharmony_ci return TIMER_ERR_INVALID_VALUE; 423f4cbf05Sopenharmony_ci } 433f4cbf05Sopenharmony_ci reactor_->SwitchOn(); 443f4cbf05Sopenharmony_ci std::thread loop_thread([this] { this->MainLoop(); }); 453f4cbf05Sopenharmony_ci thread_.swap(loop_thread); 463f4cbf05Sopenharmony_ci 473f4cbf05Sopenharmony_ci return TIMER_ERR_OK; 483f4cbf05Sopenharmony_ci} 493f4cbf05Sopenharmony_ci 503f4cbf05Sopenharmony_civoid Timer::Shutdown(bool useJoin) 513f4cbf05Sopenharmony_ci{ 523f4cbf05Sopenharmony_ci if (!thread_.joinable()) { 533f4cbf05Sopenharmony_ci UTILS_LOGD("timer has been stopped already"); 543f4cbf05Sopenharmony_ci return; 553f4cbf05Sopenharmony_ci } 563f4cbf05Sopenharmony_ci 573f4cbf05Sopenharmony_ci reactor_->SwitchOff(); 583f4cbf05Sopenharmony_ci if (timeoutMs_ == -1) { 593f4cbf05Sopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 603f4cbf05Sopenharmony_ci if (intervalToTimers_.empty()) { 613f4cbf05Sopenharmony_ci UTILS_LOGI("no event for epoll wait, use detach to shutdown"); 623f4cbf05Sopenharmony_ci 633f4cbf05Sopenharmony_ci int tmpTimerFd = INVALID_TIMER_FD; 643f4cbf05Sopenharmony_ci uint32_t ret = reactor_->ScheduleTimer([](int unused) { 653f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s:Pseudo-task invoked to get thread exited.", __func__); 663f4cbf05Sopenharmony_ci }, 0, tmpTimerFd, true); // Add a task to avoid eternally blocking of epoll_wait 673f4cbf05Sopenharmony_ci if (ret == TIMER_ERR_OK) { 683f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s:Pseudo-task need to be scheduled.", __func__); 693f4cbf05Sopenharmony_ci } 703f4cbf05Sopenharmony_ci 713f4cbf05Sopenharmony_ci thread_.detach(); 723f4cbf05Sopenharmony_ci return; 733f4cbf05Sopenharmony_ci } 743f4cbf05Sopenharmony_ci } 753f4cbf05Sopenharmony_ci if (!useJoin) { 763f4cbf05Sopenharmony_ci thread_.detach(); 773f4cbf05Sopenharmony_ci return; 783f4cbf05Sopenharmony_ci } 793f4cbf05Sopenharmony_ci thread_.join(); 803f4cbf05Sopenharmony_ci} 813f4cbf05Sopenharmony_ci 823f4cbf05Sopenharmony_ciuint32_t Timer::Register(const TimerCallback& callback, uint32_t interval /* ms */, bool once) 833f4cbf05Sopenharmony_ci{ 843f4cbf05Sopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 853f4cbf05Sopenharmony_ci static std::atomic_uint32_t timerId = 1; 863f4cbf05Sopenharmony_ci int timerFd = once ? INVALID_TIMER_FD : GetTimerFd(interval); 873f4cbf05Sopenharmony_ci if (timerFd == INVALID_TIMER_FD) { 883f4cbf05Sopenharmony_ci uint32_t ret = DoRegister([this](int fd) { this->OnTimer(fd); }, interval, once, timerFd); 893f4cbf05Sopenharmony_ci if (ret != TIMER_ERR_OK) { 903f4cbf05Sopenharmony_ci UTILS_LOGE("do register interval timer %{public}d failed, return %{public}u", interval, ret); 913f4cbf05Sopenharmony_ci return TIMER_ERR_DEAL_FAILED; 923f4cbf05Sopenharmony_ci } 933f4cbf05Sopenharmony_ci } 943f4cbf05Sopenharmony_ci 953f4cbf05Sopenharmony_ci timerId = GetValidId(timerId); 963f4cbf05Sopenharmony_ci while (timerToEntries_.find(timerId) != timerToEntries_.end()) { 973f4cbf05Sopenharmony_ci timerId++; 983f4cbf05Sopenharmony_ci timerId = GetValidId(timerId); 993f4cbf05Sopenharmony_ci } 1003f4cbf05Sopenharmony_ci 1013f4cbf05Sopenharmony_ci TimerEntryPtr entry(new TimerEntry()); 1023f4cbf05Sopenharmony_ci entry->timerId = timerId++; 1033f4cbf05Sopenharmony_ci entry->interval = interval; 1043f4cbf05Sopenharmony_ci entry->callback = callback; 1053f4cbf05Sopenharmony_ci entry->once = once; 1063f4cbf05Sopenharmony_ci entry->timerFd = timerFd; 1073f4cbf05Sopenharmony_ci 1083f4cbf05Sopenharmony_ci intervalToTimers_[interval].push_back(entry); 1093f4cbf05Sopenharmony_ci timerToEntries_[entry->timerId] = entry; 1103f4cbf05Sopenharmony_ci 1113f4cbf05Sopenharmony_ci UTILS_LOGD("register timer %{public}u with %{public}u ms interval.", entry->timerId, entry->interval); 1123f4cbf05Sopenharmony_ci return entry->timerId; 1133f4cbf05Sopenharmony_ci} 1143f4cbf05Sopenharmony_ci 1153f4cbf05Sopenharmony_civoid Timer::Unregister(uint32_t timerId) 1163f4cbf05Sopenharmony_ci{ 1173f4cbf05Sopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 1183f4cbf05Sopenharmony_ci if (timerToEntries_.find(timerId) == timerToEntries_.end()) { 1193f4cbf05Sopenharmony_ci UTILS_LOGD("timer %{public}u does not exist", timerId); 1203f4cbf05Sopenharmony_ci return; 1213f4cbf05Sopenharmony_ci } 1223f4cbf05Sopenharmony_ci 1233f4cbf05Sopenharmony_ci auto entry = timerToEntries_[timerId]; 1243f4cbf05Sopenharmony_ci UTILS_LOGD("deregister timer %{public}u with %{public}u ms interval", timerId, entry->interval); 1253f4cbf05Sopenharmony_ci 1263f4cbf05Sopenharmony_ci auto itor = intervalToTimers_[entry->interval].begin(); 1273f4cbf05Sopenharmony_ci for (; itor != intervalToTimers_[entry->interval].end(); ++itor) { 1283f4cbf05Sopenharmony_ci if ((*itor)->timerId == timerId) { 1293f4cbf05Sopenharmony_ci UTILS_LOGD("erase timer %{public}u.", timerId); 1303f4cbf05Sopenharmony_ci if ((*itor)->once) { 1313f4cbf05Sopenharmony_ci reactor_->CancelTimer((*itor)->timerFd); 1323f4cbf05Sopenharmony_ci timers_.erase((*itor)->timerFd); 1333f4cbf05Sopenharmony_ci } 1343f4cbf05Sopenharmony_ci intervalToTimers_[entry->interval].erase(itor); 1353f4cbf05Sopenharmony_ci break; 1363f4cbf05Sopenharmony_ci } 1373f4cbf05Sopenharmony_ci } 1383f4cbf05Sopenharmony_ci 1393f4cbf05Sopenharmony_ci if (intervalToTimers_[entry->interval].empty()) { 1403f4cbf05Sopenharmony_ci UTILS_LOGD("deregister timer interval: %{public}u.", entry->interval); 1413f4cbf05Sopenharmony_ci intervalToTimers_.erase(entry->interval); 1423f4cbf05Sopenharmony_ci DoUnregister(entry->interval); 1433f4cbf05Sopenharmony_ci } 1443f4cbf05Sopenharmony_ci timerToEntries_.erase(timerId); 1453f4cbf05Sopenharmony_ci} 1463f4cbf05Sopenharmony_ci 1473f4cbf05Sopenharmony_civoid Timer::MainLoop() 1483f4cbf05Sopenharmony_ci{ 1493f4cbf05Sopenharmony_ci prctl(PR_SET_NAME, name_.c_str(), 0, 0, 0); 1503f4cbf05Sopenharmony_ci if (reactor_->SetUp() == TIMER_ERR_OK) { 1513f4cbf05Sopenharmony_ci reactor_->RunLoop(timeoutMs_); 1523f4cbf05Sopenharmony_ci } 1533f4cbf05Sopenharmony_ci reactor_->CleanUp(); 1543f4cbf05Sopenharmony_ci} 1553f4cbf05Sopenharmony_ci 1563f4cbf05Sopenharmony_ciuint32_t Timer::DoRegister(const TimerListCallback& callback, uint32_t interval, bool once, int &timerFd) 1573f4cbf05Sopenharmony_ci{ 1583f4cbf05Sopenharmony_ci std::function<void(int)> cb = [this, callback](int fd) { this->DoTimerListCallback(callback, fd); }; 1593f4cbf05Sopenharmony_ci uint32_t ret = reactor_->ScheduleTimer(cb, interval, timerFd, once); 1603f4cbf05Sopenharmony_ci if ((ret != TIMER_ERR_OK) || (timerFd < 0)) { 1613f4cbf05Sopenharmony_ci UTILS_LOGE("ScheduleTimer failed!ret:%{public}d, timerFd:%{public}d", ret, timerFd); 1623f4cbf05Sopenharmony_ci return ret; 1633f4cbf05Sopenharmony_ci } 1643f4cbf05Sopenharmony_ci timers_[timerFd] = interval; 1653f4cbf05Sopenharmony_ci return TIMER_ERR_OK; 1663f4cbf05Sopenharmony_ci} 1673f4cbf05Sopenharmony_ci 1683f4cbf05Sopenharmony_civoid Timer::DoUnregister(uint32_t interval) 1693f4cbf05Sopenharmony_ci{ 1703f4cbf05Sopenharmony_ci for (auto& itor : timers_) { 1713f4cbf05Sopenharmony_ci if (itor.second == interval) { 1723f4cbf05Sopenharmony_ci reactor_->CancelTimer(itor.first); 1733f4cbf05Sopenharmony_ci } 1743f4cbf05Sopenharmony_ci } 1753f4cbf05Sopenharmony_ci} 1763f4cbf05Sopenharmony_ci 1773f4cbf05Sopenharmony_civoid Timer::OnTimer(int timerFd) 1783f4cbf05Sopenharmony_ci{ 1793f4cbf05Sopenharmony_ci uint32_t interval; 1803f4cbf05Sopenharmony_ci TimerEntryList entryList; 1813f4cbf05Sopenharmony_ci { 1823f4cbf05Sopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 1833f4cbf05Sopenharmony_ci interval = timers_[timerFd]; 1843f4cbf05Sopenharmony_ci entryList = intervalToTimers_[interval]; 1853f4cbf05Sopenharmony_ci } 1863f4cbf05Sopenharmony_ci 1873f4cbf05Sopenharmony_ci std::vector<uint32_t> onceIdsUnused; 1883f4cbf05Sopenharmony_ci for (const TimerEntryPtr& ptr : entryList) { 1893f4cbf05Sopenharmony_ci if (ptr->timerFd != timerFd) { 1903f4cbf05Sopenharmony_ci continue; 1913f4cbf05Sopenharmony_ci } 1923f4cbf05Sopenharmony_ci /* if stop, callback is forbidden */ 1933f4cbf05Sopenharmony_ci if (reactor_->IsLoopReady() && reactor_->IsSwitchedOn()) { 1943f4cbf05Sopenharmony_ci ptr->callback(); 1953f4cbf05Sopenharmony_ci } 1963f4cbf05Sopenharmony_ci 1973f4cbf05Sopenharmony_ci if (!ptr->once) { 1983f4cbf05Sopenharmony_ci continue; 1993f4cbf05Sopenharmony_ci } 2003f4cbf05Sopenharmony_ci onceIdsUnused.push_back(ptr->timerId); 2013f4cbf05Sopenharmony_ci } 2023f4cbf05Sopenharmony_ci 2033f4cbf05Sopenharmony_ci if (!onceIdsUnused.empty()) { 2043f4cbf05Sopenharmony_ci EraseUnusedTimerId(interval, onceIdsUnused); 2053f4cbf05Sopenharmony_ci } 2063f4cbf05Sopenharmony_ci} 2073f4cbf05Sopenharmony_ci 2083f4cbf05Sopenharmony_civoid Timer::DoTimerListCallback(const TimerListCallback& callback, int timerFd) 2093f4cbf05Sopenharmony_ci{ 2103f4cbf05Sopenharmony_ci callback(timerFd); 2113f4cbf05Sopenharmony_ci} 2123f4cbf05Sopenharmony_ci 2133f4cbf05Sopenharmony_ci/* valid range: [1, UINT32_MAX], but not TIMER_ERR_DEAL_FAILED */ 2143f4cbf05Sopenharmony_ciuint32_t Timer::GetValidId(uint32_t timerId) const 2153f4cbf05Sopenharmony_ci{ 2163f4cbf05Sopenharmony_ci if (timerId == TIMER_ERR_DEAL_FAILED) { 2173f4cbf05Sopenharmony_ci return timerId + 1; 2183f4cbf05Sopenharmony_ci } 2193f4cbf05Sopenharmony_ci if (timerId == UINT32_MAX) { 2203f4cbf05Sopenharmony_ci return 1; 2213f4cbf05Sopenharmony_ci } 2223f4cbf05Sopenharmony_ci return timerId; 2233f4cbf05Sopenharmony_ci} 2243f4cbf05Sopenharmony_ci 2253f4cbf05Sopenharmony_ciint Timer::GetTimerFd(uint32_t interval /* ms */) 2263f4cbf05Sopenharmony_ci{ 2273f4cbf05Sopenharmony_ci if (intervalToTimers_.find(interval) == intervalToTimers_.end()) { 2283f4cbf05Sopenharmony_ci return INVALID_TIMER_FD; 2293f4cbf05Sopenharmony_ci } 2303f4cbf05Sopenharmony_ci auto &entryList = intervalToTimers_[interval]; 2313f4cbf05Sopenharmony_ci for (const TimerEntryPtr &ptr : entryList) { 2323f4cbf05Sopenharmony_ci if (!ptr->once) { 2333f4cbf05Sopenharmony_ci return ptr->timerFd; 2343f4cbf05Sopenharmony_ci } 2353f4cbf05Sopenharmony_ci } 2363f4cbf05Sopenharmony_ci return INVALID_TIMER_FD; 2373f4cbf05Sopenharmony_ci} 2383f4cbf05Sopenharmony_ci 2393f4cbf05Sopenharmony_civoid Timer::EraseUnusedTimerId(uint32_t interval, const std::vector<uint32_t>& unusedIds) 2403f4cbf05Sopenharmony_ci{ 2413f4cbf05Sopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 2423f4cbf05Sopenharmony_ci auto &entryList = intervalToTimers_[interval]; 2433f4cbf05Sopenharmony_ci for (auto itor = entryList.begin(); itor != entryList.end();) { 2443f4cbf05Sopenharmony_ci uint32_t id = (*itor)->timerId; 2453f4cbf05Sopenharmony_ci if (std::find(unusedIds.begin(), unusedIds.end(), id) == unusedIds.end()) { 2463f4cbf05Sopenharmony_ci ++itor; 2473f4cbf05Sopenharmony_ci continue; 2483f4cbf05Sopenharmony_ci } 2493f4cbf05Sopenharmony_ci 2503f4cbf05Sopenharmony_ci reactor_->CancelTimer((*itor)->timerFd); 2513f4cbf05Sopenharmony_ci timers_.erase((*itor)->timerFd); 2523f4cbf05Sopenharmony_ci itor = entryList.erase(itor); 2533f4cbf05Sopenharmony_ci timerToEntries_.erase(id); 2543f4cbf05Sopenharmony_ci 2553f4cbf05Sopenharmony_ci if (entryList.empty()) { 2563f4cbf05Sopenharmony_ci intervalToTimers_.erase(interval); 2573f4cbf05Sopenharmony_ci DoUnregister(interval); 2583f4cbf05Sopenharmony_ci return; 2593f4cbf05Sopenharmony_ci } 2603f4cbf05Sopenharmony_ci } 2613f4cbf05Sopenharmony_ci} 2623f4cbf05Sopenharmony_ci 2633f4cbf05Sopenharmony_ci} // namespace Utils 2643f4cbf05Sopenharmony_ci} // namespace OHOS 265