1 /*
2 * Copyright (C) 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 "samgr_time_handler.h"
17 #include "sam_log.h"
18 #include <cinttypes>
19
20 using namespace std;
21 namespace OHOS {
22 namespace {
23 constexpr uint32_t INIT_NUM = 4;
24 constexpr uint32_t MAX_EVENT = 8;
25 constexpr int32_t RETRY_TIMES = 3;
26 }
27 SamgrTimeHandler* volatile SamgrTimeHandler::singleton = nullptr;
28 SamgrTimeHandler::Deletor SamgrTimeHandler::deletor;
29 static mutex mtx;
30
GetInstance()31 SamgrTimeHandler* SamgrTimeHandler::GetInstance()
32 {
33 if (singleton == nullptr) {
34 lock_guard<mutex> autoLock(mtx);
35 if (singleton == nullptr) {
36 singleton = new SamgrTimeHandler;
37 }
38 }
39 return singleton;
40 }
41
SamgrTimeHandler()42 SamgrTimeHandler::SamgrTimeHandler()
43 {
44 HILOGI("SamgrTimeHandler init start");
45 epollfd = epoll_create(INIT_NUM);
46 if (epollfd == -1) {
47 HILOGE("SamgrTimeHandler epoll_create error");
48 }
49 flag = false;
50 StartThread();
51 }
52
StartThread()53 void SamgrTimeHandler::StartThread()
54 {
55 std::function<void()> func = [this]() {
56 HILOGI("SamgrTimeHandler thread start");
57 struct epoll_event events[MAX_EVENT];
58 while (!this->timeFunc.IsEmpty()) {
59 int number = epoll_wait(this->epollfd, events, MAX_EVENT, -1);
60 OnTime((*this), number, events);
61 }
62 this->flag = false;
63 HILOGI("SamgrTimeHandler thread end");
64 };
65 std::thread t(func);
66 this->flag = true;
67 t.detach();
68 }
69
OnTime(SamgrTimeHandler & handle,int number,struct epoll_event events[])70 void SamgrTimeHandler::OnTime(SamgrTimeHandler &handle, int number, struct epoll_event events[])
71 {
72 if (number > 0) {
73 HILOGI("SamgrTimeHandler OnTime: %{public}d", number);
74 }
75 for (int i = 0; i < number; i++) {
76 uint32_t timerfd = events[i].data.u32;
77 uint64_t unused = 0;
78 HILOGI("SamgrTimeHandler timerfd: %{public}u", timerfd);
79 int ret = read(timerfd, &unused, sizeof(unused));
80 if (ret == sizeof(uint64_t)) {
81 TaskType funcTime;
82 bool hasFunction = handle.timeFunc.Find(timerfd, funcTime);
83 HILOGI("SamgrTimeHandler hasFunction: %{public}d", hasFunction);
84 funcTime();
85 handle.timeFunc.Erase(timerfd);
86 epoll_ctl(this->epollfd, EPOLL_CTL_DEL, timerfd, nullptr);
87 ::close(timerfd);
88 }
89 }
90 }
91
~SamgrTimeHandler()92 SamgrTimeHandler::~SamgrTimeHandler()
93 {
94 auto closeFunc = [this](uint32_t fd) {
95 epoll_ctl(this->epollfd, EPOLL_CTL_DEL, fd, nullptr);
96 ::close(fd);
97 };
98 timeFunc.Clear(closeFunc);
99 ::close(epollfd);
100 }
101
CreateAndRetry()102 int SamgrTimeHandler::CreateAndRetry()
103 {
104 for (int32_t i = 0; i < RETRY_TIMES; i++) {
105 int timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
106 if (timerfd != -1) {
107 return timerfd;
108 }
109 HILOGE("timerfd_create set alarm err: %{public}s", strerror(errno));
110 }
111 return -1;
112 }
113
PostTask(TaskType func,uint64_t delayTime)114 bool SamgrTimeHandler::PostTask(TaskType func, uint64_t delayTime)
115 {
116 HILOGI("SamgrTimeHandler postTask start: %{public}" PRId64 "s", delayTime);
117 int timerfd = CreateAndRetry();
118 if (timerfd == -1) {
119 timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
120 if (timerfd == -1) {
121 HILOGE("timerfd_create fail : %{public}s", strerror(errno));
122 return false;
123 }
124 }
125 epoll_event event {};
126 event.events = EPOLLIN | EPOLLWAKEUP;
127 event.data.u32 = static_cast<uint32_t>(timerfd);
128 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &event) == -1) {
129 HILOGE("epoll_ctl(EPOLL_CTL_ADD) failed : %{public}s", strerror(errno));
130 ::close(timerfd);
131 return false;
132 }
133 struct itimerspec newValue = {};
134 newValue.it_value.tv_sec = static_cast<int64_t>(delayTime);
135 newValue.it_value.tv_nsec = 0;
136 newValue.it_interval.tv_sec = 0;
137 newValue.it_interval.tv_nsec = 0;
138
139 if (timerfd_settime(timerfd, 0, &newValue, NULL) == -1) {
140 HILOGE("timerfd_settime failed : %{public}s", strerror(errno));
141 ::close(timerfd);
142 return false;
143 }
144 timeFunc.EnsureInsert(timerfd, func);
145 if (!flag) {
146 StartThread();
147 }
148 return true;
149 }
150 } // namespace OHOS