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 samgr::mutex mtx;
30
GetInstance()31 SamgrTimeHandler* SamgrTimeHandler::GetInstance()
32 {
33 if (singleton == nullptr) {
34 lock_guard<samgr::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 }
50
StartThread()51 void SamgrTimeHandler::StartThread()
52 {
53 std::function<void()> func = [this]() {
54 HILOGI("SamgrTimeHandler thread start");
55 struct epoll_event events[MAX_EVENT];
56 while (!this->timeFunc.IsEmpty()) {
57 int number = epoll_wait(this->epollfd, events, MAX_EVENT, -1);
58 OnTime((*this), number, events);
59 }
60 HILOGI("SamgrTimeHandler thread end");
61 };
62 std::thread t(func);
63 t.detach();
64 }
65
OnTime(SamgrTimeHandler & handle,int number,struct epoll_event events[])66 void SamgrTimeHandler::OnTime(SamgrTimeHandler &handle, int number, struct epoll_event events[])
67 {
68 if (number > 0) {
69 HILOGI("SamgrTimeHandler OnTime: %{public}d", number);
70 }
71 for (int i = 0; i < number; i++) {
72 uint32_t timerfd = events[i].data.u32;
73 uint64_t unused = 0;
74 HILOGI("SamgrTimeHandler timerfd: %{public}u", timerfd);
75 int ret = read(timerfd, &unused, sizeof(unused));
76 if (ret == sizeof(uint64_t)) {
77 TaskType funcTime;
78 bool hasFunction = handle.timeFunc.Find(timerfd, funcTime);
79 HILOGI("SamgrTimeHandler hasFunction: %{public}d", hasFunction);
80 funcTime();
81 handle.timeFunc.Erase(timerfd);
82 epoll_ctl(this->epollfd, EPOLL_CTL_DEL, timerfd, nullptr);
83 ::close(timerfd);
84 }
85 }
86 }
87
~SamgrTimeHandler()88 SamgrTimeHandler::~SamgrTimeHandler()
89 {
90 auto closeFunc = [this](uint32_t fd) {
91 epoll_ctl(this->epollfd, EPOLL_CTL_DEL, fd, nullptr);
92 ::close(fd);
93 };
94 timeFunc.Clear(closeFunc);
95 ::close(epollfd);
96 }
97
CreateAndRetry()98 int SamgrTimeHandler::CreateAndRetry()
99 {
100 for (int32_t i = 0; i < RETRY_TIMES; i++) {
101 int timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
102 if (timerfd != -1) {
103 return timerfd;
104 }
105 HILOGE("timerfd_create set alarm err: %{public}s", strerror(errno));
106 }
107 return -1;
108 }
109
PostTask(TaskType func,uint64_t delayTime)110 bool SamgrTimeHandler::PostTask(TaskType func, uint64_t delayTime)
111 {
112 if (!func) {
113 HILOGE("SamgrTimeHandler PostTask failed, func is null");
114 return false;
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 auto isFirst = timeFunc.FirstInsert(timerfd, func);
145 if (isFirst) {
146 StartThread();
147 }
148 return true;
149 }
150 } // namespace OHOS