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 "nstackx_timer.h"
17 #include "nstackx_log.h"
18 #include "nstackx_error.h"
19 #include "securec.h"
20
21 #define TAG "nStackXTimer"
22
TimerDelete(Timer * timer)23 void TimerDelete(Timer *timer)
24 {
25 if (timer == NULL) {
26 return;
27 }
28 if (timer->task.taskfd != INVALID_TASK_DESC) {
29 if (DeRegisterEpollTask(&(timer->task)) != NSTACKX_EOK) {
30 LOGE(TAG, "DeRegisterEpollTask failed");
31 }
32 if (close(timer->task.taskfd) < 0) {
33 LOGE(TAG, "close timer task failed");
34 }
35 timer->task.taskfd = INVALID_TASK_DESC;
36 }
37 free(timer);
38 }
39
TimerReadHandle(void * arg)40 static void TimerReadHandle(void *arg)
41 {
42 EpollTask *task = arg;
43 Timer *timer = NULL;
44 uint64_t exp;
45 if (task == NULL) {
46 LOGE(TAG, "Timer task is NULL");
47 return;
48 }
49
50 timer = task->ptr;
51 if (timer == NULL) {
52 LOGE(TAG, "Timer is NULL");
53 return;
54 }
55
56 if (timer->disabled) {
57 LOGD(TAG, "User disable timer before timer callback.");
58 return;
59 }
60
61 if (read(task->taskfd, &exp, sizeof(exp)) != (ssize_t)(sizeof(uint64_t))) {
62 LOGE(TAG, "read invalid exp");
63 return;
64 }
65
66 if (timer->timeoutHandle != NULL) {
67 timer->timeoutHandle(timer->data);
68 }
69 return;
70 }
71
TimerGetRemainTime(Timer * timer,uint32_t * remainTimeMsPtr)72 int32_t TimerGetRemainTime(Timer *timer, uint32_t *remainTimeMsPtr)
73 {
74 struct itimerspec currValue = {{0}, {0}};
75
76 if (timer == NULL || remainTimeMsPtr == NULL) {
77 LOGE(TAG, "Invalid timer parameter");
78 return NSTACKX_EINVAL;
79 }
80
81 if (timerfd_gettime(timer->task.taskfd, &currValue) < 0) {
82 LOGE(TAG, "timerfd_gettime() failed! %d", errno);
83 return NSTACKX_EFAILED;
84 }
85
86 *remainTimeMsPtr = (uint32_t)(currValue.it_value.tv_sec * NSTACKX_MILLI_TICKS +
87 currValue.it_value.tv_nsec / NSTACKX_MILLI_TICKS / NSTACKX_MILLI_TICKS);
88
89 return NSTACKX_EOK;
90 }
91
TimerSetTimeout(Timer * timer,uint32_t timeoutMs,uint8_t repeated)92 int32_t TimerSetTimeout(Timer *timer, uint32_t timeoutMs, uint8_t repeated)
93 {
94 struct itimerspec ts;
95
96 if (timer == NULL) {
97 LOGE(TAG, "Invalid timer parameter");
98 return NSTACKX_EINVAL;
99 }
100
101 (void)memset_s(&ts, sizeof(ts), 0, sizeof(ts));
102 if (timeoutMs) {
103 ts.it_value.tv_sec = timeoutMs / NSTACKX_MILLI_TICKS;
104 ts.it_value.tv_nsec = (timeoutMs % NSTACKX_MILLI_TICKS) * NSTACKX_NANO_SEC_PER_MILLI_SEC;
105 if (repeated) {
106 ts.it_interval.tv_sec = ts.it_value.tv_sec;
107 ts.it_interval.tv_nsec = ts.it_value.tv_nsec;
108 }
109 timer->disabled = NSTACKX_FALSE;
110 } else {
111 timer->disabled = NSTACKX_TRUE;
112 }
113
114 if (timerfd_settime(timer->task.taskfd, 0, &ts, NULL) < 0) {
115 LOGE(TAG, "timerfd_settime failed! %d", errno);
116 return NSTACKX_EFAILED;
117 }
118
119 return NSTACKX_EOK;
120 }
121
TimerStart(EpollDesc epollfd,uint32_t ms,uint8_t repeated,TimeoutHandle handle,void * data)122 Timer *TimerStart(EpollDesc epollfd, uint32_t ms, uint8_t repeated, TimeoutHandle handle, void *data)
123 {
124 Timer *timer = calloc(1, sizeof(Timer));
125 if (timer == NULL) {
126 LOGE(TAG, "timer malloc failed");
127 return NULL;
128 }
129
130 timer->timeoutHandle = handle;
131 timer->data = data;
132 timer->disabled = NSTACKX_FALSE;
133
134 timer->task.taskfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
135 if (timer->task.taskfd < 0) {
136 LOGE(TAG, "timer create failed! errno %d", errno);
137 TimerDelete(timer);
138 return NULL;
139 }
140 timer->task.epollfd = epollfd;
141 timer->task.readHandle = TimerReadHandle;
142 timer->task.writeHandle = NULL;
143 timer->task.errorHandle = NULL;
144 timer->task.ptr = timer;
145
146 if (TimerSetTimeout(timer, ms, repeated) != NSTACKX_EOK) {
147 TimerDelete(timer);
148 return NULL;
149 }
150
151 if (RegisterEpollTask(&timer->task, EPOLLIN) != NSTACKX_EOK) {
152 LOGE(TAG, "RegisterEpollTask failed");
153 TimerDelete(timer);
154 return NULL;
155 }
156 return timer;
157 }
158