13f4cbf05Sopenharmony_ci/*
23f4cbf05Sopenharmony_ci * Copyright (c) 2023 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 <gtest/gtest.h>
173f4cbf05Sopenharmony_ci#include <sys/types.h>
183f4cbf05Sopenharmony_ci#include <sys/timerfd.h>
193f4cbf05Sopenharmony_ci#include <sys/prctl.h>
203f4cbf05Sopenharmony_ci#include "unistd.h"
213f4cbf05Sopenharmony_ci#include <cstdint>
223f4cbf05Sopenharmony_ci#include <cstring>
233f4cbf05Sopenharmony_ci#include <string>
243f4cbf05Sopenharmony_ci#include <thread>
253f4cbf05Sopenharmony_ci#include <mutex>
263f4cbf05Sopenharmony_ci#include <memory>
273f4cbf05Sopenharmony_ci#include <atomic>
283f4cbf05Sopenharmony_ci#include <algorithm>
293f4cbf05Sopenharmony_ci#include <list>
303f4cbf05Sopenharmony_ci#include <map>
313f4cbf05Sopenharmony_ci#include <functional>
323f4cbf05Sopenharmony_ci#include <iostream>
333f4cbf05Sopenharmony_ci#include "common_timer_errors.h"
343f4cbf05Sopenharmony_ci#include "common_event_sys_errors.h"
353f4cbf05Sopenharmony_ci#include "io_event_handler.h"
363f4cbf05Sopenharmony_ci#include "io_event_reactor.h"
373f4cbf05Sopenharmony_ci
383f4cbf05Sopenharmony_ciusing namespace testing::ext;
393f4cbf05Sopenharmony_ciusing namespace OHOS::Utils;
403f4cbf05Sopenharmony_ci
413f4cbf05Sopenharmony_cinamespace OHOS {
423f4cbf05Sopenharmony_cinamespace {
433f4cbf05Sopenharmony_ci
443f4cbf05Sopenharmony_ciclass UtilsEventTest : public testing::Test {
453f4cbf05Sopenharmony_cipublic:
463f4cbf05Sopenharmony_ci    static void SetUpTestCase(void) {}
473f4cbf05Sopenharmony_ci    static void TearDownTestCase(void) {}
483f4cbf05Sopenharmony_ci    void SetUp() {}
493f4cbf05Sopenharmony_ci    void TearDown() {}
503f4cbf05Sopenharmony_ci};
513f4cbf05Sopenharmony_ci
523f4cbf05Sopenharmony_ciint g_data = 0;
533f4cbf05Sopenharmony_civoid TimerCallback1()
543f4cbf05Sopenharmony_ci{
553f4cbf05Sopenharmony_ci    std::cout << "timer callback1 invoked." << std::endl;
563f4cbf05Sopenharmony_ci    g_data++;
573f4cbf05Sopenharmony_ci}
583f4cbf05Sopenharmony_ci
593f4cbf05Sopenharmony_cistatic const int MILLI_TO_BASE = 1000;
603f4cbf05Sopenharmony_cistatic const int NANO_TO_BASE = 1000000000;
613f4cbf05Sopenharmony_cistatic constexpr int MILLI_TO_NANO = NANO_TO_BASE / MILLI_TO_BASE;
623f4cbf05Sopenharmony_ciclass TimerFdHandler : public IOEventHandler {
633f4cbf05Sopenharmony_cipublic:
643f4cbf05Sopenharmony_ci    using TimerEventCallback = std::function<void()>;
653f4cbf05Sopenharmony_ci    TimerFdHandler(int fd, const TimerEventCallback& cb);
663f4cbf05Sopenharmony_ci    ~TimerFdHandler() {}
673f4cbf05Sopenharmony_ci    void TimeOut();
683f4cbf05Sopenharmony_ci    bool Initialize(uint32_t interval);
693f4cbf05Sopenharmony_ci    void Uninitialize();
703f4cbf05Sopenharmony_ci
713f4cbf05Sopenharmony_ciprivate:
723f4cbf05Sopenharmony_ci    TimerEventCallback timerCallback_;
733f4cbf05Sopenharmony_ci};
743f4cbf05Sopenharmony_ci
753f4cbf05Sopenharmony_civoid TestCallback() {}
763f4cbf05Sopenharmony_ci
773f4cbf05Sopenharmony_ci/*
783f4cbf05Sopenharmony_ci * @tc.name: testIOEventHandler001
793f4cbf05Sopenharmony_ci * @tc.desc: test basic interfaces of IOEventHandler.
803f4cbf05Sopenharmony_ci */
813f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testIOEventHandler001, TestSize.Level0)
823f4cbf05Sopenharmony_ci{
833f4cbf05Sopenharmony_ci    g_data = 0;
843f4cbf05Sopenharmony_ci    // 1. Create io event handler
853f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventHandler> handler = std::make_shared<IOEventHandler>(-1);
863f4cbf05Sopenharmony_ci
873f4cbf05Sopenharmony_ci    // 2. Set fd
883f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
893f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
903f4cbf05Sopenharmony_ci    handler->SetFd(fd);
913f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->GetFd(), fd);
923f4cbf05Sopenharmony_ci
933f4cbf05Sopenharmony_ci    // 3. Set callback
943f4cbf05Sopenharmony_ci    handler->SetCallback(&TestCallback);
953f4cbf05Sopenharmony_ci    EXPECT_NE(handler->GetCallback(), nullptr);
963f4cbf05Sopenharmony_ci
973f4cbf05Sopenharmony_ci    // 4. Set interest events
983f4cbf05Sopenharmony_ci    handler->SetEvents(Events::EVENT_READ | Events::EVENT_WRITE);
993f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->GetEvents(), Events::EVENT_READ | Events::EVENT_WRITE);
1003f4cbf05Sopenharmony_ci
1013f4cbf05Sopenharmony_ci    // 5. Check status
1023f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->Prev(), nullptr);
1033f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->Next(), nullptr);
1043f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->IsActive(), false);
1053f4cbf05Sopenharmony_ci
1063f4cbf05Sopenharmony_ci    // 6. disable events
1073f4cbf05Sopenharmony_ci    handler->DisableAll();
1083f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->GetEvents(), Events::EVENT_NONE);
1093f4cbf05Sopenharmony_ci
1103f4cbf05Sopenharmony_ci    // 7. enable events
1113f4cbf05Sopenharmony_ci    handler->EnableRead();
1123f4cbf05Sopenharmony_ci    handler->EnableWrite();
1133f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->GetEvents(), Events::EVENT_READ | Events::EVENT_WRITE);
1143f4cbf05Sopenharmony_ci
1153f4cbf05Sopenharmony_ci    // 8. disable one of the events
1163f4cbf05Sopenharmony_ci    handler->DisableWrite();
1173f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->GetEvents(), Events::EVENT_READ);
1183f4cbf05Sopenharmony_ci}
1193f4cbf05Sopenharmony_ci
1203f4cbf05Sopenharmony_ci/*
1213f4cbf05Sopenharmony_ci * @tc.name: testIOEventHandler002
1223f4cbf05Sopenharmony_ci * @tc.desc: test reactor-related interfaces of IOEventHandler.
1233f4cbf05Sopenharmony_ci */
1243f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testIOEventHandler002, TestSize.Level0)
1253f4cbf05Sopenharmony_ci{
1263f4cbf05Sopenharmony_ci    g_data = 0;
1273f4cbf05Sopenharmony_ci    // 1. Create io event handler
1283f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventHandler> handler = std::make_shared<IOEventHandler>(-1);
1293f4cbf05Sopenharmony_ci
1303f4cbf05Sopenharmony_ci    // 2. Set fd
1313f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
1323f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
1333f4cbf05Sopenharmony_ci    handler->SetFd(fd);
1343f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->GetFd(), fd);
1353f4cbf05Sopenharmony_ci
1363f4cbf05Sopenharmony_ci    // 3. Set callback
1373f4cbf05Sopenharmony_ci    handler->SetCallback(&TestCallback);
1383f4cbf05Sopenharmony_ci    EXPECT_NE(handler->GetCallback(), nullptr);
1393f4cbf05Sopenharmony_ci
1403f4cbf05Sopenharmony_ci    // 4. Set interest events
1413f4cbf05Sopenharmony_ci    handler->EnableRead();
1423f4cbf05Sopenharmony_ci    EXPECT_EQ(handler->GetEvents(), Events::EVENT_READ);
1433f4cbf05Sopenharmony_ci
1443f4cbf05Sopenharmony_ci    // 5. Create a reactor but not run
1453f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventReactor> reactor = std::make_shared<IOEventReactor>();
1463f4cbf05Sopenharmony_ci    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
1473f4cbf05Sopenharmony_ci
1483f4cbf05Sopenharmony_ci    // 6. Start handler
1493f4cbf05Sopenharmony_ci    handler->Start(reactor.get());
1503f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->FindHandler(handler.get()), EVENT_SYS_ERR_OK);
1513f4cbf05Sopenharmony_ci
1523f4cbf05Sopenharmony_ci    // 7. Change setting and update handler to the reactor
1533f4cbf05Sopenharmony_ci    handler->EnableWrite();
1543f4cbf05Sopenharmony_ci    EXPECT_TRUE(handler->Update(reactor.get()));
1553f4cbf05Sopenharmony_ci
1563f4cbf05Sopenharmony_ci    // 8. Remove the handler
1573f4cbf05Sopenharmony_ci    handler->Stop(reactor.get());
1583f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->FindHandler(handler.get()), EVENT_SYS_ERR_NOT_FOUND);
1593f4cbf05Sopenharmony_ci
1603f4cbf05Sopenharmony_ci    // 9. Add handler, then delete handler. handler will remove itself from the reactor during deconstruction.
1613f4cbf05Sopenharmony_ci    ASSERT_TRUE(handler->Start(reactor.get()));
1623f4cbf05Sopenharmony_ci    handler.reset();
1633f4cbf05Sopenharmony_ci}
1643f4cbf05Sopenharmony_ci
1653f4cbf05Sopenharmony_ci/*
1663f4cbf05Sopenharmony_ci * @tc.name: testIOEventReactor001
1673f4cbf05Sopenharmony_ci * @tc.desc: test basic interfaces of IOEventReactor.
1683f4cbf05Sopenharmony_ci */
1693f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testIOEventReactor001, TestSize.Level0)
1703f4cbf05Sopenharmony_ci{
1713f4cbf05Sopenharmony_ci    g_data = 0;
1723f4cbf05Sopenharmony_ci    // Get fd
1733f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
1743f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
1753f4cbf05Sopenharmony_ci
1763f4cbf05Sopenharmony_ci    // 1. Create io event handlers
1773f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventHandler> handler1 = std::make_shared<IOEventHandler>(fd);
1783f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventHandler> handler2 = std::make_shared<IOEventHandler>(fd);
1793f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventHandler> handler3 = std::make_shared<IOEventHandler>(-1); // -1: invalid fd
1803f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventHandler> handler4 = std::make_shared<IOEventHandler>(fd);
1813f4cbf05Sopenharmony_ci
1823f4cbf05Sopenharmony_ci    // 2. Create a reactor but not run
1833f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventReactor> reactor = std::make_shared<IOEventReactor>();
1843f4cbf05Sopenharmony_ci    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
1853f4cbf05Sopenharmony_ci
1863f4cbf05Sopenharmony_ci    // 3. Add handler
1873f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->AddHandler(handler1.get()), EVENT_SYS_ERR_OK);
1883f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->AddHandler(handler2.get()), EVENT_SYS_ERR_OK);
1893f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->AddHandler(handler3.get()), EVENT_SYS_ERR_OK);
1903f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->AddHandler(nullptr), EVENT_SYS_ERR_OK);
1913f4cbf05Sopenharmony_ci
1923f4cbf05Sopenharmony_ci    // 4. Add handler from the handler side.
1933f4cbf05Sopenharmony_ci    EXPECT_NE(handler1->Start(reactor.get()), EVENT_SYS_ERR_OK); // already started.
1943f4cbf05Sopenharmony_ci    EXPECT_NE(handler3->Start(reactor.get()), EVENT_SYS_ERR_OK); // Bad fd.
1953f4cbf05Sopenharmony_ci
1963f4cbf05Sopenharmony_ci    // 5. Remove handler
1973f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->RemoveHandler(nullptr), EVENT_SYS_ERR_OK);
1983f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->RemoveHandler(handler3.get()), EVENT_SYS_ERR_OK); // Bad fd.
1993f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->RemoveHandler(handler4.get()), EVENT_SYS_ERR_OK);
2003f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->RemoveHandler(handler2.get()), EVENT_SYS_ERR_OK);
2013f4cbf05Sopenharmony_ci
2023f4cbf05Sopenharmony_ci    // 6. Remove handler from the handler side.
2033f4cbf05Sopenharmony_ci    EXPECT_NE(handler2->Stop(reactor.get()), EVENT_SYS_ERR_OK); // Not found.
2043f4cbf05Sopenharmony_ci
2053f4cbf05Sopenharmony_ci    // 7. Update handler
2063f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->UpdateHandler(nullptr), EVENT_SYS_ERR_OK);
2073f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->UpdateHandler(handler3.get()), EVENT_SYS_ERR_OK);
2083f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->UpdateHandler(handler1.get()), EVENT_SYS_ERR_OK);
2093f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->UpdateHandler(handler4.get()), EVENT_SYS_ERR_OK);
2103f4cbf05Sopenharmony_ci
2113f4cbf05Sopenharmony_ci    // 8. Update handler from the handler side.
2123f4cbf05Sopenharmony_ci    EXPECT_NE(handler2->Update(reactor.get()), EVENT_SYS_ERR_OK); // Not found.
2133f4cbf05Sopenharmony_ci    EXPECT_NE(handler3->Update(reactor.get()), EVENT_SYS_ERR_OK); // Bad fd.
2143f4cbf05Sopenharmony_ci
2153f4cbf05Sopenharmony_ci    // 9. Find handler
2163f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->FindHandler(nullptr), EVENT_SYS_ERR_OK);
2173f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->FindHandler(handler3.get()), EVENT_SYS_ERR_OK);
2183f4cbf05Sopenharmony_ci
2193f4cbf05Sopenharmony_ci    // 10. Clean handler
2203f4cbf05Sopenharmony_ci    EXPECT_NE(reactor->Clean(-1), EVENT_SYS_ERR_OK);
2213f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->Clean(fd), EVENT_SYS_ERR_OK);
2223f4cbf05Sopenharmony_ci}
2233f4cbf05Sopenharmony_ci
2243f4cbf05Sopenharmony_ci/*
2253f4cbf05Sopenharmony_ci * @tc.name: testIOEventReactor002
2263f4cbf05Sopenharmony_ci * @tc.desc: test change event but not update.
2273f4cbf05Sopenharmony_ci */
2283f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testIOEventReactor002, TestSize.Level0)
2293f4cbf05Sopenharmony_ci{
2303f4cbf05Sopenharmony_ci    g_data = 0;
2313f4cbf05Sopenharmony_ci    // 1. Open timer
2323f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
2333f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
2343f4cbf05Sopenharmony_ci
2353f4cbf05Sopenharmony_ci    // 2. Create io event handlers
2363f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventHandler> handler1 = std::make_shared<IOEventHandler>(fd);
2373f4cbf05Sopenharmony_ci    std::shared_ptr<IOEventHandler> handler2 = std::make_shared<IOEventHandler>(fd);
2383f4cbf05Sopenharmony_ci
2393f4cbf05Sopenharmony_ci    // 3. Create a reactor but not run
2403f4cbf05Sopenharmony_ci    std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
2413f4cbf05Sopenharmony_ci    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
2423f4cbf05Sopenharmony_ci
2433f4cbf05Sopenharmony_ci    // 4. Add handler
2443f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->AddHandler(handler1.get()), EVENT_SYS_ERR_OK);
2453f4cbf05Sopenharmony_ci    EXPECT_EQ(reactor->AddHandler(handler2.get()), EVENT_SYS_ERR_OK);
2463f4cbf05Sopenharmony_ci
2473f4cbf05Sopenharmony_ci    // 5. release one handler
2483f4cbf05Sopenharmony_ci    handler2.reset(); // will be removed from the inner list.
2493f4cbf05Sopenharmony_ci}
2503f4cbf05Sopenharmony_ci
2513f4cbf05Sopenharmony_ciTimerFdHandler::TimerFdHandler(int fd, const TimerEventCallback& cb)
2523f4cbf05Sopenharmony_ci    : IOEventHandler(fd),  timerCallback_(cb) {}
2533f4cbf05Sopenharmony_ci
2543f4cbf05Sopenharmony_cibool TimerFdHandler::Initialize(uint32_t interval)
2553f4cbf05Sopenharmony_ci{
2563f4cbf05Sopenharmony_ci    if ((GetFd() == -1)) {
2573f4cbf05Sopenharmony_ci        return false;
2583f4cbf05Sopenharmony_ci    }
2593f4cbf05Sopenharmony_ci
2603f4cbf05Sopenharmony_ci    struct itimerspec newValue = {{0, 0}, {0, 0}};
2613f4cbf05Sopenharmony_ci    timespec now{0, 0};
2623f4cbf05Sopenharmony_ci    if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
2633f4cbf05Sopenharmony_ci        return false;
2643f4cbf05Sopenharmony_ci    }
2653f4cbf05Sopenharmony_ci
2663f4cbf05Sopenharmony_ci    // next time out time is now + interval
2673f4cbf05Sopenharmony_ci    newValue.it_value.tv_sec = now.tv_sec + interval / MILLI_TO_BASE;
2683f4cbf05Sopenharmony_ci    newValue.it_value.tv_nsec = now.tv_nsec + (interval % MILLI_TO_BASE) * MILLI_TO_NANO;
2693f4cbf05Sopenharmony_ci    if (newValue.it_value.tv_nsec >= NANO_TO_BASE) {
2703f4cbf05Sopenharmony_ci        newValue.it_value.tv_sec = newValue.it_value.tv_sec + 1;
2713f4cbf05Sopenharmony_ci        newValue.it_value.tv_nsec = newValue.it_value.tv_nsec % NANO_TO_BASE;
2723f4cbf05Sopenharmony_ci    }
2733f4cbf05Sopenharmony_ci
2743f4cbf05Sopenharmony_ci    // interval
2753f4cbf05Sopenharmony_ci    newValue.it_interval.tv_sec  = interval / MILLI_TO_BASE;
2763f4cbf05Sopenharmony_ci    newValue.it_interval.tv_nsec = (interval % MILLI_TO_BASE) * MILLI_TO_NANO;
2773f4cbf05Sopenharmony_ci
2783f4cbf05Sopenharmony_ci    if (timerfd_settime(GetFd(), TFD_TIMER_ABSTIME, &newValue, nullptr) == -1) {
2793f4cbf05Sopenharmony_ci        std::cout << "Set timerFd failed-" << strerror(errno) << "timer_fd:" << GetFd() << ", next_time:" <<
2803f4cbf05Sopenharmony_ci                  newValue.it_value.tv_sec << ", interval:" << newValue.it_interval.tv_sec << std::endl;
2813f4cbf05Sopenharmony_ci        return false;
2823f4cbf05Sopenharmony_ci    }
2833f4cbf05Sopenharmony_ci
2843f4cbf05Sopenharmony_ci    EnableRead();
2853f4cbf05Sopenharmony_ci    SetCallback(std::bind(&TimerFdHandler::TimeOut, this));
2863f4cbf05Sopenharmony_ci
2873f4cbf05Sopenharmony_ci    return true;
2883f4cbf05Sopenharmony_ci}
2893f4cbf05Sopenharmony_ci
2903f4cbf05Sopenharmony_civoid TimerFdHandler::Uninitialize()
2913f4cbf05Sopenharmony_ci{
2923f4cbf05Sopenharmony_ci    DisableAll();
2933f4cbf05Sopenharmony_ci}
2943f4cbf05Sopenharmony_ci
2953f4cbf05Sopenharmony_civoid TimerFdHandler::TimeOut()
2963f4cbf05Sopenharmony_ci{
2973f4cbf05Sopenharmony_ci    if (GetFd() == -1) {
2983f4cbf05Sopenharmony_ci        std::cout << "Invalid timer_fd." << std::endl;
2993f4cbf05Sopenharmony_ci        return;
3003f4cbf05Sopenharmony_ci    }
3013f4cbf05Sopenharmony_ci    uint64_t expirations = 0;
3023f4cbf05Sopenharmony_ci    ssize_t n = ::read(GetFd(), &expirations, sizeof(expirations));
3033f4cbf05Sopenharmony_ci    if (n != sizeof(expirations)) {
3043f4cbf05Sopenharmony_ci        std::cout << "reads " << static_cast<int>(n) << "bytes instead of 8." << std::endl;
3053f4cbf05Sopenharmony_ci    }
3063f4cbf05Sopenharmony_ci
3073f4cbf05Sopenharmony_ci    if (timerCallback_) {
3083f4cbf05Sopenharmony_ci        timerCallback_();
3093f4cbf05Sopenharmony_ci    }
3103f4cbf05Sopenharmony_ci}
3113f4cbf05Sopenharmony_ci
3123f4cbf05Sopenharmony_cistatic void InitAndRun(std::shared_ptr<TimerFdHandler>& handler, const uint32_t interval,
3133f4cbf05Sopenharmony_ci                       std::unique_ptr<IOEventReactor>& reactor, std::thread& loopThread)
3143f4cbf05Sopenharmony_ci{
3153f4cbf05Sopenharmony_ci    // Initialize timer handler and add it to reactor
3163f4cbf05Sopenharmony_ci    ASSERT_TRUE(handler->Initialize(interval));
3173f4cbf05Sopenharmony_ci    ASSERT_TRUE(handler->Start(reactor.get()));
3183f4cbf05Sopenharmony_ci
3193f4cbf05Sopenharmony_ci    // Run event loop
3203f4cbf05Sopenharmony_ci    loopThread = std::thread([&reactor] {
3213f4cbf05Sopenharmony_ci        reactor->Run(-1);
3223f4cbf05Sopenharmony_ci    }
3233f4cbf05Sopenharmony_ci    );
3243f4cbf05Sopenharmony_ci}
3253f4cbf05Sopenharmony_ci
3263f4cbf05Sopenharmony_ci/*
3273f4cbf05Sopenharmony_ci * @tc.name: testEvent001
3283f4cbf05Sopenharmony_ci * @tc.desc: test handling event of timerfd.
3293f4cbf05Sopenharmony_ci */
3303f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testEvent001, TestSize.Level0)
3313f4cbf05Sopenharmony_ci{
3323f4cbf05Sopenharmony_ci    g_data = 0;
3333f4cbf05Sopenharmony_ci    // 1. Open timer
3343f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
3353f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
3363f4cbf05Sopenharmony_ci    // 2. Create timer event handler
3373f4cbf05Sopenharmony_ci    std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
3383f4cbf05Sopenharmony_ci
3393f4cbf05Sopenharmony_ci    // 3. Create reactor for event loop
3403f4cbf05Sopenharmony_ci    std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
3413f4cbf05Sopenharmony_ci    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
3423f4cbf05Sopenharmony_ci    reactor->EnableHandling();
3433f4cbf05Sopenharmony_ci
3443f4cbf05Sopenharmony_ci    // 4. Initialize timer handler and add it to reactor. Run event loop
3453f4cbf05Sopenharmony_ci    uint32_t interval = 10;
3463f4cbf05Sopenharmony_ci    std::thread loopThread;
3473f4cbf05Sopenharmony_ci    InitAndRun(handler, interval, reactor, loopThread);
3483f4cbf05Sopenharmony_ci
3493f4cbf05Sopenharmony_ci    // 5. Wait for event handling
3503f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(16));
3513f4cbf05Sopenharmony_ci
3523f4cbf05Sopenharmony_ci    // 6. Check result, execute once at least
3533f4cbf05Sopenharmony_ci    EXPECT_GE(g_data, 1);
3543f4cbf05Sopenharmony_ci
3553f4cbf05Sopenharmony_ci    // 7. terminate the event-loop (aka Run())
3563f4cbf05Sopenharmony_ci    reactor->Terminate();
3573f4cbf05Sopenharmony_ci    loopThread.join();
3583f4cbf05Sopenharmony_ci}
3593f4cbf05Sopenharmony_ci
3603f4cbf05Sopenharmony_ci/*
3613f4cbf05Sopenharmony_ci * @tc.name: testEvent002
3623f4cbf05Sopenharmony_ci * @tc.desc: test changing event to EVENT_NONE.
3633f4cbf05Sopenharmony_ci */
3643f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testEvent002, TestSize.Level0)
3653f4cbf05Sopenharmony_ci{
3663f4cbf05Sopenharmony_ci    g_data = 0;
3673f4cbf05Sopenharmony_ci    // 1. Open timer
3683f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
3693f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
3703f4cbf05Sopenharmony_ci    // 2. Create timer event handler
3713f4cbf05Sopenharmony_ci    std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
3723f4cbf05Sopenharmony_ci
3733f4cbf05Sopenharmony_ci    // 3. Create reactor for event loop
3743f4cbf05Sopenharmony_ci    std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
3753f4cbf05Sopenharmony_ci    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
3763f4cbf05Sopenharmony_ci
3773f4cbf05Sopenharmony_ci    // 4. Initialize timer handler and add it to reactor. Run event loop
3783f4cbf05Sopenharmony_ci    uint32_t interval = 10;
3793f4cbf05Sopenharmony_ci    std::thread loopThread;
3803f4cbf05Sopenharmony_ci    InitAndRun(handler, interval, reactor, loopThread);
3813f4cbf05Sopenharmony_ci
3823f4cbf05Sopenharmony_ci    // 5. Change settings
3833f4cbf05Sopenharmony_ci    reactor->DisableHandling();
3843f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(1));
3853f4cbf05Sopenharmony_ci    reactor->EnableHandling();
3863f4cbf05Sopenharmony_ci    handler->SetEvents(Events::EVENT_NONE);
3873f4cbf05Sopenharmony_ci
3883f4cbf05Sopenharmony_ci    // 6. Wait for event handling
3893f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(16));
3903f4cbf05Sopenharmony_ci
3913f4cbf05Sopenharmony_ci    // 7. Check result, no execution
3923f4cbf05Sopenharmony_ci    EXPECT_EQ(g_data, 0);
3933f4cbf05Sopenharmony_ci
3943f4cbf05Sopenharmony_ci    // 8. terminate the event-loop (aka Run())
3953f4cbf05Sopenharmony_ci    reactor->Terminate();
3963f4cbf05Sopenharmony_ci    loopThread.join();
3973f4cbf05Sopenharmony_ci}
3983f4cbf05Sopenharmony_ci
3993f4cbf05Sopenharmony_ci/*
4003f4cbf05Sopenharmony_ci * @tc.name: testEvent003
4013f4cbf05Sopenharmony_ci * @tc.desc: test disable single event.
4023f4cbf05Sopenharmony_ci */
4033f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testEvent003, TestSize.Level0)
4043f4cbf05Sopenharmony_ci{
4053f4cbf05Sopenharmony_ci    g_data = 0;
4063f4cbf05Sopenharmony_ci    // 1. Open timer
4073f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
4083f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
4093f4cbf05Sopenharmony_ci    // 2. Create timer event handler
4103f4cbf05Sopenharmony_ci    std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
4113f4cbf05Sopenharmony_ci
4123f4cbf05Sopenharmony_ci    // 3. Create reactor for event loop
4133f4cbf05Sopenharmony_ci    std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
4143f4cbf05Sopenharmony_ci    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
4153f4cbf05Sopenharmony_ci
4163f4cbf05Sopenharmony_ci    // 4. Initialize timer handler and add it to reactor. Run event loop
4173f4cbf05Sopenharmony_ci    uint32_t interval = 10;
4183f4cbf05Sopenharmony_ci    std::thread loopThread;
4193f4cbf05Sopenharmony_ci    InitAndRun(handler, interval, reactor, loopThread);
4203f4cbf05Sopenharmony_ci
4213f4cbf05Sopenharmony_ci    // 5. Change settings
4223f4cbf05Sopenharmony_ci    reactor->EnableHandling();
4233f4cbf05Sopenharmony_ci    ASSERT_TRUE(handler->Stop(reactor.get())); // block to get lock, so no need to wait.
4243f4cbf05Sopenharmony_ci
4253f4cbf05Sopenharmony_ci    // 6. Check result, no execution
4263f4cbf05Sopenharmony_ci    EXPECT_EQ(g_data, 0);
4273f4cbf05Sopenharmony_ci
4283f4cbf05Sopenharmony_ci    // 7. terminate the event-loop (aka Run())
4293f4cbf05Sopenharmony_ci    reactor->Terminate();
4303f4cbf05Sopenharmony_ci    loopThread.join();
4313f4cbf05Sopenharmony_ci}
4323f4cbf05Sopenharmony_ci
4333f4cbf05Sopenharmony_ci/*
4343f4cbf05Sopenharmony_ci * @tc.name: testEvent004
4353f4cbf05Sopenharmony_ci * @tc.desc: test removing callback.
4363f4cbf05Sopenharmony_ci */
4373f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testEvent004, TestSize.Level0)
4383f4cbf05Sopenharmony_ci{
4393f4cbf05Sopenharmony_ci    g_data = 0;
4403f4cbf05Sopenharmony_ci    // 1. Open timer
4413f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
4423f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
4433f4cbf05Sopenharmony_ci    // 2. Create timer event handler
4443f4cbf05Sopenharmony_ci    std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
4453f4cbf05Sopenharmony_ci
4463f4cbf05Sopenharmony_ci    // 3. Create reactor for event loop
4473f4cbf05Sopenharmony_ci    std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
4483f4cbf05Sopenharmony_ci    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
4493f4cbf05Sopenharmony_ci
4503f4cbf05Sopenharmony_ci    // 4. Initialize timer handler and add it to reactor. Run event loop
4513f4cbf05Sopenharmony_ci    uint32_t interval = 10;
4523f4cbf05Sopenharmony_ci    std::thread loopThread;
4533f4cbf05Sopenharmony_ci    InitAndRun(handler, interval, reactor, loopThread);
4543f4cbf05Sopenharmony_ci
4553f4cbf05Sopenharmony_ci    // 5. Change settings
4563f4cbf05Sopenharmony_ci    reactor->EnableHandling();
4573f4cbf05Sopenharmony_ci    handler->SetCallback(nullptr);
4583f4cbf05Sopenharmony_ci
4593f4cbf05Sopenharmony_ci    // 6. Wait for event handling
4603f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(16));
4613f4cbf05Sopenharmony_ci
4623f4cbf05Sopenharmony_ci    // 7. Check result, no execution
4633f4cbf05Sopenharmony_ci    EXPECT_EQ(g_data, 0);
4643f4cbf05Sopenharmony_ci
4653f4cbf05Sopenharmony_ci    // 8. terminate the event-loop (aka Run())
4663f4cbf05Sopenharmony_ci    reactor->Terminate();
4673f4cbf05Sopenharmony_ci    loopThread.join();
4683f4cbf05Sopenharmony_ci}
4693f4cbf05Sopenharmony_ci
4703f4cbf05Sopenharmony_ci/*
4713f4cbf05Sopenharmony_ci * @tc.name: testEvent005
4723f4cbf05Sopenharmony_ci * @tc.desc: test change event but not update.
4733f4cbf05Sopenharmony_ci */
4743f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testEvent005, TestSize.Level0)
4753f4cbf05Sopenharmony_ci{
4763f4cbf05Sopenharmony_ci    g_data = 0;
4773f4cbf05Sopenharmony_ci    // 1. Open timer
4783f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
4793f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
4803f4cbf05Sopenharmony_ci    // 2. Create timer event handler
4813f4cbf05Sopenharmony_ci    std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
4823f4cbf05Sopenharmony_ci
4833f4cbf05Sopenharmony_ci    // 3. Create reactor for event loop
4843f4cbf05Sopenharmony_ci    std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
4853f4cbf05Sopenharmony_ci    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
4863f4cbf05Sopenharmony_ci
4873f4cbf05Sopenharmony_ci    // 4. Initialize timer handler and add it to reactor. Run event loop
4883f4cbf05Sopenharmony_ci    uint32_t interval = 15;
4893f4cbf05Sopenharmony_ci    std::thread loopThread;
4903f4cbf05Sopenharmony_ci    InitAndRun(handler, interval, reactor, loopThread);
4913f4cbf05Sopenharmony_ci
4923f4cbf05Sopenharmony_ci    // 5. Change settings but not update
4933f4cbf05Sopenharmony_ci    handler->SetEvents(Events::EVENT_WRITE);
4943f4cbf05Sopenharmony_ci    reactor->EnableHandling();
4953f4cbf05Sopenharmony_ci
4963f4cbf05Sopenharmony_ci    // 6. Wait for event handling
4973f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(16));
4983f4cbf05Sopenharmony_ci
4993f4cbf05Sopenharmony_ci    // 7. Check result, no execution
5003f4cbf05Sopenharmony_ci    EXPECT_EQ(g_data, 0);
5013f4cbf05Sopenharmony_ci
5023f4cbf05Sopenharmony_ci    // 8. terminate the event-loop (aka Run())
5033f4cbf05Sopenharmony_ci    reactor->Terminate();
5043f4cbf05Sopenharmony_ci    loopThread.join();
5053f4cbf05Sopenharmony_ci}
5063f4cbf05Sopenharmony_ci
5073f4cbf05Sopenharmony_ci/*
5083f4cbf05Sopenharmony_ci * @tc.name: testEvent006
5093f4cbf05Sopenharmony_ci * @tc.desc: test release the handler when started.
5103f4cbf05Sopenharmony_ci */
5113f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testEvent006, TestSize.Level0)
5123f4cbf05Sopenharmony_ci{
5133f4cbf05Sopenharmony_ci    g_data = 0;
5143f4cbf05Sopenharmony_ci    // 1. Open timer
5153f4cbf05Sopenharmony_ci    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
5163f4cbf05Sopenharmony_ci    ASSERT_NE(fd, -1);
5173f4cbf05Sopenharmony_ci    // 2. Create timer event handler
5183f4cbf05Sopenharmony_ci    std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
5193f4cbf05Sopenharmony_ci
5203f4cbf05Sopenharmony_ci    // 3. Create reactor for event loop
5213f4cbf05Sopenharmony_ci    std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
5223f4cbf05Sopenharmony_ci    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
5233f4cbf05Sopenharmony_ci
5243f4cbf05Sopenharmony_ci    // 4. Initialize timer handler and add it to reactor. Run event loop
5253f4cbf05Sopenharmony_ci    uint32_t interval = 15;
5263f4cbf05Sopenharmony_ci    std::thread loopThread;
5273f4cbf05Sopenharmony_ci    InitAndRun(handler, interval, reactor, loopThread);
5283f4cbf05Sopenharmony_ci
5293f4cbf05Sopenharmony_ci    // 5. release eventhandler
5303f4cbf05Sopenharmony_ci    handler.reset();
5313f4cbf05Sopenharmony_ci    reactor->EnableHandling();
5323f4cbf05Sopenharmony_ci
5333f4cbf05Sopenharmony_ci    // 6. Wait for event handling
5343f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(16));
5353f4cbf05Sopenharmony_ci
5363f4cbf05Sopenharmony_ci    // 7. Check result, no execution
5373f4cbf05Sopenharmony_ci    EXPECT_EQ(g_data, 0);
5383f4cbf05Sopenharmony_ci
5393f4cbf05Sopenharmony_ci    // 8. terminate the event-loop (aka Run())
5403f4cbf05Sopenharmony_ci    reactor->Terminate();
5413f4cbf05Sopenharmony_ci    loopThread.join();
5423f4cbf05Sopenharmony_ci}
5433f4cbf05Sopenharmony_ci
5443f4cbf05Sopenharmony_ci// Try to substitue underlying implementation of OHOS::UTILS::TIMER
5453f4cbf05Sopenharmony_ciclass TimerEventHandler {
5463f4cbf05Sopenharmony_cipublic:
5473f4cbf05Sopenharmony_ci    using TimerEventCallback = std::function<void(TimerEventHandler*)>;
5483f4cbf05Sopenharmony_ci    TimerEventHandler(int timerFd, uint32_t timeout, bool once);
5493f4cbf05Sopenharmony_ci    TimerEventHandler(uint32_t timeout /* ms */, bool once);
5503f4cbf05Sopenharmony_ci    ~TimerEventHandler();
5513f4cbf05Sopenharmony_ci
5523f4cbf05Sopenharmony_ci    TimerEventHandler(const TimerEventHandler&&) = delete;
5533f4cbf05Sopenharmony_ci    TimerEventHandler& operator=(const TimerEventHandler&&) = delete;
5543f4cbf05Sopenharmony_ci    TimerEventHandler(const TimerEventHandler&) = delete;
5553f4cbf05Sopenharmony_ci    TimerEventHandler& operator=(const TimerEventHandler&) = delete;
5563f4cbf05Sopenharmony_ci
5573f4cbf05Sopenharmony_ci    ErrCode Initialize();
5583f4cbf05Sopenharmony_ci    void Uninitialize();
5593f4cbf05Sopenharmony_ci
5603f4cbf05Sopenharmony_ci    bool Start(IOEventReactor* reactor);
5613f4cbf05Sopenharmony_ci    bool Stop(IOEventReactor* reactor);
5623f4cbf05Sopenharmony_ci
5633f4cbf05Sopenharmony_ci    inline void SetTimerId(const uint32_t& id) { timerId_ = id; }
5643f4cbf05Sopenharmony_ci
5653f4cbf05Sopenharmony_ci    inline void SetTimerEventCallback(const TimerEventCallback& callback) { timerEventCallback_ = callback; }
5663f4cbf05Sopenharmony_ci
5673f4cbf05Sopenharmony_ci    inline uint32_t GetInterval() const { return interval_; }
5683f4cbf05Sopenharmony_ci    inline int GetTimerFd() const { return handler_->GetFd(); }
5693f4cbf05Sopenharmony_ci    inline uint32_t GetTimerId() const { return timerId_; }
5703f4cbf05Sopenharmony_ci
5713f4cbf05Sopenharmony_ciprivate:
5723f4cbf05Sopenharmony_ci    void TimeOut();
5733f4cbf05Sopenharmony_ci
5743f4cbf05Sopenharmony_ciprivate:
5753f4cbf05Sopenharmony_ci    bool           once_;
5763f4cbf05Sopenharmony_ci    uint32_t       timerId_;
5773f4cbf05Sopenharmony_ci    uint32_t       interval_;
5783f4cbf05Sopenharmony_ci    std::unique_ptr<IOEventHandler> handler_;
5793f4cbf05Sopenharmony_ci    TimerEventCallback  timerEventCallback_;
5803f4cbf05Sopenharmony_ci
5813f4cbf05Sopenharmony_ci    friend class Timer;
5823f4cbf05Sopenharmony_ci};
5833f4cbf05Sopenharmony_ci
5843f4cbf05Sopenharmony_ciclass Timer {
5853f4cbf05Sopenharmony_cipublic:
5863f4cbf05Sopenharmony_ci    using TimerCallback = std::function<void ()>;
5873f4cbf05Sopenharmony_ci    using TimerCallbackPtr = std::shared_ptr<TimerCallback>;
5883f4cbf05Sopenharmony_ci    using TimerEventCallback = TimerEventHandler::TimerEventCallback;
5893f4cbf05Sopenharmony_ci
5903f4cbf05Sopenharmony_ci    explicit Timer(const std::string& name, int timeoutMs = 1000);
5913f4cbf05Sopenharmony_ci    virtual ~Timer()
5923f4cbf05Sopenharmony_ci    {
5933f4cbf05Sopenharmony_ci    }
5943f4cbf05Sopenharmony_ci    virtual uint32_t Setup();
5953f4cbf05Sopenharmony_ci    virtual void Shutdown(bool useJoin = true);
5963f4cbf05Sopenharmony_ci    uint32_t Register(const TimerCallback& callback, uint32_t interval /* ms */, bool once = false);
5973f4cbf05Sopenharmony_ci    void Unregister(uint32_t timerId);
5983f4cbf05Sopenharmony_ci
5993f4cbf05Sopenharmony_ciprivate:
6003f4cbf05Sopenharmony_ci    void MainLoop();
6013f4cbf05Sopenharmony_ci    void OnTimer(TimerEventHandler* handler, const TimerCallback& callback);
6023f4cbf05Sopenharmony_ci    int GetTimerFd(uint32_t interval /* ms */);
6033f4cbf05Sopenharmony_ci    uint32_t GetValidId() const;
6043f4cbf05Sopenharmony_ci    void EraseUnusedTimerId(uint32_t interval, const std::vector<uint32_t>& unusedIds);
6053f4cbf05Sopenharmony_ci
6063f4cbf05Sopenharmony_ciprivate:
6073f4cbf05Sopenharmony_ci    using TimerHandlerPtr = std::shared_ptr<TimerEventHandler>;
6083f4cbf05Sopenharmony_ci    using TimerHandlerList = std::list<TimerHandlerPtr>;
6093f4cbf05Sopenharmony_ci
6103f4cbf05Sopenharmony_ci    ErrCode ScheduleTimer(const TimerEventCallback& callback, uint32_t interval, uint32_t timerId, int& timerFd,
6113f4cbf05Sopenharmony_ci                          bool once);
6123f4cbf05Sopenharmony_ci    void EraseExistNode(TimerHandlerPtr target);
6133f4cbf05Sopenharmony_ci    ErrCode CancelTimer(TimerHandlerPtr target);
6143f4cbf05Sopenharmony_ci
6153f4cbf05Sopenharmony_ci    std::map<uint32_t, TimerHandlerList> intervalToTimers_;
6163f4cbf05Sopenharmony_ci    std::map<uint32_t, TimerHandlerPtr> timerHandlers_;
6173f4cbf05Sopenharmony_ci
6183f4cbf05Sopenharmony_ci    std::string name_;
6193f4cbf05Sopenharmony_ci    int timeoutMs_;
6203f4cbf05Sopenharmony_ci    std::thread thread_;
6213f4cbf05Sopenharmony_ci    std::unique_ptr<IOEventReactor> reactor_;
6223f4cbf05Sopenharmony_ci    std::mutex mutex_;
6233f4cbf05Sopenharmony_ci};
6243f4cbf05Sopenharmony_ci
6253f4cbf05Sopenharmony_ciTimer::Timer(const std::string& name, int timeoutMs) : name_(name), timeoutMs_(timeoutMs),
6263f4cbf05Sopenharmony_ci    reactor_(new IOEventReactor()) {}
6273f4cbf05Sopenharmony_ci
6283f4cbf05Sopenharmony_civoid Timer::MainLoop()
6293f4cbf05Sopenharmony_ci{
6303f4cbf05Sopenharmony_ci    prctl(PR_SET_NAME, name_.c_str(), 0, 0, 0);
6313f4cbf05Sopenharmony_ci
6323f4cbf05Sopenharmony_ci    reactor_->Run(timeoutMs_);
6333f4cbf05Sopenharmony_ci    std::cout << "||" << gettid() << "||" << "Loop finished" << std::endl;
6343f4cbf05Sopenharmony_ci
6353f4cbf05Sopenharmony_ci    if (reactor_->CleanUp() != EVENT_SYS_ERR_OK) {
6363f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" <<
6373f4cbf05Sopenharmony_ci                  "Reactor Clean Failed. It will clean during deconstruction" << std::endl;
6383f4cbf05Sopenharmony_ci    }
6393f4cbf05Sopenharmony_ci}
6403f4cbf05Sopenharmony_ci
6413f4cbf05Sopenharmony_ciuint32_t Timer::Setup()
6423f4cbf05Sopenharmony_ci{
6433f4cbf05Sopenharmony_ci    if (thread_.joinable()) { // avoid double assign to an active thread
6443f4cbf05Sopenharmony_ci        return TIMER_ERR_INVALID_VALUE;
6453f4cbf05Sopenharmony_ci    }
6463f4cbf05Sopenharmony_ci
6473f4cbf05Sopenharmony_ci    if (reactor_->SetUp() != EVENT_SYS_ERR_OK) {
6483f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Setup reactor failed." << std::endl;
6493f4cbf05Sopenharmony_ci        return TIMER_ERR_DEAL_FAILED;
6503f4cbf05Sopenharmony_ci    }
6513f4cbf05Sopenharmony_ci
6523f4cbf05Sopenharmony_ci    reactor_->EnableHandling();
6533f4cbf05Sopenharmony_ci
6543f4cbf05Sopenharmony_ci    std::thread loopThread(std::bind(&Timer::MainLoop, this));
6553f4cbf05Sopenharmony_ci    thread_.swap(loopThread);
6563f4cbf05Sopenharmony_ci
6573f4cbf05Sopenharmony_ci    return TIMER_ERR_OK;
6583f4cbf05Sopenharmony_ci}
6593f4cbf05Sopenharmony_ci
6603f4cbf05Sopenharmony_civoid Timer::Shutdown(bool useJoin)
6613f4cbf05Sopenharmony_ci{
6623f4cbf05Sopenharmony_ci    if (!thread_.joinable()) {
6633f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Invalid operation. Already shutdown." << std::endl;
6643f4cbf05Sopenharmony_ci        return;
6653f4cbf05Sopenharmony_ci    }
6663f4cbf05Sopenharmony_ci
6673f4cbf05Sopenharmony_ci    std::cout << "||" << gettid() << "||" << "Stop reactor." << std::endl;
6683f4cbf05Sopenharmony_ci    reactor_->Terminate();
6693f4cbf05Sopenharmony_ci
6703f4cbf05Sopenharmony_ci    if (!useJoin) {
6713f4cbf05Sopenharmony_ci        thread_.detach();
6723f4cbf05Sopenharmony_ci        return;
6733f4cbf05Sopenharmony_ci    }
6743f4cbf05Sopenharmony_ci    thread_.join();
6753f4cbf05Sopenharmony_ci}
6763f4cbf05Sopenharmony_ci
6773f4cbf05Sopenharmony_ciErrCode Timer::ScheduleTimer(const TimerEventCallback& callback, uint32_t interval, uint32_t timerId,
6783f4cbf05Sopenharmony_ci                             int& timerFd, bool once)
6793f4cbf05Sopenharmony_ci{
6803f4cbf05Sopenharmony_ci    std::shared_ptr<TimerEventHandler> handler = std::make_shared<TimerEventHandler>(timerFd, interval, once);
6813f4cbf05Sopenharmony_ci
6823f4cbf05Sopenharmony_ci    handler->SetTimerId(timerId);
6833f4cbf05Sopenharmony_ci    handler->SetTimerEventCallback(callback);
6843f4cbf05Sopenharmony_ci
6853f4cbf05Sopenharmony_ci    uint32_t ret = handler->Initialize();
6863f4cbf05Sopenharmony_ci    if (ret != TIMER_ERR_OK) {
6873f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Init timer handler failed." << std::endl;
6883f4cbf05Sopenharmony_ci        return ret;
6893f4cbf05Sopenharmony_ci    }
6903f4cbf05Sopenharmony_ci    if (!handler->Start(reactor_.get())) {
6913f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Start timer handler failed." << std::endl;
6923f4cbf05Sopenharmony_ci        return TIMER_ERR_DEAL_FAILED;
6933f4cbf05Sopenharmony_ci    }
6943f4cbf05Sopenharmony_ci    timerHandlers_.emplace(timerId, handler); // Add to the id2handlers map
6953f4cbf05Sopenharmony_ci    intervalToTimers_[interval].push_back(handler); // Add to interval2handlerlist map
6963f4cbf05Sopenharmony_ci    timerFd = handler->GetTimerFd();
6973f4cbf05Sopenharmony_ci    return TIMER_ERR_OK;
6983f4cbf05Sopenharmony_ci}
6993f4cbf05Sopenharmony_ci
7003f4cbf05Sopenharmony_ci
7013f4cbf05Sopenharmony_ciuint32_t Timer::Register(const TimerCallback& callback, uint32_t interval /* ms */, bool once)
7023f4cbf05Sopenharmony_ci{
7033f4cbf05Sopenharmony_ci    std::lock_guard<std::mutex> lock(mutex_);
7043f4cbf05Sopenharmony_ci
7053f4cbf05Sopenharmony_ci    // wrap the callback in OnTiner
7063f4cbf05Sopenharmony_ci    TimerEventCallback wrappedCb = std::bind(&Timer::OnTimer, this, std::placeholders::_1, callback);
7073f4cbf05Sopenharmony_ci    int timerFd = once ? IO_EVENT_INVALID_FD : GetTimerFd(interval); // Get timerFd
7083f4cbf05Sopenharmony_ci    uint32_t timerId = GetValidId();                        // Get timerId
7093f4cbf05Sopenharmony_ci
7103f4cbf05Sopenharmony_ci    uint32_t ret = ScheduleTimer(wrappedCb, interval, timerId, timerFd, once);
7113f4cbf05Sopenharmony_ci    if (ret != TIMER_ERR_OK) {
7123f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Try schedule task failed. timer-id:" <<
7133f4cbf05Sopenharmony_ci                  timerId << ", interval:" << interval << "timer-fd:" << timerFd << std::endl;
7143f4cbf05Sopenharmony_ci        return TIMER_ERR_DEAL_FAILED;
7153f4cbf05Sopenharmony_ci    }
7163f4cbf05Sopenharmony_ci
7173f4cbf05Sopenharmony_ci    return timerId;
7183f4cbf05Sopenharmony_ci}
7193f4cbf05Sopenharmony_ci
7203f4cbf05Sopenharmony_civoid Timer::EraseExistNode(TimerHandlerPtr target)
7213f4cbf05Sopenharmony_ci{
7223f4cbf05Sopenharmony_ci    auto handlerList = intervalToTimers_[target->interval_];
7233f4cbf05Sopenharmony_ci    auto itor = std::find(handlerList.begin(), handlerList.end(), target);
7243f4cbf05Sopenharmony_ci    if (itor != handlerList.end()) {
7253f4cbf05Sopenharmony_ci        handlerList.erase(itor);
7263f4cbf05Sopenharmony_ci    }
7273f4cbf05Sopenharmony_ci
7283f4cbf05Sopenharmony_ci    if (handlerList.empty()) {
7293f4cbf05Sopenharmony_ci        intervalToTimers_.erase(target->interval_);
7303f4cbf05Sopenharmony_ci    }
7313f4cbf05Sopenharmony_ci}
7323f4cbf05Sopenharmony_ci
7333f4cbf05Sopenharmony_ciErrCode Timer::CancelTimer(TimerHandlerPtr target)
7343f4cbf05Sopenharmony_ci{
7353f4cbf05Sopenharmony_ci    std::cout << "||" << gettid() << "||" << "Cancle timer handler with fd:" <<  target->GetTimerFd() << std::endl;
7363f4cbf05Sopenharmony_ci    target->Uninitialize();
7373f4cbf05Sopenharmony_ci    if (!target->Stop(reactor_.get())) {
7383f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Stop timer handler failed." << std::endl;
7393f4cbf05Sopenharmony_ci        return TIMER_ERR_DEAL_FAILED;
7403f4cbf05Sopenharmony_ci    }
7413f4cbf05Sopenharmony_ci    timerHandlers_.erase(target->timerId_);
7423f4cbf05Sopenharmony_ci    EraseExistNode(target);
7433f4cbf05Sopenharmony_ci    return TIMER_ERR_OK;
7443f4cbf05Sopenharmony_ci}
7453f4cbf05Sopenharmony_ci
7463f4cbf05Sopenharmony_civoid Timer::Unregister(uint32_t timerId)
7473f4cbf05Sopenharmony_ci{
7483f4cbf05Sopenharmony_ci    std::lock_guard<std::mutex> lock(mutex_);
7493f4cbf05Sopenharmony_ci
7503f4cbf05Sopenharmony_ci    if (timerHandlers_.find(timerId) == timerHandlers_.end()) {
7513f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" <<
7523f4cbf05Sopenharmony_ci                  "Unregister failed. timer-id:" << timerId << " not found." << std::endl;
7533f4cbf05Sopenharmony_ci        return;
7543f4cbf05Sopenharmony_ci    }
7553f4cbf05Sopenharmony_ci
7563f4cbf05Sopenharmony_ci    auto entry = timerHandlers_[timerId];
7573f4cbf05Sopenharmony_ci    std::cout << "||" << gettid() << "||" << "Try remove timer handler from reactor. timerId:" << timerId <<
7583f4cbf05Sopenharmony_ci              ", interval:" << entry->interval_ << std::endl;
7593f4cbf05Sopenharmony_ci
7603f4cbf05Sopenharmony_ci    if (CancelTimer(entry) != TIMER_ERR_OK) {
7613f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Unregister timer handler failed." << std::endl;
7623f4cbf05Sopenharmony_ci    }
7633f4cbf05Sopenharmony_ci}
7643f4cbf05Sopenharmony_ci
7653f4cbf05Sopenharmony_civoid Timer::OnTimer(TimerEventHandler* handler, const TimerCallback& callback)
7663f4cbf05Sopenharmony_ci{
7673f4cbf05Sopenharmony_ci    callback();
7683f4cbf05Sopenharmony_ci
7693f4cbf05Sopenharmony_ci    if (handler->once_) {
7703f4cbf05Sopenharmony_ci        Unregister(handler->timerId_);
7713f4cbf05Sopenharmony_ci    }
7723f4cbf05Sopenharmony_ci}
7733f4cbf05Sopenharmony_ci
7743f4cbf05Sopenharmony_ciuint32_t Timer::GetValidId() const
7753f4cbf05Sopenharmony_ci{
7763f4cbf05Sopenharmony_ci    static std::atomic_uint32_t timerId = 1;
7773f4cbf05Sopenharmony_ci
7783f4cbf05Sopenharmony_ci    while (timerHandlers_.find(timerId) != timerHandlers_.end()) {
7793f4cbf05Sopenharmony_ci        timerId = timerId + 1;
7803f4cbf05Sopenharmony_ci        if (timerId == UINT32_MAX) {
7813f4cbf05Sopenharmony_ci            timerId = 1;
7823f4cbf05Sopenharmony_ci        }
7833f4cbf05Sopenharmony_ci
7843f4cbf05Sopenharmony_ci        if (timerId == TIMER_ERR_DEAL_FAILED) {
7853f4cbf05Sopenharmony_ci            timerId = timerId + 1;
7863f4cbf05Sopenharmony_ci        }
7873f4cbf05Sopenharmony_ci    }
7883f4cbf05Sopenharmony_ci
7893f4cbf05Sopenharmony_ci    return timerId;
7903f4cbf05Sopenharmony_ci}
7913f4cbf05Sopenharmony_ci
7923f4cbf05Sopenharmony_ciint Timer::GetTimerFd(uint32_t interval /* ms */)
7933f4cbf05Sopenharmony_ci{
7943f4cbf05Sopenharmony_ci    if (intervalToTimers_.find(interval) == intervalToTimers_.end()) {
7953f4cbf05Sopenharmony_ci        return IO_EVENT_INVALID_FD;
7963f4cbf05Sopenharmony_ci    }
7973f4cbf05Sopenharmony_ci    auto &handlerList = intervalToTimers_[interval];
7983f4cbf05Sopenharmony_ci    for (const TimerHandlerPtr &ptr : handlerList) {
7993f4cbf05Sopenharmony_ci        if (!ptr->once_) {
8003f4cbf05Sopenharmony_ci            return ptr->GetTimerFd();
8013f4cbf05Sopenharmony_ci        }
8023f4cbf05Sopenharmony_ci    }
8033f4cbf05Sopenharmony_ci    return IO_EVENT_INVALID_FD;
8043f4cbf05Sopenharmony_ci}
8053f4cbf05Sopenharmony_ci
8063f4cbf05Sopenharmony_ciTimerEventHandler::TimerEventHandler(int timerFd, uint32_t timeout /* ms */, bool once)
8073f4cbf05Sopenharmony_ci    : once_(once), interval_(timeout)
8083f4cbf05Sopenharmony_ci{
8093f4cbf05Sopenharmony_ci    if (timerFd == IO_EVENT_INVALID_FD) {
8103f4cbf05Sopenharmony_ci        handler_ = std::make_unique<IOEventHandler>(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC));
8113f4cbf05Sopenharmony_ci    } else {
8123f4cbf05Sopenharmony_ci        handler_ = std::make_unique<IOEventHandler>(timerFd);
8133f4cbf05Sopenharmony_ci    }
8143f4cbf05Sopenharmony_ci}
8153f4cbf05Sopenharmony_ci
8163f4cbf05Sopenharmony_ciTimerEventHandler::~TimerEventHandler()
8173f4cbf05Sopenharmony_ci{
8183f4cbf05Sopenharmony_ci    if (close(handler_->GetFd()) != 0) {
8193f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Close timer-fd failed. fd:" << handler_->GetFd() << ", interval:" <<
8203f4cbf05Sopenharmony_ci                  interval_ << ", once:" << once_ << std::endl;
8213f4cbf05Sopenharmony_ci    }
8223f4cbf05Sopenharmony_ci    handler_->SetFd(IO_EVENT_INVALID_FD);
8233f4cbf05Sopenharmony_ci}
8243f4cbf05Sopenharmony_ci
8253f4cbf05Sopenharmony_ciErrCode TimerEventHandler::Initialize()
8263f4cbf05Sopenharmony_ci{
8273f4cbf05Sopenharmony_ci    if (handler_->GetFd() == IO_EVENT_INVALID_FD) {
8283f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Invalid timer-fd:" << handler_->GetFd() << ", interval:" <<
8293f4cbf05Sopenharmony_ci                  interval_ << ", once:" << once_ << std::endl;
8303f4cbf05Sopenharmony_ci        return TIMER_ERR_INVALID_VALUE;
8313f4cbf05Sopenharmony_ci    }
8323f4cbf05Sopenharmony_ci
8333f4cbf05Sopenharmony_ci    struct itimerspec newValue = {{0, 0}, {0, 0}};
8343f4cbf05Sopenharmony_ci    timespec now{0, 0};
8353f4cbf05Sopenharmony_ci    if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
8363f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Get current time failed." << std::endl;
8373f4cbf05Sopenharmony_ci        return TIMER_ERR_DEAL_FAILED;
8383f4cbf05Sopenharmony_ci    }
8393f4cbf05Sopenharmony_ci
8403f4cbf05Sopenharmony_ci    // next time out time is now + interval
8413f4cbf05Sopenharmony_ci    newValue.it_value.tv_sec = now.tv_sec + interval_ / MILLI_TO_BASE;
8423f4cbf05Sopenharmony_ci    newValue.it_value.tv_nsec = now.tv_nsec + (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
8433f4cbf05Sopenharmony_ci    if (newValue.it_value.tv_nsec >= NANO_TO_BASE) {
8443f4cbf05Sopenharmony_ci        newValue.it_value.tv_sec = newValue.it_value.tv_sec + 1;
8453f4cbf05Sopenharmony_ci        newValue.it_value.tv_nsec = newValue.it_value.tv_nsec % NANO_TO_BASE;
8463f4cbf05Sopenharmony_ci    }
8473f4cbf05Sopenharmony_ci
8483f4cbf05Sopenharmony_ci    if (once_) {
8493f4cbf05Sopenharmony_ci        // interval, 0 means time out only once
8503f4cbf05Sopenharmony_ci        newValue.it_interval.tv_sec  = 0;
8513f4cbf05Sopenharmony_ci        newValue.it_interval.tv_nsec = 0;
8523f4cbf05Sopenharmony_ci    } else {
8533f4cbf05Sopenharmony_ci        // interval
8543f4cbf05Sopenharmony_ci        newValue.it_interval.tv_sec  = interval_ / MILLI_TO_BASE;
8553f4cbf05Sopenharmony_ci        newValue.it_interval.tv_nsec = (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
8563f4cbf05Sopenharmony_ci    }
8573f4cbf05Sopenharmony_ci
8583f4cbf05Sopenharmony_ci    if (timerfd_settime(handler_->GetFd(), TFD_TIMER_ABSTIME, &newValue, nullptr) == -1) {
8593f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Set timer-fd failed. next:" <<
8603f4cbf05Sopenharmony_ci                  static_cast<long long>(newValue.it_value.tv_sec) << "interval:" <<
8613f4cbf05Sopenharmony_ci                  static_cast<long long>(newValue.it_interval.tv_sec) << std::endl;
8623f4cbf05Sopenharmony_ci        return TIMER_ERR_DEAL_FAILED;
8633f4cbf05Sopenharmony_ci    }
8643f4cbf05Sopenharmony_ci
8653f4cbf05Sopenharmony_ci    handler_->SetCallback(std::bind(&TimerEventHandler::TimeOut, this));
8663f4cbf05Sopenharmony_ci    handler_->EnableRead();
8673f4cbf05Sopenharmony_ci
8683f4cbf05Sopenharmony_ci    return TIMER_ERR_OK;
8693f4cbf05Sopenharmony_ci}
8703f4cbf05Sopenharmony_ci
8713f4cbf05Sopenharmony_civoid TimerEventHandler::Uninitialize()
8723f4cbf05Sopenharmony_ci{
8733f4cbf05Sopenharmony_ci    handler_->DisableAll();
8743f4cbf05Sopenharmony_ci}
8753f4cbf05Sopenharmony_ci
8763f4cbf05Sopenharmony_cibool TimerEventHandler::Start(IOEventReactor* reactor)
8773f4cbf05Sopenharmony_ci{
8783f4cbf05Sopenharmony_ci    if (handler_ == nullptr || !handler_->Start(reactor)) {
8793f4cbf05Sopenharmony_ci        return false;
8803f4cbf05Sopenharmony_ci    }
8813f4cbf05Sopenharmony_ci
8823f4cbf05Sopenharmony_ci    return true;
8833f4cbf05Sopenharmony_ci}
8843f4cbf05Sopenharmony_ci
8853f4cbf05Sopenharmony_cibool TimerEventHandler::Stop(IOEventReactor* reactor)
8863f4cbf05Sopenharmony_ci{
8873f4cbf05Sopenharmony_ci    if (handler_ == nullptr || !handler_->Stop(reactor)) {
8883f4cbf05Sopenharmony_ci        return false;
8893f4cbf05Sopenharmony_ci    }
8903f4cbf05Sopenharmony_ci
8913f4cbf05Sopenharmony_ci    return true;
8923f4cbf05Sopenharmony_ci}
8933f4cbf05Sopenharmony_ci
8943f4cbf05Sopenharmony_civoid TimerEventHandler::TimeOut()
8953f4cbf05Sopenharmony_ci{
8963f4cbf05Sopenharmony_ci    if (handler_->GetFd() == IO_EVENT_INVALID_FD) {
8973f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Invalid timerfd." << std::endl;
8983f4cbf05Sopenharmony_ci        return;
8993f4cbf05Sopenharmony_ci    }
9003f4cbf05Sopenharmony_ci    uint64_t expirations = 0;
9013f4cbf05Sopenharmony_ci    ssize_t n = ::read(handler_->GetFd(), &expirations, sizeof(expirations));
9023f4cbf05Sopenharmony_ci    if (n != sizeof(expirations)) {
9033f4cbf05Sopenharmony_ci        std::cout << "||" << gettid() << "||" << "Reads " << static_cast<int>(n) <<
9043f4cbf05Sopenharmony_ci                  " bytes instead of 8 from timer fd." << std::endl;
9053f4cbf05Sopenharmony_ci    }
9063f4cbf05Sopenharmony_ci
9073f4cbf05Sopenharmony_ci    if (timerEventCallback_) {
9083f4cbf05Sopenharmony_ci        timerEventCallback_(this);
9093f4cbf05Sopenharmony_ci    }
9103f4cbf05Sopenharmony_ci}
9113f4cbf05Sopenharmony_ci
9123f4cbf05Sopenharmony_cistd::atomic<int> g_data1(0);
9133f4cbf05Sopenharmony_civoid TimeOutCallback1()
9143f4cbf05Sopenharmony_ci{
9153f4cbf05Sopenharmony_ci    g_data1 += 1;
9163f4cbf05Sopenharmony_ci}
9173f4cbf05Sopenharmony_ci
9183f4cbf05Sopenharmony_cistd::atomic<int> g_data2(0);
9193f4cbf05Sopenharmony_civoid TimeOutCallback2()
9203f4cbf05Sopenharmony_ci{
9213f4cbf05Sopenharmony_ci    g_data2 = g_data2 + 1;
9223f4cbf05Sopenharmony_ci}
9233f4cbf05Sopenharmony_ci
9243f4cbf05Sopenharmony_ciint64_t CurMs()
9253f4cbf05Sopenharmony_ci{
9263f4cbf05Sopenharmony_ci    struct timeval tpend;
9273f4cbf05Sopenharmony_ci    gettimeofday(&tpend, nullptr);
9283f4cbf05Sopenharmony_ci    return (tpend.tv_sec * 1000000 + tpend.tv_usec) / 1000; // 1000000: s to us, 1000: us to ms
9293f4cbf05Sopenharmony_ci}
9303f4cbf05Sopenharmony_ci
9313f4cbf05Sopenharmony_ci/*
9323f4cbf05Sopenharmony_ci * @tc.name: testNewTimer001
9333f4cbf05Sopenharmony_ci * @tc.desc: test basic function of timer implemented by new event-system.
9343f4cbf05Sopenharmony_ci */
9353f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testNewTimer001, TestSize.Level0)
9363f4cbf05Sopenharmony_ci{
9373f4cbf05Sopenharmony_ci    g_data1 = 0;
9383f4cbf05Sopenharmony_ci    Timer timer("test_timer");
9393f4cbf05Sopenharmony_ci    uint32_t ret = timer.Setup();
9403f4cbf05Sopenharmony_ci    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
9413f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback1, 1, true);
9423f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(15));
9433f4cbf05Sopenharmony_ci    timer.Shutdown();
9443f4cbf05Sopenharmony_ci    EXPECT_EQ(1, g_data1);
9453f4cbf05Sopenharmony_ci}
9463f4cbf05Sopenharmony_ci
9473f4cbf05Sopenharmony_ci/*
9483f4cbf05Sopenharmony_ci * @tc.name: testNewTimer002
9493f4cbf05Sopenharmony_ci * @tc.desc: test basic function of timer implemented by new event-system.
9503f4cbf05Sopenharmony_ci */
9513f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testNewTimer002, TestSize.Level0)
9523f4cbf05Sopenharmony_ci{
9533f4cbf05Sopenharmony_ci    g_data1 = 0;
9543f4cbf05Sopenharmony_ci    g_data2 = 0;
9553f4cbf05Sopenharmony_ci    Timer timer("test_timer");
9563f4cbf05Sopenharmony_ci    uint32_t ret = timer.Setup();
9573f4cbf05Sopenharmony_ci    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
9583f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback1, 1);
9593f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback2, 50);
9603f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(500));
9613f4cbf05Sopenharmony_ci    timer.Shutdown();
9623f4cbf05Sopenharmony_ci    EXPECT_GE(g_data1, 8);
9633f4cbf05Sopenharmony_ci    EXPECT_GE(g_data2, 2);
9643f4cbf05Sopenharmony_ci}
9653f4cbf05Sopenharmony_ci
9663f4cbf05Sopenharmony_cistatic void TestTimerEvent(Timer& timer)
9673f4cbf05Sopenharmony_ci{
9683f4cbf05Sopenharmony_ci    uint32_t interval = 1;
9693f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback1, interval);
9703f4cbf05Sopenharmony_ci    uint32_t interval2 = 2;
9713f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback1, interval2);
9723f4cbf05Sopenharmony_ci    int sleepTime = 30;
9733f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
9743f4cbf05Sopenharmony_ci    timer.Shutdown();
9753f4cbf05Sopenharmony_ci}
9763f4cbf05Sopenharmony_ci
9773f4cbf05Sopenharmony_ci/*
9783f4cbf05Sopenharmony_ci * @tc.name: testNewTimer003
9793f4cbf05Sopenharmony_ci * @tc.desc: test basic function of timer implemented by new event-system.
9803f4cbf05Sopenharmony_ci */
9813f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testNewTimer003, TestSize.Level0)
9823f4cbf05Sopenharmony_ci{
9833f4cbf05Sopenharmony_ci    g_data1 = 0;
9843f4cbf05Sopenharmony_ci    Timer timer("test_timer");
9853f4cbf05Sopenharmony_ci    uint32_t ret = timer.Setup();
9863f4cbf05Sopenharmony_ci    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
9873f4cbf05Sopenharmony_ci    TestTimerEvent(timer);
9883f4cbf05Sopenharmony_ci    EXPECT_GE(g_data1, 5);
9893f4cbf05Sopenharmony_ci}
9903f4cbf05Sopenharmony_ci
9913f4cbf05Sopenharmony_ciclass A {
9923f4cbf05Sopenharmony_cipublic:
9933f4cbf05Sopenharmony_ci    explicit A(int data) : data_(data), timer_("ATimer") {}
9943f4cbf05Sopenharmony_ci    ~A() = default;
9953f4cbf05Sopenharmony_ci    bool Init();
9963f4cbf05Sopenharmony_ci    int GetData() const {return data_;}
9973f4cbf05Sopenharmony_ci    bool StartTimer(int milliseconds, bool once);
9983f4cbf05Sopenharmony_ci    void StopTimer();
9993f4cbf05Sopenharmony_ciprivate:
10003f4cbf05Sopenharmony_ci    void TimeOutProc()
10013f4cbf05Sopenharmony_ci    {
10023f4cbf05Sopenharmony_ci        data_ -= 1;
10033f4cbf05Sopenharmony_ci    };
10043f4cbf05Sopenharmony_ci    int data_;
10053f4cbf05Sopenharmony_ci    Timer timer_;
10063f4cbf05Sopenharmony_ci};
10073f4cbf05Sopenharmony_ci
10083f4cbf05Sopenharmony_cibool A::Init()
10093f4cbf05Sopenharmony_ci{
10103f4cbf05Sopenharmony_ci    return timer_.Setup() == Utils::TIMER_ERR_OK;
10113f4cbf05Sopenharmony_ci}
10123f4cbf05Sopenharmony_ci
10133f4cbf05Sopenharmony_civoid A::StopTimer()
10143f4cbf05Sopenharmony_ci{
10153f4cbf05Sopenharmony_ci    timer_.Shutdown();
10163f4cbf05Sopenharmony_ci}
10173f4cbf05Sopenharmony_ci
10183f4cbf05Sopenharmony_cibool A::StartTimer(int milliseconds, bool once)
10193f4cbf05Sopenharmony_ci{
10203f4cbf05Sopenharmony_ci    uint32_t timerId = timer_.Register(std::bind(&A::TimeOutProc, this), milliseconds, once);
10213f4cbf05Sopenharmony_ci    return timerId != Utils::TIMER_ERR_DEAL_FAILED;
10223f4cbf05Sopenharmony_ci}
10233f4cbf05Sopenharmony_ci
10243f4cbf05Sopenharmony_ci/*
10253f4cbf05Sopenharmony_ci * @tc.name: testNewTimer004
10263f4cbf05Sopenharmony_ci * @tc.desc: test wrapper of the timer implemented by new event-system.
10273f4cbf05Sopenharmony_ci */
10283f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testNewTimer004, TestSize.Level0)
10293f4cbf05Sopenharmony_ci{
10303f4cbf05Sopenharmony_ci    A a(10);
10313f4cbf05Sopenharmony_ci    EXPECT_TRUE(a.Init());
10323f4cbf05Sopenharmony_ci    EXPECT_TRUE(a.StartTimer(1, true));
10333f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(20));
10343f4cbf05Sopenharmony_ci    a.StopTimer();
10353f4cbf05Sopenharmony_ci    EXPECT_EQ(9, a.GetData());
10363f4cbf05Sopenharmony_ci}
10373f4cbf05Sopenharmony_ci
10383f4cbf05Sopenharmony_cistatic void SleepLoop()
10393f4cbf05Sopenharmony_ci{
10403f4cbf05Sopenharmony_ci    int loops = 11;
10413f4cbf05Sopenharmony_ci    int64_t desiredVal = 10;
10423f4cbf05Sopenharmony_ci    int sleepTime = 10;
10433f4cbf05Sopenharmony_ci    for (int i = 0; i < loops; i++) {
10443f4cbf05Sopenharmony_ci        int64_t pre = CurMs();
10453f4cbf05Sopenharmony_ci        std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
10463f4cbf05Sopenharmony_ci        int64_t cur = CurMs();
10473f4cbf05Sopenharmony_ci        EXPECT_GE(cur - pre, desiredVal);
10483f4cbf05Sopenharmony_ci    }
10493f4cbf05Sopenharmony_ci}
10503f4cbf05Sopenharmony_ci
10513f4cbf05Sopenharmony_cistatic void TimerEvent(Timer& timer)
10523f4cbf05Sopenharmony_ci{
10533f4cbf05Sopenharmony_ci    uint32_t timerId = 0;
10543f4cbf05Sopenharmony_ci    uint32_t loops = 10;
10553f4cbf05Sopenharmony_ci    uint32_t interval = 7;
10563f4cbf05Sopenharmony_ci    int sleepTime = 10;
10573f4cbf05Sopenharmony_ci    for (uint32_t i = 0; i < loops; i++) {
10583f4cbf05Sopenharmony_ci        timerId = timer.Register(TimeOutCallback1, interval, true);
10593f4cbf05Sopenharmony_ci        std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
10603f4cbf05Sopenharmony_ci    }
10613f4cbf05Sopenharmony_ci    timer.Unregister(timerId);
10623f4cbf05Sopenharmony_ci    timer.Unregister(timerId);
10633f4cbf05Sopenharmony_ci}
10643f4cbf05Sopenharmony_ci
10653f4cbf05Sopenharmony_ci/*
10663f4cbf05Sopenharmony_ci * @tc.name: testNewTimer005
10673f4cbf05Sopenharmony_ci * @tc.desc: test abnormal case of timer implemented by new event-system.
10683f4cbf05Sopenharmony_ci */
10693f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testNewTimer005, TestSize.Level0)
10703f4cbf05Sopenharmony_ci{
10713f4cbf05Sopenharmony_ci    g_data1 = 0;
10723f4cbf05Sopenharmony_ci    Timer timer("test_timer", -1);
10733f4cbf05Sopenharmony_ci    uint32_t ret = timer.Setup();
10743f4cbf05Sopenharmony_ci    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
10753f4cbf05Sopenharmony_ci    TimerEvent(timer);
10763f4cbf05Sopenharmony_ci    timer.Shutdown();
10773f4cbf05Sopenharmony_ci    timer.Shutdown(false);
10783f4cbf05Sopenharmony_ci    EXPECT_GE(g_data1, 5);
10793f4cbf05Sopenharmony_ci}
10803f4cbf05Sopenharmony_ci
10813f4cbf05Sopenharmony_ci/*
10823f4cbf05Sopenharmony_ci * @tc.name: testNewTimer006
10833f4cbf05Sopenharmony_ci * @tc.desc: sleep test for ivi of timer implemented by new event-system.
10843f4cbf05Sopenharmony_ci */
10853f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testNewTimer006, TestSize.Level0)
10863f4cbf05Sopenharmony_ci{
10873f4cbf05Sopenharmony_ci    g_data1 = 0;
10883f4cbf05Sopenharmony_ci    Timer timer("test_timer");
10893f4cbf05Sopenharmony_ci    uint32_t ret = timer.Setup();
10903f4cbf05Sopenharmony_ci    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
10913f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback1, 10);
10923f4cbf05Sopenharmony_ci
10933f4cbf05Sopenharmony_ci    SleepLoop();
10943f4cbf05Sopenharmony_ci    timer.Shutdown();
10953f4cbf05Sopenharmony_ci    EXPECT_GE(g_data1, 10);
10963f4cbf05Sopenharmony_ci}
10973f4cbf05Sopenharmony_ci
10983f4cbf05Sopenharmony_ci/*
10993f4cbf05Sopenharmony_ci * @tc.name: testNewTimer007
11003f4cbf05Sopenharmony_ci * @tc.desc: recursive test of timer implemented by new event-system.
11013f4cbf05Sopenharmony_ci */
11023f4cbf05Sopenharmony_civoid DoFunc(Timer &timer, int &count)
11033f4cbf05Sopenharmony_ci{
11043f4cbf05Sopenharmony_ci    (void)timer.Register(
11053f4cbf05Sopenharmony_ci        [&timer, &count]() {
11063f4cbf05Sopenharmony_ci            count = count + 1;
11073f4cbf05Sopenharmony_ci            if (count > 9) { // 9: recursion depth
11083f4cbf05Sopenharmony_ci                return;
11093f4cbf05Sopenharmony_ci            }
11103f4cbf05Sopenharmony_ci            DoFunc(timer, count);
11113f4cbf05Sopenharmony_ci        },
11123f4cbf05Sopenharmony_ci        10, true); // 10: interval
11133f4cbf05Sopenharmony_ci    g_data1++;
11143f4cbf05Sopenharmony_ci}
11153f4cbf05Sopenharmony_ci
11163f4cbf05Sopenharmony_civoid DoFunc2(Timer &timer, int &count)
11173f4cbf05Sopenharmony_ci{
11183f4cbf05Sopenharmony_ci    (void)timer.Register(
11193f4cbf05Sopenharmony_ci        [&timer, &count]() {
11203f4cbf05Sopenharmony_ci            count = count + 1;
11213f4cbf05Sopenharmony_ci            if (count > 9) { // 9: recursion depth
11223f4cbf05Sopenharmony_ci                return;
11233f4cbf05Sopenharmony_ci            }
11243f4cbf05Sopenharmony_ci            DoFunc2(timer, count);
11253f4cbf05Sopenharmony_ci        },
11263f4cbf05Sopenharmony_ci        10, true); // 10: interval
11273f4cbf05Sopenharmony_ci    g_data1++;
11283f4cbf05Sopenharmony_ci}
11293f4cbf05Sopenharmony_ci
11303f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testNewTimer007, TestSize.Level0)
11313f4cbf05Sopenharmony_ci{
11323f4cbf05Sopenharmony_ci    g_data1 = 0;
11333f4cbf05Sopenharmony_ci    Timer timer("test_timer");
11343f4cbf05Sopenharmony_ci    uint32_t ret = timer.Setup();
11353f4cbf05Sopenharmony_ci    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
11363f4cbf05Sopenharmony_ci
11373f4cbf05Sopenharmony_ci    int cnt = 0;
11383f4cbf05Sopenharmony_ci    int cnt1 = 0;
11393f4cbf05Sopenharmony_ci    DoFunc(timer, cnt);
11403f4cbf05Sopenharmony_ci    DoFunc2(timer, cnt1);
11413f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(50));
11423f4cbf05Sopenharmony_ci    EXPECT_GE(g_data1, 5);  /* 8 for max */
11433f4cbf05Sopenharmony_ci    EXPECT_GE(14, g_data1); /* 10 for min */
11443f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(50));
11453f4cbf05Sopenharmony_ci    timer.Shutdown();
11463f4cbf05Sopenharmony_ci    EXPECT_GE(g_data1, 10); /* 18 for max */
11473f4cbf05Sopenharmony_ci}
11483f4cbf05Sopenharmony_ci
11493f4cbf05Sopenharmony_cistatic void TimerRegisterMechanism(Timer& timer)
11503f4cbf05Sopenharmony_ci{
11513f4cbf05Sopenharmony_ci    uint32_t interval = 10;
11523f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback1, interval, true);
11533f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback1, interval);
11543f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback1, interval, true);
11553f4cbf05Sopenharmony_ci    timer.Register(TimeOutCallback1, interval);
11563f4cbf05Sopenharmony_ci}
11573f4cbf05Sopenharmony_ci
11583f4cbf05Sopenharmony_ci/*
11593f4cbf05Sopenharmony_ci * @tc.name: testNewTimer008
11603f4cbf05Sopenharmony_ci * @tc.desc: test execute-once and execute-periodly tasks.
11613f4cbf05Sopenharmony_ci */
11623f4cbf05Sopenharmony_ciHWTEST_F(UtilsEventTest, testNewTimer008, TestSize.Level0)
11633f4cbf05Sopenharmony_ci{
11643f4cbf05Sopenharmony_ci    g_data1 = 0;
11653f4cbf05Sopenharmony_ci    Timer timer("test_timer");
11663f4cbf05Sopenharmony_ci    uint32_t ret = timer.Setup();
11673f4cbf05Sopenharmony_ci    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
11683f4cbf05Sopenharmony_ci    TimerRegisterMechanism(timer);
11693f4cbf05Sopenharmony_ci    std::this_thread::sleep_for(std::chrono::milliseconds(52));
11703f4cbf05Sopenharmony_ci    timer.Shutdown();
11713f4cbf05Sopenharmony_ci    EXPECT_GE(g_data1, 8); /* 12 for max */
11723f4cbf05Sopenharmony_ci}
11733f4cbf05Sopenharmony_ci
11743f4cbf05Sopenharmony_ci
11753f4cbf05Sopenharmony_ci}  // namespace
11763f4cbf05Sopenharmony_ci}  // namespace OHOS