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 
22 namespace OHOS {
23 namespace DistributedHardware {
24 
25 constexpr const char* TIMER_RUNNING = "TimerRunning";
26 constexpr int32_t ERR_DM_INPUT_PARA_INVALID = -20006;
27 constexpr int32_t DM_OK = 0;
28 
Timer(std::string name, int32_t time, TimerCallback callback)29 Timer::Timer(std::string name, int32_t time, TimerCallback callback)
30     : timerName_(name), expire_(steadyClock::now()), state_(true), timeOut_(time), callback_(callback) {};
31 
DmTimer()32 DmTimer::DmTimer()
33 {
34 }
35 
~DmTimer()36 DmTimer::~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 
StartTimer(std::string name, int32_t timeOut, TimerCallback callback)46 int32_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 
DeleteTimer(std::string timerName)74 int32_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 
DeleteAll()91 int32_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 
TimerRunning()102 int32_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 
DeleteVector(std::string name)148 void 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 }