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