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 "timer_event_handler.h"
17 #include "event_reactor.h"
18 #include "event_handler.h"
19 #include "common_timer_errors.h"
20 #include "utils_log.h"
21
22 #include <unistd.h>
23 #include <sys/timerfd.h>
24
25 namespace OHOS {
26 namespace Utils {
27
28 // Unit of measure conversion
29 static const int MILLI_TO_BASE = 1000;
30 static const int NANO_TO_BASE = 1000000000;
31 constexpr int MILLI_TO_NANO = NANO_TO_BASE / MILLI_TO_BASE;
32
TimerEventHandler(EventReactor * p,uint32_t timeout,bool once)33 TimerEventHandler::TimerEventHandler(EventReactor* p, uint32_t timeout /* ms */, bool once)
34 : once_(once),
35 timerFd_(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC)),
36 interval_(timeout),
37 reactor_(p),
38 handler_(new EventHandler(timerFd_, p)),
39 callback_()
40 {
41 }
42
~TimerEventHandler()43 TimerEventHandler::~TimerEventHandler()
44 {
45 close(timerFd_);
46 timerFd_ = INVALID_TIMER_FD;
47 }
48
Initialize()49 uint32_t TimerEventHandler::Initialize()
50 {
51 if ((timerFd_ == INVALID_TIMER_FD) || (reactor_ == nullptr) || (handler_ == nullptr)) {
52 UTILS_LOGE("TimerEventHandler::initialize failed.");
53 return TIMER_ERR_INVALID_VALUE;
54 }
55
56 struct itimerspec newValue = {{0, 0}, {0, 0}};
57 timespec now{0, 0};
58 if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
59 UTILS_LOGE("Failed clock_gettime.");
60 return TIMER_ERR_DEAL_FAILED;
61 }
62
63 // next time out time is now + interval
64 newValue.it_value.tv_sec = now.tv_sec + interval_ / MILLI_TO_BASE;
65 newValue.it_value.tv_nsec = now.tv_nsec + (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
66 if (newValue.it_value.tv_nsec >= NANO_TO_BASE) {
67 newValue.it_value.tv_sec += 1;
68 newValue.it_value.tv_nsec = newValue.it_value.tv_nsec % NANO_TO_BASE;
69 }
70
71 if (once_) {
72 // interval, 0 means time out only once
73 newValue.it_interval.tv_sec = 0;
74 newValue.it_interval.tv_nsec = 0;
75 } else {
76 // interval
77 newValue.it_interval.tv_sec = interval_ / MILLI_TO_BASE;
78 newValue.it_interval.tv_nsec = (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
79 }
80
81 if (timerfd_settime(timerFd_, TFD_TIMER_ABSTIME, &newValue, nullptr) == -1) {
82 UTILS_LOGE("Failed in timerFd_settime");
83 return TIMER_ERR_DEAL_FAILED;
84 }
85
86 handler_->SetReadCallback(std::bind(&TimerEventHandler::TimeOut, this));
87 handler_->EnableRead();
88 return TIMER_ERR_OK;
89 }
90
Uninitialize()91 void TimerEventHandler::Uninitialize()
92 {
93 if (handler_ != nullptr) {
94 handler_->DisableAll();
95 }
96 }
97
TimeOut()98 void TimerEventHandler::TimeOut()
99 {
100 if (timerFd_ == INVALID_TIMER_FD) {
101 UTILS_LOGE("timerFd_ is invalid.");
102 return;
103 }
104 uint64_t expirations = 0;
105 ssize_t n = ::read(timerFd_, &expirations, sizeof(expirations));
106 if (n != sizeof(expirations)) {
107 UTILS_LOGE("epoll_loop::on_timer() reads %{public}d bytes instead of 8.", static_cast<int>(n));
108 }
109 if (callback_) {
110 callback_(timerFd_);
111 }
112 }
113
114 } // namespace Utils
115 } // namespace OHOS