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 close(task->taskId.fd);
71 }
72
LE_CreateTimer(const LoopHandle loopHandle,TimerHandle * timer,LE_ProcessTimer processTimer,void * context)73 LE_STATUS LE_CreateTimer(const LoopHandle loopHandle,
74 TimerHandle *timer, LE_ProcessTimer processTimer, void *context)
75 {
76 LE_CHECK(loopHandle != NULL && timer != NULL, return LE_INVALID_PARAM, "Invalid parameters");
77 LE_CHECK(processTimer != NULL, return LE_FAILURE, "Invalid parameters processTimer");
78 LE_BaseInfo baseInfo = {};
79 baseInfo.flags = TASK_TIME;
80 baseInfo.userDataSize = sizeof(uint64_t);
81 baseInfo.close = NULL;
82 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
83 LE_CHECK(fd >= 0, return LE_FAILURE, "Failed to create timer");
84 SetNoBlock(fd);
85 TimerTask *task = (TimerTask *)CreateTask(loopHandle, fd, &baseInfo, sizeof(TimerTask));
86 LE_CHECK(task != NULL, close(fd);
87 return LE_NO_MEMORY, "Failed to create task");
88 task->base.handleEvent = HandleTimerEvent_;
89 task->base.innerClose = HandleTimerClose_;
90 task->processTimer = processTimer;
91 *(uint64_t *)(task + 1) = (uint64_t)context;
92 *timer = (TimerHandle)task;
93 return LE_SUCCESS;
94 }
95
LE_StartTimer(const LoopHandle loopHandle,const TimerHandle timer,uint64_t timeout,uint64_t repeat)96 LE_STATUS LE_StartTimer(const LoopHandle loopHandle,
97 const TimerHandle timer, uint64_t timeout, uint64_t repeat)
98 {
99 LE_CHECK(loopHandle != NULL && timer != NULL, return LE_INVALID_PARAM, "Invalid parameters");
100 EventLoop *loop = (EventLoop *)loopHandle;
101 TimerTask *task = (TimerTask *)timer;
102 task->timeout = timeout;
103 task->repeat = repeat;
104 int ret = SetTimer_(GetSocketFd(timer), task->timeout);
105 LE_CHECK(ret == 0, return LE_FAILURE, "Failed to set timer");
106 ret = loop->addEvent(loop, (const BaseTask *)task, Event_Read);
107 LE_CHECK(ret == 0, return LE_FAILURE, "Failed to add event");
108 return LE_SUCCESS;
109 }
110
LE_StopTimer(const LoopHandle loopHandle,const TimerHandle timer)111 void LE_StopTimer(const LoopHandle loopHandle, const TimerHandle timer)
112 {
113 LE_CHECK(loopHandle != NULL && timer != NULL, return, "Invalid parameters");
114 LE_CloseTask(loopHandle, timer);
115 }