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 24namespace OHOS { 25namespace Utils { 26 27// Unit of measure conversion 28static const int MILLI_TO_BASE = 1000; 29static const int NANO_TO_BASE = 1000000000; 30constexpr int MILLI_TO_NANO = NANO_TO_BASE / MILLI_TO_BASE; 31 32TimerEventHandler::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 40TimerEventHandler::~TimerEventHandler() 41{ 42 close(GetHandle()); 43 SetHandle(INVALID_TIMER_FD); 44} 45 46uint32_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([this] { this->TimeOut(); }); 84 EnableRead(); 85 return TIMER_ERR_OK; 86} 87 88void TimerEventHandler::Uninitialize() 89{ 90 DisableAll(); 91} 92 93void 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, errno=%{public}d", static_cast<int>(n), 103 errno); 104 } 105 if (callback_) { 106 callback_(GetHandle()); 107 } 108} 109 110} // namespace Utils 111} // namespace OHOS 112