1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci
16d9f0492fSopenharmony_ci#include "le_timer.h"
17d9f0492fSopenharmony_ci
18d9f0492fSopenharmony_ci#include <errno.h>
19d9f0492fSopenharmony_ci#include <time.h>
20d9f0492fSopenharmony_ci
21d9f0492fSopenharmony_ci#include "le_loop.h"
22d9f0492fSopenharmony_ci#include "le_task.h"
23d9f0492fSopenharmony_ci#include "le_utils.h"
24d9f0492fSopenharmony_ci#include "list.h"
25d9f0492fSopenharmony_ci#include "loop_event.h"
26d9f0492fSopenharmony_ci
27d9f0492fSopenharmony_ci#define TIMER_CANCELED 0x1000
28d9f0492fSopenharmony_ci#define TIMER_PROCESSING 0x2000
29d9f0492fSopenharmony_ci
30d9f0492fSopenharmony_ciuint64_t GetCurrentTimespec(uint64_t timeout)
31d9f0492fSopenharmony_ci{
32d9f0492fSopenharmony_ci    struct timespec start;
33d9f0492fSopenharmony_ci    clock_gettime(CLOCK_MONOTONIC, &start);
34d9f0492fSopenharmony_ci    uint64_t ms = timeout;
35d9f0492fSopenharmony_ci    ms += (uint64_t)start.tv_sec * LE_SEC_TO_MSEC + (uint64_t)start.tv_nsec / LE_MSEC_TO_NSEC;
36d9f0492fSopenharmony_ci    return ms;
37d9f0492fSopenharmony_ci}
38d9f0492fSopenharmony_ci
39d9f0492fSopenharmony_cistatic int TimerNodeCompareProc(ListNode *node, ListNode *newNode)
40d9f0492fSopenharmony_ci{
41d9f0492fSopenharmony_ci    TimerNode *timer1 = ListEntry(node, TimerNode, node);
42d9f0492fSopenharmony_ci    TimerNode *timer2 = ListEntry(newNode, TimerNode, node);
43d9f0492fSopenharmony_ci    if (timer1->endTime > timer2->endTime) {
44d9f0492fSopenharmony_ci        return 1;
45d9f0492fSopenharmony_ci    } else if (timer1->endTime == timer2->endTime) {
46d9f0492fSopenharmony_ci        return 0;
47d9f0492fSopenharmony_ci    }
48d9f0492fSopenharmony_ci
49d9f0492fSopenharmony_ci    return -1;
50d9f0492fSopenharmony_ci}
51d9f0492fSopenharmony_ci
52d9f0492fSopenharmony_cistatic void InsertTimerNode(EventLoop *loop, TimerNode *timer)
53d9f0492fSopenharmony_ci{
54d9f0492fSopenharmony_ci    timer->endTime = GetCurrentTimespec(timer->timeout);
55d9f0492fSopenharmony_ci    LoopMutexLock(&timer->mutex);
56d9f0492fSopenharmony_ci    timer->flags &= ~TIMER_PROCESSING;
57d9f0492fSopenharmony_ci    timer->repeat--;
58d9f0492fSopenharmony_ci    OH_ListAddWithOrder(&loop->timerList, &timer->node, TimerNodeCompareProc);
59d9f0492fSopenharmony_ci
60d9f0492fSopenharmony_ci    LoopMutexUnlock(&timer->mutex);
61d9f0492fSopenharmony_ci}
62d9f0492fSopenharmony_ci
63d9f0492fSopenharmony_civoid CheckTimeoutOfTimer(EventLoop *loop, uint64_t currTime)
64d9f0492fSopenharmony_ci{
65d9f0492fSopenharmony_ci    const uint64_t faultTime = 10; // 10ms
66d9f0492fSopenharmony_ci    ListNode timeoutList;
67d9f0492fSopenharmony_ci    OH_ListInit(&timeoutList);
68d9f0492fSopenharmony_ci    ListNode *node = loop->timerList.next;
69d9f0492fSopenharmony_ci    while (node != &loop->timerList) {
70d9f0492fSopenharmony_ci        TimerNode *timer = ListEntry(node, TimerNode, node);
71d9f0492fSopenharmony_ci        if (timer->endTime > (currTime + faultTime)) {
72d9f0492fSopenharmony_ci            break;
73d9f0492fSopenharmony_ci        }
74d9f0492fSopenharmony_ci
75d9f0492fSopenharmony_ci        LoopMutexLock(&timer->mutex);
76d9f0492fSopenharmony_ci        OH_ListRemove(&timer->node);
77d9f0492fSopenharmony_ci        OH_ListInit(&timer->node);
78d9f0492fSopenharmony_ci        LoopMutexUnlock(&timer->mutex);
79d9f0492fSopenharmony_ci
80d9f0492fSopenharmony_ci        OH_ListAddTail(&timeoutList, &timer->node);
81d9f0492fSopenharmony_ci        timer->flags |= TIMER_PROCESSING;
82d9f0492fSopenharmony_ci
83d9f0492fSopenharmony_ci        node = loop->timerList.next;
84d9f0492fSopenharmony_ci    }
85d9f0492fSopenharmony_ci
86d9f0492fSopenharmony_ci    node = timeoutList.next;
87d9f0492fSopenharmony_ci    while (node != &timeoutList) {
88d9f0492fSopenharmony_ci        TimerNode *timer = ListEntry(node, TimerNode, node);
89d9f0492fSopenharmony_ci
90d9f0492fSopenharmony_ci        OH_ListRemove(&timer->node);
91d9f0492fSopenharmony_ci        OH_ListInit(&timer->node);
92d9f0492fSopenharmony_ci        timer->process((TimerHandle)timer, timer->context);
93d9f0492fSopenharmony_ci        if ((timer->repeat == 0) || ((timer->flags & TIMER_CANCELED) == TIMER_CANCELED)) {
94d9f0492fSopenharmony_ci            free(timer);
95d9f0492fSopenharmony_ci            node = timeoutList.next;
96d9f0492fSopenharmony_ci            continue;
97d9f0492fSopenharmony_ci        }
98d9f0492fSopenharmony_ci
99d9f0492fSopenharmony_ci        InsertTimerNode(loop, timer);
100d9f0492fSopenharmony_ci        node = timeoutList.next;
101d9f0492fSopenharmony_ci    }
102d9f0492fSopenharmony_ci}
103d9f0492fSopenharmony_ci
104d9f0492fSopenharmony_cistatic TimerNode *CreateTimer(void)
105d9f0492fSopenharmony_ci{
106d9f0492fSopenharmony_ci    TimerNode *timer = (TimerNode *)malloc(sizeof(TimerNode));
107d9f0492fSopenharmony_ci    LE_CHECK(timer != NULL, return NULL, "Failed to create timer");
108d9f0492fSopenharmony_ci    OH_ListInit(&timer->node);
109d9f0492fSopenharmony_ci    LoopMutexInit(&timer->mutex);
110d9f0492fSopenharmony_ci    timer->timeout = 0;
111d9f0492fSopenharmony_ci    timer->repeat = 1;
112d9f0492fSopenharmony_ci    timer->flags = TASK_TIME;
113d9f0492fSopenharmony_ci
114d9f0492fSopenharmony_ci    return timer;
115d9f0492fSopenharmony_ci}
116d9f0492fSopenharmony_ci
117d9f0492fSopenharmony_ciLE_STATUS LE_CreateTimer(const LoopHandle loopHandle,
118d9f0492fSopenharmony_ci    TimerHandle *timer, LE_ProcessTimer processTimer, void *context)
119d9f0492fSopenharmony_ci{
120d9f0492fSopenharmony_ci    LE_CHECK(loopHandle != NULL, return LE_INVALID_PARAM, "loopHandle iS NULL");
121d9f0492fSopenharmony_ci    LE_CHECK(timer != NULL, return LE_INVALID_PARAM, "Invalid parameters");
122d9f0492fSopenharmony_ci    LE_CHECK(processTimer != NULL, return LE_FAILURE, "Invalid parameters processTimer");
123d9f0492fSopenharmony_ci
124d9f0492fSopenharmony_ci    TimerNode *timerNode = CreateTimer();
125d9f0492fSopenharmony_ci    LE_CHECK(timerNode != NULL, return LE_FAILURE, "Failed to create timer");
126d9f0492fSopenharmony_ci    timerNode->process = processTimer;
127d9f0492fSopenharmony_ci    timerNode->context = context;
128d9f0492fSopenharmony_ci    *timer = (TimerHandle)timerNode;
129d9f0492fSopenharmony_ci
130d9f0492fSopenharmony_ci    return LE_SUCCESS;
131d9f0492fSopenharmony_ci}
132d9f0492fSopenharmony_ci
133d9f0492fSopenharmony_ciLE_STATUS LE_StartTimer(const LoopHandle loopHandle,
134d9f0492fSopenharmony_ci    const TimerHandle timer, uint64_t timeout, uint64_t repeat)
135d9f0492fSopenharmony_ci{
136d9f0492fSopenharmony_ci    LE_CHECK(loopHandle != NULL && timer != NULL, return LE_INVALID_PARAM, "Invalid parameters");
137d9f0492fSopenharmony_ci    EventLoop *loop = (EventLoop *)loopHandle;
138d9f0492fSopenharmony_ci
139d9f0492fSopenharmony_ci    TimerNode *timerNode = (TimerNode *)timer;
140d9f0492fSopenharmony_ci    timerNode->timeout = timeout;
141d9f0492fSopenharmony_ci    timerNode->repeat = repeat > 0 ? repeat : 1;
142d9f0492fSopenharmony_ci
143d9f0492fSopenharmony_ci    InsertTimerNode(loop, timerNode);
144d9f0492fSopenharmony_ci    return LE_SUCCESS;
145d9f0492fSopenharmony_ci}
146d9f0492fSopenharmony_ci
147d9f0492fSopenharmony_ciuint64_t GetMinTimeoutPeriod(const EventLoop *loop)
148d9f0492fSopenharmony_ci{
149d9f0492fSopenharmony_ci    LE_CHECK(loop != NULL, return 0, "Invalid loop");
150d9f0492fSopenharmony_ci    LE_ONLY_CHECK(loop->timerList.next != &(loop->timerList), return 0);
151d9f0492fSopenharmony_ci    TimerNode *timerNode = ListEntry(loop->timerList.next, TimerNode, node);
152d9f0492fSopenharmony_ci    LE_CHECK(timerNode != NULL, return 0, "Invalid timeNode");
153d9f0492fSopenharmony_ci
154d9f0492fSopenharmony_ci    return timerNode->endTime;
155d9f0492fSopenharmony_ci}
156d9f0492fSopenharmony_ci
157d9f0492fSopenharmony_cistatic void TimerNodeDestroyProc(ListNode *node)
158d9f0492fSopenharmony_ci{
159d9f0492fSopenharmony_ci    TimerNode *timer = ListEntry(node, TimerNode, node);
160d9f0492fSopenharmony_ci    OH_ListRemove(&timer->node);
161d9f0492fSopenharmony_ci    OH_ListInit(&timer->node);
162d9f0492fSopenharmony_ci    LoopMutexDestroy(timer->mutex);
163d9f0492fSopenharmony_ci    free(timer);
164d9f0492fSopenharmony_ci}
165d9f0492fSopenharmony_ci
166d9f0492fSopenharmony_civoid DestroyTimerList(EventLoop *loop)
167d9f0492fSopenharmony_ci{
168d9f0492fSopenharmony_ci    OH_ListRemoveAll(&loop->timerList, TimerNodeDestroyProc);
169d9f0492fSopenharmony_ci}
170d9f0492fSopenharmony_ci
171d9f0492fSopenharmony_civoid CancelTimer(TimerHandle timerHandle)
172d9f0492fSopenharmony_ci{
173d9f0492fSopenharmony_ci    TimerNode *timer = (TimerNode *)timerHandle;
174d9f0492fSopenharmony_ci    LE_CHECK(timer != NULL, return, "Invalid timer");
175d9f0492fSopenharmony_ci
176d9f0492fSopenharmony_ci    if ((timer->flags & TIMER_PROCESSING) == TIMER_PROCESSING) {
177d9f0492fSopenharmony_ci        timer->flags |= TIMER_CANCELED;
178d9f0492fSopenharmony_ci        return;
179d9f0492fSopenharmony_ci    }
180d9f0492fSopenharmony_ci    LoopMutexLock(&timer->mutex);
181d9f0492fSopenharmony_ci    OH_ListRemove(&timer->node);
182d9f0492fSopenharmony_ci    OH_ListInit(&timer->node);
183d9f0492fSopenharmony_ci    LoopMutexUnlock(&timer->mutex);
184d9f0492fSopenharmony_ci    free(timer);
185d9f0492fSopenharmony_ci}
186d9f0492fSopenharmony_ci
187d9f0492fSopenharmony_civoid LE_StopTimer(const LoopHandle loopHandle, const TimerHandle timer)
188d9f0492fSopenharmony_ci{
189d9f0492fSopenharmony_ci    CancelTimer(timer);
190d9f0492fSopenharmony_ci}