* 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("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;
}
}
}
}
}