• 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 "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