1 /*
2 * Copyright (c) 2021 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 <stdio.h>
19 #include <sys/timerfd.h>
20 #include <unistd.h>
21
22 #include "le_loop.h"
23 #include "le_task.h"
24 #include "loop_event.h"
25
SetTimer_(int tfd,uint64_t timeout)26 static LE_STATUS SetTimer_(int tfd, uint64_t timeout)
27 {
28 struct itimerspec timeValue;
29 time_t sec = timeout / TIMEOUT_BASE;
30 timeValue.it_interval.tv_sec = sec;
31 long nsec = (timeout % TIMEOUT_BASE) * TIMEOUT_BASE * TIMEOUT_BASE;
32 timeValue.it_interval.tv_nsec = nsec;
33 timeValue.it_value.tv_sec = sec;
34 timeValue.it_value.tv_nsec = nsec;
35 LE_LOGV("SetTimer_ sec %llu tv_nsec %lu", sec, nsec);
36 int ret = timerfd_settime(tfd, 0, &timeValue, NULL);
37 LE_CHECK(ret == 0, return LE_FAILURE, "Failed to set timer %d", errno);
38 return 0;
39 }
40
HandleTimerEvent_(const LoopHandle loop,const TaskHandle task,uint32_t oper)41 static LE_STATUS HandleTimerEvent_(const LoopHandle loop, const TaskHandle task, uint32_t oper)
42 {
43 if (!LE_TEST_FLAGS(oper, Event_Read)) {
44 return LE_FAILURE;
45 }
46 uint64_t repeat = 0;
47 (void)read(GetSocketFd(task), &repeat, sizeof(repeat));
48 TimerTask *timer = (TimerTask *)task;
49 int fd = GetSocketFd(task);
50 if (timer->processTimer) {
51 uint64_t userData = *(uint64_t *)LE_GetUserData(task);
52 timer->processTimer(task, (void *)userData);
53 }
54 timer = (TimerTask *)GetTaskByFd((EventLoop *)loop, fd);
55 if (timer == NULL) {
56 return LE_SUCCESS;
57 }
58 if (timer->repeat <= repeat) {
59 SetTimer_(fd, 0);
60 return LE_SUCCESS;
61 }
62 timer->repeat -= repeat;
63 return LE_SUCCESS;
64 }
65
HandleTimerClose_(const LoopHandle loopHandle,const TaskHandle taskHandle)66 static void HandleTimerClose_(const LoopHandle loopHandle, const TaskHandle taskHandle)
67 {
68 BaseTask *task = (BaseTask *)taskHandle;
69 CloseTask(loopHandle, task);
70 DelTask((EventLoop *)loopHandle, task);
71 close(task->taskId.fd);
72 }
73
LE_CreateTimer(const LoopHandle loopHandle,TimerHandle * timer,LE_ProcessTimer processTimer,void * context)74 LE_STATUS LE_CreateTimer(const LoopHandle loopHandle,
75 TimerHandle *timer, LE_ProcessTimer processTimer, void *context)
76 {
77 LE_CHECK(loopHandle != NULL && timer != NULL, return LE_INVALID_PARAM, "Invalid parameters");
78 LE_CHECK(processTimer != NULL, return LE_FAILURE, "Invalid parameters processTimer");
79 LE_BaseInfo baseInfo = {};
80 baseInfo.flags = TASK_TIME;
81 baseInfo.userDataSize = sizeof(uint64_t);
82 baseInfo.close = NULL;
83 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
84 LE_CHECK(fd >= 0, return LE_FAILURE, "Failed to create timer");
85 SetNoBlock(fd);
86 TimerTask *task = (TimerTask *)CreateTask(loopHandle, fd, &baseInfo, sizeof(TimerTask));
87 LE_CHECK(task != NULL, close(fd);
88 return LE_NO_MEMORY, "Failed to create task");
89 task->base.handleEvent = HandleTimerEvent_;
90 task->base.innerClose = HandleTimerClose_;
91 task->processTimer = processTimer;
92 *(uint64_t *)(task + 1) = (uint64_t)context;
93 *timer = (TimerHandle)task;
94 return LE_SUCCESS;
95 }
96
LE_StartTimer(const LoopHandle loopHandle,const TimerHandle timer,uint64_t timeout,uint64_t repeat)97 LE_STATUS LE_StartTimer(const LoopHandle loopHandle,
98 const TimerHandle timer, uint64_t timeout, uint64_t repeat)
99 {
100 LE_CHECK(loopHandle != NULL && timer != NULL, return LE_INVALID_PARAM, "Invalid parameters");
101 EventLoop *loop = (EventLoop *)loopHandle;
102 TimerTask *task = (TimerTask *)timer;
103 task->timeout = timeout;
104 task->repeat = repeat;
105 int ret = SetTimer_(GetSocketFd(timer), task->timeout);
106 LE_CHECK(ret == 0, return LE_FAILURE, "Failed to set timer");
107 ret = loop->addEvent(loop, (const BaseTask *)task, Event_Read);
108 LE_CHECK(ret == 0, return LE_FAILURE, "Failed to add event");
109 return LE_SUCCESS;
110 }
111
LE_StopTimer(const LoopHandle loopHandle,const TimerHandle timer)112 void LE_StopTimer(const LoopHandle loopHandle, const TimerHandle timer)
113 {
114 LE_CHECK(loopHandle != NULL && timer != NULL, return, "Invalid parameters");
115 LE_CloseTask(loopHandle, timer);
116 }