1 /*
2  * Copyright (c) 2022-2024 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 namespace {
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 }
29 
Timer(std::string name,int32_t time,TimerCallback callback)30 Timer::Timer(std::string name, int32_t time, TimerCallback callback)
31     : timerName_(name), expire_(steadyClock::now()), state_(true), timeOut_(time), callback_(callback) {};
32 
DmTimer()33 DmTimer::DmTimer()
34 {
35 }
36 
~DmTimer()37 DmTimer::~DmTimer()
38 {
39     LOGI("DmTimer destructor");
40     DeleteAll();
41     if (timerState_) {
42         std::unique_lock<std::mutex> locker(timerStateMutex_);
43         stopTimerCondition_.wait(locker, [this] { return static_cast<bool>(!timerState_); });
44     }
45 }
46 
StartTimer(std::string name,int32_t timeOut,TimerCallback callback)47 int32_t DmTimer::StartTimer(std::string name, int32_t timeOut, TimerCallback callback)
48 {
49     LOGI("DmTimer StartTimer %{public}s", name.c_str());
50     if (name.empty() || timeOut <= MIN_TIME_OUT || timeOut > MAX_TIME_OUT || callback == nullptr) {
51         LOGI("DmTimer StartTimer input value invalid");
52         return ERR_DM_INPUT_PARA_INVALID;
53     }
54 
55     std::shared_ptr<Timer> timer = std::make_shared<Timer>(name, timeOut, callback);
56     {
57         std::lock_guard<std::mutex> locker(timerMutex_);
58         timerQueue_.push(timer);
59         timerVec_.emplace_back(timer);
60     }
61 
62     if (timerState_) {
63         LOGI("DmTimer is running");
64         return DM_OK;
65     }
66 
67     TimerRunning();
68     {
69         std::unique_lock<std::mutex> locker(timerStateMutex_);
70         runTimerCondition_.wait(locker, [this] { return static_cast<bool>(timerState_); });
71     }
72     return DM_OK;
73 }
74 
DeleteTimer(std::string timerName)75 int32_t DmTimer::DeleteTimer(std::string timerName)
76 {
77     if (timerName.empty()) {
78         LOGE("DmTimer DeleteTimer timer is null");
79         return ERR_DM_INPUT_PARA_INVALID;
80     }
81 
82     LOGI("DmTimer DeleteTimer name %{public}s", timerName.c_str());
83     std::lock_guard<std::mutex> locker(timerMutex_);
84     for (auto iter : timerVec_) {
85         if (iter != nullptr && iter->timerName_ == timerName) {
86             iter->state_ = false;
87         }
88     }
89     return DM_OK;
90 }
91 
DeleteAll()92 int32_t DmTimer::DeleteAll()
93 {
94     LOGI("DmTimer DeleteAll start");
95     std::lock_guard<std::mutex> locker(timerMutex_);
96     for (auto iter : timerVec_) {
97         LOGI("DmTimer DeleteAll timer.name = %{public}s ", iter->timerName_.c_str());
98         iter->state_ = false;
99     }
100     return DM_OK;
101 }
102 
TimerRunning()103 int32_t DmTimer::TimerRunning()
104 {
105     int32_t ret = pthread_setname_np(pthread_self(), TIMER_RUNNING);
106     if (ret != DM_OK) {
107         LOGE("TimerRunning setname failed.");
108     }
109     std::thread([this] () {
110         {
111             timerState_ = true;
112             std::unique_lock<std::mutex> locker(timerStateMutex_);
113             runTimerCondition_.notify_one();
114         }
115         while (!timerQueue_.empty() && timerState_) {
116             std::this_thread::sleep_for(std::chrono::milliseconds(DELAY_TICK_MILLSECONDS));
117             timerMutex_.lock();
118             while (!timerQueue_.empty() && (std::chrono::duration_cast<timerDuration>(steadyClock::now() -
119                 timerQueue_.top()->expire_).count() / MILLISECOND_TO_SECOND >= timerQueue_.top()->timeOut_ ||
120                 !timerQueue_.top()->state_)) {
121                 std::string name = timerQueue_.top()->timerName_;
122                 LOGI("DmTimer TimerRunning timer.name = %{public}s", name.c_str());
123                 TimerCallback callBack = nullptr;
124                 if (timerQueue_.top()->state_) {
125                     callBack = timerQueue_.top()->callback_;
126                 }
127                 timerQueue_.pop();
128                 DeleteVector(name);
129                 timerMutex_.unlock();
130                 if (callBack != nullptr) {
131                     callBack(name);
132                 }
133                 timerMutex_.lock();
134                 if (timerQueue_.empty()) {
135                     break;
136                 }
137             }
138             timerMutex_.unlock();
139         }
140         {
141             timerState_ = false;
142             std::unique_lock<std::mutex> locker(timerStateMutex_);
143             stopTimerCondition_.notify_one();
144         }
145     }).detach();
146     return DM_OK;
147 }
148 
DeleteVector(std::string name)149 void DmTimer::DeleteVector(std::string name)
150 {
151     for (auto iter = timerVec_.begin(); iter != timerVec_.end(); ++iter) {
152         if ((*iter)->timerName_ == name) {
153             timerVec_.erase(iter);
154             break;
155         }
156     }
157 }
158 }
159 }