• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 # Copyright (C) 2024 HiHope Open Source Organization .
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 <stdint.h>
17 #include <errno.h>
18 #include <time.h>
19 #include <signal.h>
20 #include <unistd.h>
21 #include <los_hwi.h>
22 #include <los_swtmr.h>
23 #include <los_swtmr_pri.h>
24 
25 #ifndef STATIC
26 #define STATIC static
27 #endif
28 
29 #define OS_SYS_NS_PER_US 1000
30 #define OS_SYS_NS_PER_SECOND 1000000000
31 #define OS_SYS_US_PER_SECOND 1000000
32 #define OS_SYS_MS_PER_SECOND 1000
33 
ValidTimerID(UINT16 swtmrID)34 STATIC INLINE BOOL ValidTimerID(UINT16 swtmrID)
35 {
36     /* check timer id */
37     return (swtmrID < LOSCFG_BASE_CORE_SWTMR_LIMIT);
38 }
39 
40 /* internal functions */
ValidTimeSpec(const struct timespec * tp)41 STATIC INLINE BOOL ValidTimeSpec(const struct timespec *tp)
42 {
43     /* Fail a NULL pointer */
44     if (tp == NULL) {
45         return FALSE;
46     }
47 
48     /* Fail illegal nanosecond values */
49     if ((tp->tv_nsec < 0) || (tp->tv_nsec >= OS_SYS_NS_PER_SECOND) || (tp->tv_sec < 0)) {
50         return FALSE;
51     }
52 
53     return TRUE;
54 }
55 
OsTimeSpec2Tick(const struct timespec * tp)56 STATIC INLINE UINT32 OsTimeSpec2Tick(const struct timespec *tp)
57 {
58     UINT64 tick, ns;
59 
60     ns = (UINT64)tp->tv_sec * OS_SYS_NS_PER_SECOND + tp->tv_nsec;
61     /* Round up for ticks */
62     tick = (ns * LOSCFG_BASE_CORE_TICK_PER_SECOND + (OS_SYS_NS_PER_SECOND - 1)) / OS_SYS_NS_PER_SECOND;
63     if (tick > LOS_WAIT_FOREVER) {
64         tick = LOS_WAIT_FOREVER;
65     }
66     return (UINT32)tick;
67 }
68 
OsTick2TimeSpec(struct timespec * tp,UINT32 tick)69 STATIC INLINE VOID OsTick2TimeSpec(struct timespec *tp, UINT32 tick)
70 {
71     UINT64 ns = ((UINT64)tick * OS_SYS_NS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND;
72     tp->tv_sec = (time_t)(ns / OS_SYS_NS_PER_SECOND);
73     tp->tv_nsec = (long)(ns % OS_SYS_NS_PER_SECOND);
74 }
75 
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)76 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
77 {
78     UINT64 nseconds;
79     UINT64 tick;
80     UINT32 ret;
81     const UINT32 nsPerTick = OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND;
82 
83     if (!ValidTimeSpec(rqtp)) {
84         errno = EINVAL;
85         return -1;
86     }
87 
88     nseconds = (UINT64)rqtp->tv_sec * OS_SYS_NS_PER_SECOND + rqtp->tv_nsec;
89 
90     tick = (nseconds + nsPerTick - 1) / nsPerTick; // Round up for ticks
91 
92     if (tick >= UINT32_MAX) {
93         errno = EINVAL;
94         return -1;
95     }
96 
97     /* PS: skip the first tick because it is NOT a full tick. */
98     ret = LOS_TaskDelay(tick ? (UINT32)(tick + 1) : 0);
99     if (ret == LOS_OK || ret == LOS_ERRNO_TSK_YIELD_NOT_ENOUGH_TASK) {
100         if (rmtp) {
101             rmtp->tv_sec = rmtp->tv_nsec = 0;
102         }
103         return 0;
104     }
105 
106     /* sleep in interrupt context or in task sched lock state */
107     errno = EPERM;
108     return -1;
109 }
110 
timer_create(clockid_t clockID,struct sigevent * restrict evp,timer_t * restrict timerID)111 int timer_create(clockid_t clockID, struct sigevent *restrict evp, timer_t *restrict timerID)
112 {
113     UINT32 ret;
114     UINT16 swtmrID;
115 
116     if (!timerID || (clockID != CLOCK_REALTIME)) {
117         errno = EINVAL;
118         return -1;
119     }
120 
121     if (!evp || evp->sigev_notify != SIGEV_THREAD || evp->sigev_notify_attributes) {
122         errno = ENOTSUP;
123         return -1;
124     }
125 
126     ret = LOS_SwtmrCreate(1, LOS_SWTMR_MODE_ONCE, (SWTMR_PROC_FUNC)evp->sigev_notify_function,
127                           &swtmrID, (UINT32)(UINTPTR)evp->sigev_value.sival_ptr);
128     if (ret != LOS_OK) {
129         errno = (ret == LOS_ERRNO_SWTMR_MAXSIZE) ? EAGAIN : EINVAL;
130         return -1;
131     }
132 
133     *timerID = (timer_t)(UINTPTR)swtmrID;
134     return 0;
135 }
136 
timer_delete(timer_t timerID)137 int timer_delete(timer_t timerID)
138 {
139     UINT16 swtmrID = (UINT16)(UINTPTR)timerID;
140 
141     if (!ValidTimerID(swtmrID)) {
142         errno = EINVAL;
143         return -1;
144     }
145 
146     if (LOS_SwtmrDelete(swtmrID) != LOS_OK) {
147         errno = EINVAL;
148         return -1;
149     }
150 
151     return 0;
152 }
153 
timer_settime(timer_t timerID,int flags,const struct itimerspec * restrict value,struct itimerspec * restrict oldValue)154 int timer_settime(timer_t timerID, int flags,
155                   const struct itimerspec *restrict value,
156                   struct itimerspec *restrict oldValue)
157 {
158     UINT32 intSave;
159     UINT16 swtmrID = (UINT16)(UINTPTR)timerID;
160     SWTMR_CTRL_S *swtmr = NULL;
161     UINT32 interval, expiry, ret;
162 
163     if (flags != 0) {
164         /* flags not supported currently */
165         errno = ENOSYS;
166         return -1;
167     }
168 
169     if (value == NULL || !ValidTimerID(swtmrID)) {
170         errno = EINVAL;
171         return -1;
172     }
173 
174     if (!ValidTimeSpec(&value->it_value) || !ValidTimeSpec(&value->it_interval)) {
175         errno = EINVAL;
176         return -1;
177     }
178 
179     expiry = OsTimeSpec2Tick(&value->it_value);
180     interval = OsTimeSpec2Tick(&value->it_interval);
181     /* if specified interval, it must be same with expiry due to the limitation of liteos-m */
182     if (interval && interval != expiry) {
183         errno = ENOTSUP;
184         return -1;
185     }
186 
187     if (oldValue) {
188         (VOID)timer_gettime(timerID, oldValue);
189     }
190 
191     ret = LOS_SwtmrStop(swtmrID);
192     if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) {
193         errno = EINVAL;
194         return -1;
195     }
196 
197     intSave = LOS_IntLock();
198     swtmr = OS_SWT_FROM_SID(swtmrID);
199     swtmr->ucMode = (interval ? LOS_SWTMR_MODE_PERIOD : LOS_SWTMR_MODE_NO_SELFDELETE);
200     swtmr->uwInterval = (interval ? interval : expiry);
201 
202     LOS_IntRestore(intSave);
203 
204     if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0)) {
205         /*
206          * 1) when expiry is 0, means timer should be stopped.
207          * 2) If timer is ticking, stopping timer is already done before.
208          * 3) If timer is created but not ticking, return 0 as well.
209          */
210         return 0;
211     }
212 
213     if (LOS_SwtmrStart(swtmr->usTimerID) != LOS_OK) {
214         errno = EINVAL;
215         return -1;
216     }
217 
218     return 0;
219 }
220 
timer_gettime(timer_t timerID,struct itimerspec * value)221 int timer_gettime(timer_t timerID, struct itimerspec *value)
222 {
223     UINT32 tick = 0;
224     SWTMR_CTRL_S *swtmr = NULL;
225     UINT16 swtmrID = (UINT16)(UINTPTR)timerID;
226     UINT32 ret;
227 
228     if ((value == NULL) || !ValidTimerID(swtmrID)) {
229         errno = EINVAL;
230         return -1;
231     }
232 
233     swtmr = OS_SWT_FROM_SID(swtmrID);
234 
235     /* get expire time */
236     ret = LOS_SwtmrTimeGet(swtmr->usTimerID, &tick);
237     if ((ret != LOS_OK) && (ret != LOS_ERRNO_SWTMR_NOT_STARTED)) {
238         errno = EINVAL;
239         return -1;
240     }
241 
242     OsTick2TimeSpec(&value->it_value, tick);
243     OsTick2TimeSpec(&value->it_interval, (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) ? 0 : swtmr->uwInterval);
244     return 0;
245 }
246 
timer_getoverrun(timer_t timerID)247 int timer_getoverrun(timer_t timerID)
248 {
249     UINT16 swtmrID = (UINT16)(UINTPTR)timerID;
250 
251     if (!ValidTimerID(swtmrID)) {
252         errno = EINVAL;
253         return -1;
254     }
255 
256     errno = ENOSYS;
257     return -1;
258 }
259