1020a203aSopenharmony_ci/* 2020a203aSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 3020a203aSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4020a203aSopenharmony_ci * you may not use this file except in compliance with the License. 5020a203aSopenharmony_ci * You may obtain a copy of the License at 6020a203aSopenharmony_ci * 7020a203aSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8020a203aSopenharmony_ci * 9020a203aSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10020a203aSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11020a203aSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12020a203aSopenharmony_ci * See the License for the specific language governing permissions and 13020a203aSopenharmony_ci * limitations under the License. 14020a203aSopenharmony_ci */ 15020a203aSopenharmony_ci 16020a203aSopenharmony_ci#include "SceneTimerOhImpl.h" 17020a203aSopenharmony_ci#include <sys/prctl.h> 18020a203aSopenharmony_ci#include <chrono> 19020a203aSopenharmony_ci#include <thread> 20020a203aSopenharmony_ci#include "hiview_logger.h" 21020a203aSopenharmony_ci 22020a203aSopenharmony_cinamespace OHOS { 23020a203aSopenharmony_cinamespace HiviewDFX { 24020a203aSopenharmony_ciDEFINE_LOG_LABEL(0xD002D66, "Hiview-XPerformance"); 25020a203aSopenharmony_ci 26020a203aSopenharmony_ciusing namespace std::chrono; 27020a203aSopenharmony_ci 28020a203aSopenharmony_ciconst static std::string TIMER_THREAD_NAME = "XperfTimerThr"; 29020a203aSopenharmony_ci 30020a203aSopenharmony_ciSceneTimerOhImpl::SceneTimerOhImpl() 31020a203aSopenharmony_ci{ 32020a203aSopenharmony_ci std::thread timerThread(&SceneTimerOhImpl::Loop, this); 33020a203aSopenharmony_ci timerThread.detach(); 34020a203aSopenharmony_ci} 35020a203aSopenharmony_ci 36020a203aSopenharmony_civoid SceneTimerOhImpl::RegUser(int userId, ICb* cb) 37020a203aSopenharmony_ci{ 38020a203aSopenharmony_ci callbacks[userId] = cb; 39020a203aSopenharmony_ci} 40020a203aSopenharmony_ci 41020a203aSopenharmony_civoid SceneTimerOhImpl::UnRegUser(int userId) 42020a203aSopenharmony_ci{ 43020a203aSopenharmony_ci callbacks.erase(userId); 44020a203aSopenharmony_ci} 45020a203aSopenharmony_ci 46020a203aSopenharmony_civoid SceneTimerOhImpl::Start(int user, int id, long interval) 47020a203aSopenharmony_ci{ 48020a203aSopenharmony_ci int key = BuildRecordKey(user, id); 49020a203aSopenharmony_ci ValidateDuplication(key); 50020a203aSopenharmony_ci long long expireTs = CalcExpireTimeStamp(interval); 51020a203aSopenharmony_ci FillRecordAndNotify(key, expireTs); 52020a203aSopenharmony_ci} 53020a203aSopenharmony_ci 54020a203aSopenharmony_civoid SceneTimerOhImpl::Stop(int user, int id) 55020a203aSopenharmony_ci{ 56020a203aSopenharmony_ci int key = BuildRecordKey(user, id); 57020a203aSopenharmony_ci ValidateExistence(key); 58020a203aSopenharmony_ci RemoveRecordAndNotify(key); 59020a203aSopenharmony_ci} 60020a203aSopenharmony_ci 61020a203aSopenharmony_civoid SceneTimerOhImpl::Loop() 62020a203aSopenharmony_ci{ 63020a203aSopenharmony_ci std::unique_lock<std::mutex> uniqueLock(mut); 64020a203aSopenharmony_ci prctl(PR_SET_NAME, TIMER_THREAD_NAME.c_str(), nullptr, nullptr, nullptr); 65020a203aSopenharmony_ci milliseconds interval(checkInterval); 66020a203aSopenharmony_ci while (true) { 67020a203aSopenharmony_ci if (!records.empty()) { 68020a203aSopenharmony_ci cv.wait_for(uniqueLock, interval); 69020a203aSopenharmony_ci /* note the lock is held now */ 70020a203aSopenharmony_ci CheckRecordsAndTrigger(); 71020a203aSopenharmony_ci continue; 72020a203aSopenharmony_ci } 73020a203aSopenharmony_ci cv.wait(uniqueLock); 74020a203aSopenharmony_ci } 75020a203aSopenharmony_ci} 76020a203aSopenharmony_ci 77020a203aSopenharmony_civoid SceneTimerOhImpl::FillRecordAndNotify(int key, long long expireTs) 78020a203aSopenharmony_ci{ 79020a203aSopenharmony_ci std::unique_lock<std::mutex> uniqueLock(mut); 80020a203aSopenharmony_ci // I believe this double-check is needed 81020a203aSopenharmony_ci if (records.find(key) != records.end()) { 82020a203aSopenharmony_ci throw std::invalid_argument("duplicated id"); 83020a203aSopenharmony_ci } 84020a203aSopenharmony_ci records.emplace(key, expireTs); 85020a203aSopenharmony_ci cv.notify_all(); // remember this 86020a203aSopenharmony_ci} 87020a203aSopenharmony_ci 88020a203aSopenharmony_civoid SceneTimerOhImpl::ValidateDuplication(int key) 89020a203aSopenharmony_ci{ 90020a203aSopenharmony_ci std::unique_lock<std::mutex> uniqueLock(mut); 91020a203aSopenharmony_ci if (records.find(key) != records.end()) { 92020a203aSopenharmony_ci throw std::invalid_argument("duplicated id"); 93020a203aSopenharmony_ci } 94020a203aSopenharmony_ci} 95020a203aSopenharmony_ci 96020a203aSopenharmony_civoid SceneTimerOhImpl::ValidateExistence(int key) 97020a203aSopenharmony_ci{ 98020a203aSopenharmony_ci std::unique_lock<std::mutex> uniqueLock(mut); 99020a203aSopenharmony_ci if (records.find(key) == records.end()) { 100020a203aSopenharmony_ci throw std::invalid_argument("non-existing id"); 101020a203aSopenharmony_ci } 102020a203aSopenharmony_ci} 103020a203aSopenharmony_ci 104020a203aSopenharmony_cilong long SceneTimerOhImpl::GetCurTimeStamp() 105020a203aSopenharmony_ci{ 106020a203aSopenharmony_ci milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch()); 107020a203aSopenharmony_ci return ms.count(); 108020a203aSopenharmony_ci} 109020a203aSopenharmony_ci 110020a203aSopenharmony_ci/* already have lock */ 111020a203aSopenharmony_civoid SceneTimerOhImpl::CheckRecordsAndTrigger() 112020a203aSopenharmony_ci{ 113020a203aSopenharmony_ci long long nowMs = GetCurTimeStamp(); 114020a203aSopenharmony_ci for (std::map<int, long long>::iterator it = records.begin(); it != records.end();) { 115020a203aSopenharmony_ci long long expire = it->second; 116020a203aSopenharmony_ci int key = it->first; 117020a203aSopenharmony_ci if (nowMs >= expire) { 118020a203aSopenharmony_ci it = records.erase(it); 119020a203aSopenharmony_ci TriggerCallbak(key); 120020a203aSopenharmony_ci } else { 121020a203aSopenharmony_ci it++; 122020a203aSopenharmony_ci } 123020a203aSopenharmony_ci } 124020a203aSopenharmony_ci} 125020a203aSopenharmony_ci 126020a203aSopenharmony_ciint SceneTimerOhImpl::BuildRecordKey(int user, int id) 127020a203aSopenharmony_ci{ 128020a203aSopenharmony_ci if (user >= maxUserId) { 129020a203aSopenharmony_ci throw std::invalid_argument("exceeds max user id"); 130020a203aSopenharmony_ci } 131020a203aSopenharmony_ci if (id >= maxRecordPerUser) { 132020a203aSopenharmony_ci throw std::invalid_argument("exceeds max id per user"); 133020a203aSopenharmony_ci } 134020a203aSopenharmony_ci int ret = user * maxRecordPerUser + id; 135020a203aSopenharmony_ci return ret; 136020a203aSopenharmony_ci} 137020a203aSopenharmony_ci 138020a203aSopenharmony_cilong long SceneTimerOhImpl::CalcExpireTimeStamp(long delay) 139020a203aSopenharmony_ci{ 140020a203aSopenharmony_ci long long nowMs = GetCurTimeStamp(); 141020a203aSopenharmony_ci long long expire = nowMs + delay; 142020a203aSopenharmony_ci return expire; 143020a203aSopenharmony_ci} 144020a203aSopenharmony_ci 145020a203aSopenharmony_civoid SceneTimerOhImpl::TriggerCallbak(int recordKey) 146020a203aSopenharmony_ci{ 147020a203aSopenharmony_ci int user = ExtractUserFromRecordKey(recordKey); 148020a203aSopenharmony_ci int id = ExtractIdFromRecordKey(recordKey); 149020a203aSopenharmony_ci try { 150020a203aSopenharmony_ci ICb* cb = callbacks.at(user); 151020a203aSopenharmony_ci if (cb == nullptr) { 152020a203aSopenharmony_ci HIVIEW_LOGE("SceneTimerImpl::TriggerCallbak cb is null"); 153020a203aSopenharmony_ci return; 154020a203aSopenharmony_ci } 155020a203aSopenharmony_ci cb->Expired(id); 156020a203aSopenharmony_ci } 157020a203aSopenharmony_ci catch (const std::out_of_range& outex) { 158020a203aSopenharmony_ci HIVIEW_LOGE("SceneTimerImpl::back id=%{public}d;user=%{public}d;key=%{public}d;", id, user, recordKey); 159020a203aSopenharmony_ci } 160020a203aSopenharmony_ci} 161020a203aSopenharmony_ci 162020a203aSopenharmony_ciint SceneTimerOhImpl::ExtractUserFromRecordKey(int key) 163020a203aSopenharmony_ci{ 164020a203aSopenharmony_ci return key / maxRecordPerUser; 165020a203aSopenharmony_ci} 166020a203aSopenharmony_ci 167020a203aSopenharmony_ciint SceneTimerOhImpl::ExtractIdFromRecordKey(int key) 168020a203aSopenharmony_ci{ 169020a203aSopenharmony_ci return key % maxRecordPerUser; 170020a203aSopenharmony_ci} 171020a203aSopenharmony_ci 172020a203aSopenharmony_civoid SceneTimerOhImpl::RemoveRecordAndNotify(int key) 173020a203aSopenharmony_ci{ 174020a203aSopenharmony_ci std::unique_lock<std::mutex> uniqueLock(mut); 175020a203aSopenharmony_ci records.erase(records.find(key)); 176020a203aSopenharmony_ci cv.notify_all(); 177020a203aSopenharmony_ci} 178020a203aSopenharmony_ci} // HiviewDFX 179020a203aSopenharmony_ci} // OHOS