1 /*
2 * Copyright (c) 2021 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_timer.h"
17
18 #include <thread>
19
20 #include "securec.h"
21
22 namespace OHOS {
23 namespace DistributedHardware {
24 namespace {
25 const int32_t MILL_SECONDS_PER_SECOND = 1000;
26 }
DmTimer(std::string & name)27 DmTimer::DmTimer(std::string &name)
28 {
29 mStatus_ = DmTimerStatus::DM_STATUS_INIT;
30 mTimeOutSec_ = 0;
31 mHandle_ = nullptr;
32 mHandleData_ = nullptr;
33 (void)memset_s(mTimeFd_, sizeof(mTimeFd_), 0, sizeof(mTimeFd_));
34 (void)memset_s(&mEv_, sizeof(mEv_), 0, sizeof(mEv_));
35 (void)memset_s(mEvents_, sizeof(mEvents_), 0, sizeof(mEvents_));
36 mEpFd_ = 0;
37 mTimerName_ = name;
38 }
39
~DmTimer()40 DmTimer::~DmTimer()
41 {
42 DMLOG(DM_LOG_INFO, "DmTimer %s Destory in", mTimerName_.c_str());
43 Release();
44 }
45
Start(uint32_t timeOut,TimeoutHandle handle,void * data)46 DmTimerStatus DmTimer::Start(uint32_t timeOut, TimeoutHandle handle, void *data)
47 {
48 DMLOG(DM_LOG_INFO, "DmTimer %s start timeout(%d)", mTimerName_.c_str(), timeOut);
49 if (mStatus_ != DmTimerStatus::DM_STATUS_INIT) {
50 return DmTimerStatus::DM_STATUS_BUSY;
51 }
52
53 mTimeOutSec_ = timeOut;
54 mHandle_ = handle;
55 mHandleData_ = data;
56
57 if (CreateTimeFd()) {
58 return DmTimerStatus::DM_STATUS_CREATE_ERROR;
59 }
60
61 mStatus_ = DmTimerStatus::DM_STATUS_RUNNING;
62 mThread_ = std::thread(&DmTimer::WiteforTimeout, this);
63 mThread_.detach();
64
65 return mStatus_;
66 }
67
Stop(int32_t code)68 void DmTimer::Stop(int32_t code)
69 {
70 DMLOG(DM_LOG_INFO, "DmTimer %s Stop code (%d)", mTimerName_.c_str(), code);
71 if (mTimeFd_[1]) {
72 char event = 'S';
73 if (write(mTimeFd_[1], &event, 1) < 0) {
74 DMLOG(DM_LOG_ERROR, "DmTimer %s Stop timer failed, errno %d", mTimerName_.c_str(), errno);
75 return;
76 }
77 DMLOG(DM_LOG_INFO, "DmTimer %s Stop success", mTimerName_.c_str());
78 }
79
80 return;
81 }
82
WiteforTimeout()83 void DmTimer::WiteforTimeout()
84 {
85 DMLOG(DM_LOG_INFO, "DmTimer %s start timer at (%d)s", mTimerName_.c_str(), mTimeOutSec_);
86
87 int32_t nfds = epoll_wait(mEpFd_, mEvents_, MAXEVENTS, mTimeOutSec_ * MILL_SECONDS_PER_SECOND);
88 if (nfds < 0) {
89 DMLOG(DM_LOG_ERROR, "DmTimer %s epoll_wait returned n=%d, error: %d", mTimerName_.c_str(), nfds, errno);
90 }
91
92 char event = 0;
93 if (nfds > 0) {
94 if (mEvents_[0].events & EPOLLIN) {
95 int num = read(mTimeFd_[0], &event, 1);
96 if (num > 0) {
97 DMLOG(DM_LOG_INFO, "DmTimer %s exit with event %d", mTimerName_.c_str(), event);
98 } else {
99 DMLOG(DM_LOG_ERROR, "DmTimer %s exit with errno %d", mTimerName_.c_str(), errno);
100 }
101 }
102 Release();
103 return;
104 }
105
106 mHandle_(mHandleData_);
107 Release();
108
109 DMLOG(DM_LOG_ERROR, "DmTimer %s end timer at (%d)s", mTimerName_.c_str(), mTimeOutSec_);
110 return;
111 }
112
CreateTimeFd()113 int32_t DmTimer::CreateTimeFd()
114 {
115 DMLOG(DM_LOG_INFO, "DmTimer %s creatTimeFd", mTimerName_.c_str());
116 int ret = 0;
117
118 ret = pipe(mTimeFd_);
119 if (ret < 0) {
120 DMLOG(DM_LOG_ERROR, "DmTimer %s CreateTimeFd fail:(%d) errno(%d)", mTimerName_.c_str(), ret, errno);
121 return ret;
122 }
123
124 mEv_.data.fd = mTimeFd_[0];
125 mEv_.events = EPOLLIN | EPOLLET;
126 mEpFd_ = epoll_create(MAXEVENTS);
127 ret = epoll_ctl(mEpFd_, EPOLL_CTL_ADD, mTimeFd_[0], &mEv_);
128 if (ret != 0) {
129 Release();
130 }
131
132 return ret;
133 }
134
Release()135 void DmTimer::Release()
136 {
137 DMLOG(DM_LOG_INFO, "DmTimer %s Release in", mTimerName_.c_str());
138 if (mStatus_ == DmTimerStatus::DM_STATUS_INIT) {
139 DMLOG(DM_LOG_INFO, "DmTimer %s already Release", mTimerName_.c_str());
140 return;
141 }
142 mStatus_ = DmTimerStatus::DM_STATUS_INIT;
143 close(mTimeFd_[0]);
144 close(mTimeFd_[1]);
145 if (mEpFd_ >= 0) {
146 close(mEpFd_);
147 }
148 mTimeFd_[0] = 0;
149 mTimeFd_[1] = 0;
150 mEpFd_ = 0;
151 }
152 }
153 }
154