1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "dm_log.h"
17#include "dm_timer.h"
18
19#include <pthread.h>
20#include <thread>
21
22namespace OHOS {
23namespace DistributedHardware {
24
25constexpr const char* TIMER_RUNNING = "TimerRunning";
26constexpr int32_t ERR_DM_INPUT_PARA_INVALID = -20006;
27constexpr int32_t DM_OK = 0;
28
29Timer::Timer(std::string name, int32_t time, TimerCallback callback)
30    : timerName_(name), expire_(steadyClock::now()), state_(true), timeOut_(time), callback_(callback) {};
31
32DmTimer::DmTimer()
33{
34}
35
36DmTimer::~DmTimer()
37{
38    LOGI("DmTimer destructor");
39    DeleteAll();
40    if (timerState_) {
41        std::unique_lock<std::mutex> locker(timerStateMutex_);
42        stopTimerCondition_.wait(locker, [this] { return static_cast<bool>(!timerState_); });
43    }
44}
45
46int32_t DmTimer::StartTimer(std::string name, int32_t timeOut, TimerCallback callback)
47{
48    LOGI("DmTimer StartTimer %{public}s", name.c_str());
49    if (name.empty() || timeOut <= MIN_TIME_OUT || timeOut > MAX_TIME_OUT || callback == nullptr) {
50        LOGI("DmTimer StartTimer input value invalid");
51        return ERR_DM_INPUT_PARA_INVALID;
52    }
53
54    std::shared_ptr<Timer> timer = std::make_shared<Timer>(name, timeOut, callback);
55    {
56        std::lock_guard<std::mutex> locker(timerMutex_);
57        timerQueue_.push(timer);
58        timerVec_.emplace_back(timer);
59    }
60
61    if (timerState_) {
62        LOGI("DmTimer is running");
63        return DM_OK;
64    }
65
66    TimerRunning();
67    {
68        std::unique_lock<std::mutex> locker(timerStateMutex_);
69        runTimerCondition_.wait(locker, [this] { return static_cast<bool>(timerState_); });
70    }
71    return DM_OK;
72}
73
74int32_t DmTimer::DeleteTimer(std::string timerName)
75{
76    if (timerName.empty()) {
77        LOGE("DmTimer DeleteTimer timer is null");
78        return ERR_DM_INPUT_PARA_INVALID;
79    }
80
81    LOGI("DmTimer DeleteTimer name %{public}s", timerName.c_str());
82    std::lock_guard<std::mutex> locker(timerMutex_);
83    for (auto iter : timerVec_) {
84        if (iter != nullptr && iter->timerName_ == timerName) {
85            iter->state_ = false;
86        }
87    }
88    return DM_OK;
89}
90
91int32_t DmTimer::DeleteAll()
92{
93    LOGI("DmTimer DeleteAll start");
94    std::lock_guard<std::mutex> locker(timerMutex_);
95    for (auto iter : timerVec_) {
96        LOGI("DmTimer DeleteAll timer.name = %{public}s ", iter->timerName_.c_str());
97        iter->state_ = false;
98    }
99    return DM_OK;
100}
101
102int32_t DmTimer::TimerRunning()
103{
104    int32_t ret = pthread_setname_np(pthread_self(), TIMER_RUNNING);
105    if (ret != DM_OK) {
106        LOGE("TimerRunning setname failed.");
107    }
108    std::thread([this] () {
109        {
110            timerState_ = true;
111            std::unique_lock<std::mutex> locker(timerStateMutex_);
112            runTimerCondition_.notify_one();
113        }
114        while (!timerQueue_.empty() && timerState_) {
115            std::this_thread::sleep_for(std::chrono::milliseconds(DELAY_TICK_MILLSECONDS));
116            timerMutex_.lock();
117            while (!timerQueue_.empty() && (std::chrono::duration_cast<timerDuration>(steadyClock::now() -
118                timerQueue_.top()->expire_).count() / MILLISECOND_TO_SECOND >= timerQueue_.top()->timeOut_ ||
119                !timerQueue_.top()->state_)) {
120                std::string name = timerQueue_.top()->timerName_;
121                LOGI("DmTimer TimerRunning timer.name = %{public}s", name.c_str());
122                TimerCallback callBack = nullptr;
123                if (timerQueue_.top()->state_) {
124                    callBack = timerQueue_.top()->callback_;
125                }
126                timerQueue_.pop();
127                DeleteVector(name);
128                timerMutex_.unlock();
129                if (callBack != nullptr) {
130                    callBack(name);
131                }
132                timerMutex_.lock();
133                if (timerQueue_.empty()) {
134                    break;
135                }
136            }
137            timerMutex_.unlock();
138        }
139        {
140            timerState_ = false;
141            std::unique_lock<std::mutex> locker(timerStateMutex_);
142            stopTimerCondition_.notify_one();
143        }
144    }).detach();
145    return DM_OK;
146}
147
148void DmTimer::DeleteVector(std::string name)
149{
150    for (auto iter = timerVec_.begin(); iter != timerVec_.end(); ++iter) {
151        if ((*iter)->timerName_ == name) {
152            timerVec_.erase(iter);
153            break;
154        }
155    }
156}
157}
158}