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