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 <stdlib.h>
20 #include <sys/timerfd.h>
21 #include <unistd.h>
22
23 #include "le_loop.h"
24 #include "le_task.h"
25 #include "loop_event.h"
26
SetTimer_(int tfd,uint64_t timeout)27 static LE_STATUS SetTimer_(int tfd, uint64_t timeout)
28 {
29 struct itimerspec timeValue;
30 time_t sec = timeout / TIMEOUT_BASE;
31 timeValue.it_interval.tv_sec = sec;
32 long nsec = (timeout % TIMEOUT_BASE) * TIMEOUT_BASE;
33 timeValue.it_interval.tv_nsec = nsec;
34 timeValue.it_value.tv_sec = sec;
35 timeValue.it_value.tv_nsec = nsec;
36 LE_LOGV("SetTimer_ sec %lu tv_nsec %lu", sec, nsec);
37 int ret = timerfd_settime(tfd, 0, &timeValue, NULL);
38 LE_CHECK(ret == 0, return LE_FAILURE, "Failed to set timer %d", errno);
39 return 0;
40 }
41
HandleTimerEvent_(const LoopHandle loop,const TaskHandle task,uint32_t oper)42 static LE_STATUS HandleTimerEvent_(const LoopHandle loop, const TaskHandle task, uint32_t oper)
43 {
44 if (!LE_TEST_FLAGS(oper, Event_Read)) {
45 return LE_FAILURE;
46 }
47 uint64_t repeat = 0;
48 (void)read(GetSocketFd(task), &repeat, sizeof(repeat));
49 TimerTask *timer = (TimerTask *)task;
50 int fd = GetSocketFd(task);
51 if (timer->processTimer) {
52 uint64_t userData = *(uint64_t *)LE_GetUserData(task);
53 timer->processTimer(task, (void *)userData);
54 }
55 timer = (TimerTask *)GetTaskByFd((EventLoop *)loop, fd);
56 if (timer == NULL) {
57 return LE_SUCCESS;
58 }
59 if (timer->repeat <= repeat) {
60 SetTimer_(fd, 0);
61 return LE_SUCCESS;
62 }
63 timer->repeat -= repeat;
64 return LE_SUCCESS;
65 }
66
HandleTimerClose_(const LoopHandle loopHandle,const TaskHandle taskHandle)67 static void HandleTimerClose_(const LoopHandle loopHandle, const TaskHandle taskHandle)
68 {
69 BaseTask *task = (BaseTask *)taskHandle;
70 CloseTask(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 }