13f4cbf05Sopenharmony_ci/*
23f4cbf05Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
33f4cbf05Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43f4cbf05Sopenharmony_ci * you may not use this file except in compliance with the License.
53f4cbf05Sopenharmony_ci * You may obtain a copy of the License at
63f4cbf05Sopenharmony_ci *
73f4cbf05Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
83f4cbf05Sopenharmony_ci *
93f4cbf05Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103f4cbf05Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113f4cbf05Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123f4cbf05Sopenharmony_ci * See the License for the specific language governing permissions and
133f4cbf05Sopenharmony_ci * limitations under the License.
143f4cbf05Sopenharmony_ci */
153f4cbf05Sopenharmony_ci
163f4cbf05Sopenharmony_ci#include "timer_event_handler.h"
173f4cbf05Sopenharmony_ci#include "event_reactor.h"
183f4cbf05Sopenharmony_ci#include "common_timer_errors.h"
193f4cbf05Sopenharmony_ci#include "utils_log.h"
203f4cbf05Sopenharmony_ci
213f4cbf05Sopenharmony_ci#include <unistd.h>
223f4cbf05Sopenharmony_ci#include <sys/timerfd.h>
233f4cbf05Sopenharmony_ci
243f4cbf05Sopenharmony_cinamespace OHOS {
253f4cbf05Sopenharmony_cinamespace Utils {
263f4cbf05Sopenharmony_ci
273f4cbf05Sopenharmony_ci// Unit of measure conversion
283f4cbf05Sopenharmony_cistatic const int MILLI_TO_BASE = 1000;
293f4cbf05Sopenharmony_cistatic const int NANO_TO_BASE = 1000000000;
303f4cbf05Sopenharmony_ciconstexpr int MILLI_TO_NANO = NANO_TO_BASE / MILLI_TO_BASE;
313f4cbf05Sopenharmony_ci
323f4cbf05Sopenharmony_ciTimerEventHandler::TimerEventHandler(EventReactor* p, uint32_t timeout /* ms */, bool once)
333f4cbf05Sopenharmony_ci    : EventHandler(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC), p),
343f4cbf05Sopenharmony_ci      once_(once),
353f4cbf05Sopenharmony_ci      interval_(timeout),
363f4cbf05Sopenharmony_ci      callback_()
373f4cbf05Sopenharmony_ci{
383f4cbf05Sopenharmony_ci}
393f4cbf05Sopenharmony_ci
403f4cbf05Sopenharmony_ciTimerEventHandler::~TimerEventHandler()
413f4cbf05Sopenharmony_ci{
423f4cbf05Sopenharmony_ci    close(GetHandle());
433f4cbf05Sopenharmony_ci    SetHandle(INVALID_TIMER_FD);
443f4cbf05Sopenharmony_ci}
453f4cbf05Sopenharmony_ci
463f4cbf05Sopenharmony_ciuint32_t TimerEventHandler::Initialize()
473f4cbf05Sopenharmony_ci{
483f4cbf05Sopenharmony_ci    if ((GetHandle() == INVALID_TIMER_FD)) {
493f4cbf05Sopenharmony_ci        UTILS_LOGE("TimerEventHandler::initialize failed.");
503f4cbf05Sopenharmony_ci        return TIMER_ERR_INVALID_VALUE;
513f4cbf05Sopenharmony_ci    }
523f4cbf05Sopenharmony_ci
533f4cbf05Sopenharmony_ci    struct itimerspec newValue = {{0, 0}, {0, 0}};
543f4cbf05Sopenharmony_ci    timespec now{0, 0};
553f4cbf05Sopenharmony_ci    if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
563f4cbf05Sopenharmony_ci        UTILS_LOGE("Failed clock_gettime.");
573f4cbf05Sopenharmony_ci        return TIMER_ERR_DEAL_FAILED;
583f4cbf05Sopenharmony_ci    }
593f4cbf05Sopenharmony_ci
603f4cbf05Sopenharmony_ci    // next time out time is now + interval
613f4cbf05Sopenharmony_ci    newValue.it_value.tv_sec = now.tv_sec + interval_ / MILLI_TO_BASE;
623f4cbf05Sopenharmony_ci    newValue.it_value.tv_nsec = now.tv_nsec + (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
633f4cbf05Sopenharmony_ci    if (newValue.it_value.tv_nsec >= NANO_TO_BASE) {
643f4cbf05Sopenharmony_ci        newValue.it_value.tv_sec += 1;
653f4cbf05Sopenharmony_ci        newValue.it_value.tv_nsec = newValue.it_value.tv_nsec % NANO_TO_BASE;
663f4cbf05Sopenharmony_ci    }
673f4cbf05Sopenharmony_ci
683f4cbf05Sopenharmony_ci    if (once_) {
693f4cbf05Sopenharmony_ci        // interval, 0 means time out only once
703f4cbf05Sopenharmony_ci        newValue.it_interval.tv_sec  = 0;
713f4cbf05Sopenharmony_ci        newValue.it_interval.tv_nsec = 0;
723f4cbf05Sopenharmony_ci    } else {
733f4cbf05Sopenharmony_ci        // interval
743f4cbf05Sopenharmony_ci        newValue.it_interval.tv_sec  = interval_ / MILLI_TO_BASE;
753f4cbf05Sopenharmony_ci        newValue.it_interval.tv_nsec = (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
763f4cbf05Sopenharmony_ci    }
773f4cbf05Sopenharmony_ci
783f4cbf05Sopenharmony_ci    if (timerfd_settime(GetHandle(), TFD_TIMER_ABSTIME, &newValue, nullptr) == -1) {
793f4cbf05Sopenharmony_ci        UTILS_LOGE("Failed in timerFd_settime");
803f4cbf05Sopenharmony_ci        return TIMER_ERR_DEAL_FAILED;
813f4cbf05Sopenharmony_ci    }
823f4cbf05Sopenharmony_ci
833f4cbf05Sopenharmony_ci    SetReadCallback([this] { this->TimeOut(); });
843f4cbf05Sopenharmony_ci    EnableRead();
853f4cbf05Sopenharmony_ci    return TIMER_ERR_OK;
863f4cbf05Sopenharmony_ci}
873f4cbf05Sopenharmony_ci
883f4cbf05Sopenharmony_civoid TimerEventHandler::Uninitialize()
893f4cbf05Sopenharmony_ci{
903f4cbf05Sopenharmony_ci    DisableAll();
913f4cbf05Sopenharmony_ci}
923f4cbf05Sopenharmony_ci
933f4cbf05Sopenharmony_civoid TimerEventHandler::TimeOut()
943f4cbf05Sopenharmony_ci{
953f4cbf05Sopenharmony_ci    if (GetHandle() == INVALID_TIMER_FD) {
963f4cbf05Sopenharmony_ci        UTILS_LOGE("timerFd_ is invalid.");
973f4cbf05Sopenharmony_ci        return;
983f4cbf05Sopenharmony_ci    }
993f4cbf05Sopenharmony_ci    uint64_t expirations = 0;
1003f4cbf05Sopenharmony_ci    ssize_t n = ::read(GetHandle(), &expirations, sizeof(expirations));
1013f4cbf05Sopenharmony_ci    if (n != sizeof(expirations)) {
1023f4cbf05Sopenharmony_ci        UTILS_LOGE("epoll_loop::on_timer() reads %{public}d bytes instead of 8, errno=%{public}d", static_cast<int>(n),
1033f4cbf05Sopenharmony_ci            errno);
1043f4cbf05Sopenharmony_ci    }
1053f4cbf05Sopenharmony_ci    if (callback_) {
1063f4cbf05Sopenharmony_ci        callback_(GetHandle());
1073f4cbf05Sopenharmony_ci    }
1083f4cbf05Sopenharmony_ci}
1093f4cbf05Sopenharmony_ci
1103f4cbf05Sopenharmony_ci} // namespace Utils
1113f4cbf05Sopenharmony_ci} // namespace OHOS
112