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