/* * Copyright (c) 2022-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "dm_log.h" #include "dm_timer.h" #include <pthread.h> #include <thread> namespace OHOS { namespace DistributedHardware { namespace { constexpr const char* TIMER_RUNNING = "TimerRunning"; constexpr int32_t ERR_DM_INPUT_PARA_INVALID = -20006; constexpr int32_t DM_OK = 0; } Timer::Timer(std::string name, int32_t time, TimerCallback callback) : timerName_(name), expire_(steadyClock::now()), state_(true), timeOut_(time), callback_(callback) {}; DmTimer::DmTimer() { } DmTimer::~DmTimer() { LOGI("DmTimer destructor"); DeleteAll(); if (timerState_) { std::unique_lock<std::mutex> locker(timerStateMutex_); stopTimerCondition_.wait(locker, [this] { return static_cast<bool>(!timerState_); }); } } int32_t DmTimer::StartTimer(std::string name, int32_t timeOut, TimerCallback callback) { LOGI("DmTimer StartTimer %{public}s", name.c_str()); if (name.empty() || timeOut <= MIN_TIME_OUT || timeOut > MAX_TIME_OUT || callback == nullptr) { LOGI("DmTimer StartTimer input value invalid"); return ERR_DM_INPUT_PARA_INVALID; } std::shared_ptr<Timer> timer = std::make_shared<Timer>(name, timeOut, callback); { std::lock_guard<std::mutex> locker(timerMutex_); timerQueue_.push(timer); timerVec_.emplace_back(timer); } if (timerState_) { LOGI("DmTimer is running"); return DM_OK; } TimerRunning(); { std::unique_lock<std::mutex> locker(timerStateMutex_); runTimerCondition_.wait(locker, [this] { return static_cast<bool>(timerState_); }); } return DM_OK; } int32_t DmTimer::DeleteTimer(std::string timerName) { if (timerName.empty()) { LOGE("DmTimer DeleteTimer timer is null"); return ERR_DM_INPUT_PARA_INVALID; } LOGI("DmTimer DeleteTimer name %{public}s", timerName.c_str()); std::lock_guard<std::mutex> locker(timerMutex_); for (auto iter : timerVec_) { if (iter != nullptr && iter->timerName_ == timerName) { iter->state_ = false; } } return DM_OK; } int32_t DmTimer::DeleteAll() { LOGI("DmTimer DeleteAll start"); std::lock_guard<std::mutex> locker(timerMutex_); for (auto iter : timerVec_) { LOGI("DmTimer DeleteAll timer.name = %{public}s ", iter->timerName_.c_str()); iter->state_ = false; } return DM_OK; } int32_t DmTimer::TimerRunning() { int32_t ret = pthread_setname_np(pthread_self(), TIMER_RUNNING); if (ret != DM_OK) { LOGE("TimerRunning setname failed."); } std::thread([this] () { { timerState_ = true; std::unique_lock<std::mutex> locker(timerStateMutex_); runTimerCondition_.notify_one(); } while (!timerQueue_.empty() && timerState_) { std::this_thread::sleep_for(std::chrono::milliseconds(DELAY_TICK_MILLSECONDS)); timerMutex_.lock(); while (!timerQueue_.empty() && (std::chrono::duration_cast<timerDuration>(steadyClock::now() - timerQueue_.top()->expire_).count() / MILLISECOND_TO_SECOND >= timerQueue_.top()->timeOut_ || !timerQueue_.top()->state_)) { std::string name = timerQueue_.top()->timerName_; LOGI("DmTimer TimerRunning timer.name = %{public}s", name.c_str()); TimerCallback callBack = nullptr; if (timerQueue_.top()->state_) { callBack = timerQueue_.top()->callback_; } timerQueue_.pop(); DeleteVector(name); timerMutex_.unlock(); if (callBack != nullptr) { callBack(name); } timerMutex_.lock(); if (timerQueue_.empty()) { break; } } timerMutex_.unlock(); } { timerState_ = false; std::unique_lock<std::mutex> locker(timerStateMutex_); stopTimerCondition_.notify_one(); } }).detach(); return DM_OK; } void DmTimer::DeleteVector(std::string name) { for (auto iter = timerVec_.begin(); iter != timerVec_.end(); ++iter) { if ((*iter)->timerName_ == name) { timerVec_.erase(iter); break; } } } } }