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}