1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2019-08-21 zhangjun copy from minilibc
9 * 2020-09-07 Meco Man combine gcc armcc iccarm
10 * 2021-02-05 Meco Man add timegm()
11 * 2021-02-07 Meco Man fixed gettimeofday()
12 * 2021-02-08 Meco Man add settimeofday() stime()
13 * 2021-02-10 Meco Man add ctime_r() and re-implement ctime()
14 * 2021-02-11 Meco Man fix bug #3183 - align days[] and months[] to 4 bytes
15 * 2021-02-12 Meco Man add errno
16 * 2012-12-08 Bernard <clock_time.c> fix the issue of _timevalue.tv_usec initialization,
17 * which found by Rob <rdent@iinet.net.au>
18 * 2021-02-12 Meco Man move all of the functions located in <clock_time.c> to this file
19 * 2021-03-15 Meco Man fixed a bug of leaking memory in asctime()
20 * 2021-05-01 Meco Man support fixed timezone
21 * 2021-07-21 Meco Man implement that change/set timezone APIs
22 * 2023-07-03 xqyjlj refactor posix time and timer
23 * 2023-07-16 Shell update signal generation routine for lwp
24 * adapt to new api and do the signal handling in thread context
25 * 2023-08-12 Meco Man re-implement RT-Thread lightweight timezone API
26 * 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
27 * 2023-10-23 Shell add lock for _g_timerid
28 * 2023-11-16 Shell Fixup of nanosleep if previous call was interrupted
29 */
30
31 #include "sys/time.h"
32 #include <rthw.h>
33 #include <rtthread.h>
34 #ifdef RT_USING_RTC
35 #include <rtdevice.h>
36 #endif /* RT_USING_RTC */
37 #include <sys/errno.h>
38 #include <unistd.h>
39 #ifdef RT_USING_SMART
40 #include <lwp.h>
41 #endif
42 #ifdef RT_USING_POSIX_DELAY
43 #include <delay.h>
44 #endif
45 #ifdef RT_USING_KTIME
46 #include <ktime.h>
47 #endif
48
49 #define DBG_TAG "time"
50 #define DBG_LVL DBG_INFO
51 #include <rtdbg.h>
52
53 #define _WARNING_NO_RTC "Cannot find a RTC device!"
54
55 /* days per month -- nonleap! */
56 static const short __spm[13] =
57 {
58 0,
59 (31),
60 (31 + 28),
61 (31 + 28 + 31),
62 (31 + 28 + 31 + 30),
63 (31 + 28 + 31 + 30 + 31),
64 (31 + 28 + 31 + 30 + 31 + 30),
65 (31 + 28 + 31 + 30 + 31 + 30 + 31),
66 (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31),
67 (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30),
68 (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31),
69 (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30),
70 (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31),
71 };
72
73 rt_align(RT_ALIGN_SIZE) static const char days[] = "Sun Mon Tue Wed Thu Fri Sat ";
74 rt_align(RT_ALIGN_SIZE) static const char months[] = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ";
75
76 #ifndef __isleap
__isleap(int year)77 static int __isleap(int year)
78 {
79 /* every fourth year is a leap year except for century years that are
80 * not divisible by 400. */
81 /* return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); */
82 return (!(year % 4) && ((year % 100) || !(year % 400)));
83 }
84 #endif
85
num2str(char * c,int i)86 static void num2str(char *c, int i)
87 {
88 c[0] = i / 10 + '0';
89 c[1] = i % 10 + '0';
90 }
91
92 #ifdef RT_USING_RTC
_control_rtc(int cmd,void * arg)93 static rt_err_t _control_rtc(int cmd, void *arg)
94 {
95 static rt_device_t device = RT_NULL;
96 rt_err_t rst = -RT_ERROR;
97
98 if (device == RT_NULL)
99 {
100 device = rt_device_find("rtc");
101 }
102
103 /* read timestamp from RTC device */
104 if (device != RT_NULL)
105 {
106 if (rt_device_open(device, 0) == RT_EOK)
107 {
108 rst = rt_device_control(device, cmd, arg);
109 rt_device_close(device);
110 }
111 }
112 else
113 {
114 LOG_W(_WARNING_NO_RTC);
115 return -RT_ENOSYS;
116 }
117 return rst;
118 }
119 #endif /* RT_USING_RTC */
120
121 /* lightweight timezone and daylight saving time */
122 #ifdef RT_LIBC_USING_LIGHT_TZ_DST
123 #ifndef RT_LIBC_TZ_DEFAULT_HOUR
124 #define RT_LIBC_TZ_DEFAULT_HOUR (8U)
125 #endif /* RT_LIBC_TZ_DEFAULT_HOUR */
126
127 #ifndef RT_LIBC_TZ_DEFAULT_MIN
128 #define RT_LIBC_TZ_DEFAULT_MIN (0U)
129 #endif /* RT_LIBC_TZ_DEFAULT_MIN */
130
131 #ifndef RT_LIBC_TZ_DEFAULT_SEC
132 #define RT_LIBC_TZ_DEFAULT_SEC (0U)
133 #endif /* RT_LIBC_TZ_DEFAULT_SEC */
134
135 static volatile int32_t _current_tz_offset_sec = \
136 RT_LIBC_TZ_DEFAULT_HOUR * 3600U + RT_LIBC_TZ_DEFAULT_MIN * 60U + RT_LIBC_TZ_DEFAULT_SEC;
137
138 /* return current timezone offset in seconds */
rt_tz_set(int32_t offset_sec)139 void rt_tz_set(int32_t offset_sec)
140 {
141 _current_tz_offset_sec = offset_sec;
142 }
143
rt_tz_get(void)144 int32_t rt_tz_get(void)
145 {
146 return _current_tz_offset_sec;
147 }
148
rt_tz_is_dst(void)149 int8_t rt_tz_is_dst(void)
150 {
151 return 0U; /* TODO */
152 }
153 #endif /* RT_LIBC_USING_LIGHT_TZ_DST */
154
gmtime_r(const time_t * timep,struct tm * r)155 struct tm *gmtime_r(const time_t *timep, struct tm *r)
156 {
157 int i;
158 int work;
159
160 if(timep == RT_NULL || r == RT_NULL)
161 {
162 rt_set_errno(EFAULT);
163 return RT_NULL;
164 }
165
166 rt_memset(r, RT_NULL, sizeof(struct tm));
167
168 work = *timep % (24*60*60);
169 r->tm_sec = work % 60;
170 work /= 60;
171 r->tm_min = work % 60;
172 r->tm_hour = work / 60;
173 work = (int)(*timep / (24*60*60));
174 r->tm_wday = (4 + work) % 7;
175 for (i = 1970;; ++i)
176 {
177 int k = __isleap(i) ? 366 : 365;
178 if (work >= k)
179 work -= k;
180 else
181 break;
182 }
183 r->tm_year = i - 1900;
184 r->tm_yday = work;
185
186 r->tm_mday = 1;
187 if (__isleap(i) && (work > 58))
188 {
189 if (work == 59)
190 r->tm_mday = 2; /* 29.2. */
191 work -= 1;
192 }
193
194 for (i = 11; i && (__spm[i] > work); --i);
195
196 r->tm_mon = i;
197 r->tm_mday += work - __spm[i];
198 #if defined(RT_LIBC_USING_LIGHT_TZ_DST)
199 r->tm_isdst = rt_tz_is_dst();
200 #else
201 r->tm_isdst = 0U;
202 #endif /* RT_LIBC_USING_LIGHT_TZ_DST */
203 return r;
204 }
205 RTM_EXPORT(gmtime_r);
206
gmtime(const time_t * t)207 struct tm* gmtime(const time_t* t)
208 {
209 static struct tm tmp;
210 return gmtime_r(t, &tmp);
211 }
212 RTM_EXPORT(gmtime);
213
localtime_r(const time_t * t,struct tm * r)214 struct tm* localtime_r(const time_t* t, struct tm* r)
215 {
216 time_t local_tz;
217 #if defined(RT_LIBC_USING_LIGHT_TZ_DST)
218 local_tz = *t + rt_tz_get();
219 #else
220 local_tz = *t + 0U;
221 #endif /* RT_LIBC_USING_LIGHT_TZ_DST */
222 return gmtime_r(&local_tz, r);
223 }
224 RTM_EXPORT(localtime_r);
225
localtime(const time_t * t)226 struct tm* localtime(const time_t* t)
227 {
228 static struct tm tmp;
229 return localtime_r(t, &tmp);
230 }
231 RTM_EXPORT(localtime);
232
mktime(struct tm * const t)233 time_t mktime(struct tm * const t)
234 {
235 time_t timestamp;
236
237 timestamp = timegm(t);
238 #if defined(RT_LIBC_USING_LIGHT_TZ_DST)
239 timestamp = timestamp - rt_tz_get();
240 #else
241 timestamp = timestamp - 0U;
242 #endif /* RT_LIBC_USING_LIGHT_TZ_DST */
243 return timestamp;
244 }
245 RTM_EXPORT(mktime);
246
asctime_r(const struct tm * t,char * buf)247 char* asctime_r(const struct tm *t, char *buf)
248 {
249 if(t == RT_NULL || buf == RT_NULL)
250 {
251 rt_set_errno(EFAULT);
252 return RT_NULL;
253 }
254
255 rt_memset(buf, RT_NULL, 26);
256
257 /* Checking input validity */
258 if ((int)rt_strlen(days) <= (t->tm_wday << 2) || (int)rt_strlen(months) <= (t->tm_mon << 2))
259 {
260 LOG_W("asctime_r: the input parameters exceeded the limit, please check it.");
261 *(int*) buf = *(int*) days;
262 *(int*) (buf + 4) = *(int*) months;
263 num2str(buf + 8, t->tm_mday);
264 if (buf[8] == '0')
265 buf[8] = ' ';
266 buf[10] = ' ';
267 num2str(buf + 11, t->tm_hour);
268 buf[13] = ':';
269 num2str(buf + 14, t->tm_min);
270 buf[16] = ':';
271 num2str(buf + 17, t->tm_sec);
272 buf[19] = ' ';
273 num2str(buf + 20, 2000 / 100);
274 num2str(buf + 22, 2000 % 100);
275 buf[24] = '\n';
276 buf[25] = '\0';
277 return buf;
278 }
279
280 /* "Wed Jun 30 21:49:08 1993\n" */
281 *(int*) buf = *(int*) (days + (t->tm_wday << 2));
282 *(int*) (buf + 4) = *(int*) (months + (t->tm_mon << 2));
283 num2str(buf + 8, t->tm_mday);
284 if (buf[8] == '0')
285 buf[8] = ' ';
286 buf[10] = ' ';
287 num2str(buf + 11, t->tm_hour);
288 buf[13] = ':';
289 num2str(buf + 14, t->tm_min);
290 buf[16] = ':';
291 num2str(buf + 17, t->tm_sec);
292 buf[19] = ' ';
293 num2str(buf + 20, (t->tm_year + 1900) / 100);
294 num2str(buf + 22, (t->tm_year + 1900) % 100);
295 buf[24] = '\n';
296 buf[25] = '\0';
297 return buf;
298 }
299 RTM_EXPORT(asctime_r);
300
asctime(const struct tm * timeptr)301 char *asctime(const struct tm *timeptr)
302 {
303 static char buf[26];
304 return asctime_r(timeptr, buf);
305 }
306 RTM_EXPORT(asctime);
307
ctime_r(const time_t * tim_p,char * result)308 char *ctime_r(const time_t * tim_p, char * result)
309 {
310 struct tm tm;
311 return asctime_r(localtime_r(tim_p, &tm), result);
312 }
313 RTM_EXPORT(ctime_r);
314
ctime(const time_t * tim_p)315 char *ctime(const time_t *tim_p)
316 {
317 return asctime(localtime(tim_p));
318 }
319 RTM_EXPORT(ctime);
320
321 #if (!defined __ARMCC_VERSION) && (!defined __CC_ARM) && (!defined __ICCARM__)
difftime(time_t time1,time_t time2)322 double difftime(time_t time1, time_t time2)
323 {
324 return (double)(time1 - time2);
325 }
326 #endif
327 RTM_EXPORT(difftime);
328
329 RTM_EXPORT(strftime); /* inherent in the toolchain */
330
331 /**
332 * Returns the current time.
333 *
334 * @param time_t * t the timestamp pointer, if not used, keep NULL.
335 *
336 * @return The value ((time_t)-1) is returned if the calendar time is not available.
337 * If timer is not a NULL pointer, the return value is also stored in timer.
338 *
339 */
time(time_t * t)340 rt_weak time_t time(time_t *t)
341 {
342 #ifdef RT_USING_RTC
343 time_t _t;
344
345 if (_control_rtc(RT_DEVICE_CTRL_RTC_GET_TIME, &_t) != RT_EOK)
346 {
347 rt_set_errno(EFAULT);
348 return (time_t)-1;
349 }
350
351 if (t)
352 *t = _t;
353
354 return _t;
355 #else
356 rt_set_errno(EFAULT);
357 return (time_t)-1;
358 #endif
359 }
360 RTM_EXPORT(time);
361
clock(void)362 rt_weak clock_t clock(void)
363 {
364 return rt_tick_get(); // TODO should return cpu usage time
365 }
366 RTM_EXPORT(clock);
367
stime(const time_t * t)368 int stime(const time_t *t)
369 {
370 #ifdef RT_USING_RTC
371 if ((t != RT_NULL) && (_control_rtc(RT_DEVICE_CTRL_RTC_SET_TIME, (void *)t) == RT_EOK))
372 {
373 return 0;
374 }
375 #endif /* RT_USING_RTC */
376
377 rt_set_errno(EFAULT);
378 return -1;
379 }
380 RTM_EXPORT(stime);
381
timegm(struct tm * const t)382 time_t timegm(struct tm * const t)
383 {
384 time_t day;
385 time_t i;
386 time_t years;
387
388 if(t == RT_NULL)
389 {
390 rt_set_errno(EFAULT);
391 return (time_t)-1;
392 }
393
394 years = (time_t)t->tm_year - 70;
395 if (t->tm_sec > 60) /* seconds after the minute - [0, 60] including leap second */
396 {
397 t->tm_min += t->tm_sec / 60;
398 t->tm_sec %= 60;
399 }
400 if (t->tm_min >= 60) /* minutes after the hour - [0, 59] */
401 {
402 t->tm_hour += t->tm_min / 60;
403 t->tm_min %= 60;
404 }
405 if (t->tm_hour >= 24) /* hours since midnight - [0, 23] */
406 {
407 t->tm_mday += t->tm_hour / 24;
408 t->tm_hour %= 24;
409 }
410 if (t->tm_mon >= 12) /* months since January - [0, 11] */
411 {
412 t->tm_year += t->tm_mon / 12;
413 t->tm_mon %= 12;
414 }
415 while (t->tm_mday > __spm[1 + t->tm_mon])
416 {
417 if (t->tm_mon == 1 && __isleap(t->tm_year + 1900))
418 {
419 --t->tm_mday;
420 }
421 t->tm_mday -= __spm[t->tm_mon];
422 ++t->tm_mon;
423 if (t->tm_mon > 11)
424 {
425 t->tm_mon = 0;
426 ++t->tm_year;
427 }
428 }
429
430 if (t->tm_year < 70)
431 {
432 rt_set_errno(EINVAL);
433 return (time_t) -1;
434 }
435
436 /* Days since 1970 is 365 * number of years + number of leap years since 1970 */
437 day = years * 365 + (years + 1) / 4;
438
439 /* After 2100 we have to substract 3 leap years for every 400 years
440 This is not intuitive. Most mktime implementations do not support
441 dates after 2059, anyway, so we might leave this out for it's
442 bloat. */
443 if (years >= 131)
444 {
445 years -= 131;
446 years /= 100;
447 day -= (years >> 2) * 3 + 1;
448 if ((years &= 3) == 3)
449 years--;
450 day -= years;
451 }
452
453 day += t->tm_yday = __spm[t->tm_mon] + t->tm_mday - 1 +
454 (__isleap(t->tm_year + 1900) & (t->tm_mon > 1));
455
456 /* day is now the number of days since 'Jan 1 1970' */
457 i = 7;
458 t->tm_wday = (int)((day + 4) % i); /* Sunday=0, Monday=1, ..., Saturday=6 */
459
460 i = 24;
461 day *= i;
462 i = 60;
463 return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec;
464 }
465 RTM_EXPORT(timegm);
466
gettimeofday(struct timeval * tv,struct timezone * tz)467 int gettimeofday(struct timeval *tv, struct timezone *tz)
468 {
469 /* The use of the timezone structure is obsolete;
470 * the tz argument should normally be specified as NULL.
471 * The tz_dsttime field has never been used under Linux.
472 * Thus, the following is purely of historic interest.
473 */
474 if(tz != RT_NULL)
475 {
476 tz->tz_dsttime = DST_NONE;
477 #if defined(RT_LIBC_USING_LIGHT_TZ_DST)
478 tz->tz_minuteswest = -(rt_tz_get() / 60);
479 #else
480 tz->tz_minuteswest = 0;
481 #endif /* RT_LIBC_USING_LIGHT_TZ_DST */
482 }
483
484 #ifdef RT_USING_RTC
485 if (tv != RT_NULL)
486 {
487 tv->tv_sec = 0;
488 tv->tv_usec = 0;
489
490 if (_control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMEVAL, tv) == RT_EOK)
491 {
492 return 0;
493 }
494 else
495 {
496 if (_control_rtc(RT_DEVICE_CTRL_RTC_GET_TIME, (void *)&tv->tv_sec) == RT_EOK)
497 {
498 return 0;
499 }
500 }
501 }
502 #endif /* RT_USING_RTC */
503
504 rt_set_errno(EINVAL);
505 return -1;
506 }
507 RTM_EXPORT(gettimeofday);
508
settimeofday(const struct timeval * tv,const struct timezone * tz)509 int settimeofday(const struct timeval *tv, const struct timezone *tz)
510 {
511 /* The use of the timezone structure is obsolete;
512 * the tz argument should normally be specified as NULL.
513 * The tz_dsttime field has never been used under Linux.
514 * Thus, the following is purely of historic interest.
515 */
516 #ifdef RT_USING_RTC
517 if (tv != RT_NULL && (long)tv->tv_usec >= 0 && (long)tv->tv_sec >= 0)
518 {
519 if (_control_rtc(RT_DEVICE_CTRL_RTC_SET_TIMEVAL, (void *)tv) == RT_EOK)
520 {
521 return 0;
522 }
523 else
524 {
525 if (_control_rtc(RT_DEVICE_CTRL_RTC_SET_TIME, (void *)&tv->tv_sec) == RT_EOK)
526 {
527 return 0;
528 }
529 }
530 }
531 #endif /* RT_USING_RTC */
532
533 rt_set_errno(EINVAL);
534 return -1;
535 }
536 RTM_EXPORT(settimeofday);
537
538 #if defined(RT_USING_POSIX_DELAY) && defined(RT_USING_KTIME)
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)539 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
540 {
541 struct timespec old_ts = {0};
542 struct timespec new_ts = {0};
543 struct rt_ktime_hrtimer timer;
544
545 rt_ktime_hrtimer_delay_init(&timer);
546
547 if (rqtp == RT_NULL)
548 {
549 rt_set_errno(EFAULT);
550 return -1;
551 }
552
553 if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
554 {
555 rt_set_errno(EINVAL);
556 return -1;
557 }
558 unsigned long ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec;
559 rt_ktime_boottime_get_ns(&old_ts);
560 rt_ktime_hrtimer_ndelay(&timer, ns);
561 if (rt_get_errno() == RT_EINTR)
562 {
563 if (rmtp)
564 {
565 rt_base_t rsec, rnsec;
566 rt_ktime_boottime_get_ns(&new_ts);
567
568 rsec = old_ts.tv_sec + rqtp->tv_sec - new_ts.tv_sec;
569 rnsec = old_ts.tv_nsec + rqtp->tv_nsec - new_ts.tv_nsec;
570 if (rnsec < 0)
571 {
572 rmtp->tv_sec = rsec - 1;
573 rmtp->tv_nsec = NANOSECOND_PER_SECOND + rnsec;
574 }
575 else
576 {
577 rmtp->tv_sec = rsec;
578 rmtp->tv_nsec = rnsec;
579 }
580 }
581
582 rt_ktime_hrtimer_delay_detach(&timer);
583 rt_set_errno(EINTR);
584 return -1;
585 }
586
587 rt_ktime_hrtimer_delay_detach(&timer);
588 return 0;
589 }
590 RTM_EXPORT(nanosleep);
591 #endif /* RT_USING_POSIX_DELAY && RT_USING_KTIME */
592
593 #if defined(RT_USING_POSIX_CLOCK) && defined(RT_USING_KTIME)
594
clock_getres(clockid_t clockid,struct timespec * res)595 int clock_getres(clockid_t clockid, struct timespec *res)
596 {
597 if (res == RT_NULL)
598 {
599 rt_set_errno(EFAULT);
600 return -1;
601 }
602
603 switch (clockid)
604 {
605 case CLOCK_REALTIME: // use RTC
606 case CLOCK_REALTIME_COARSE:
607 #ifdef RT_USING_RTC
608 return _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMERES, res);
609 #endif /* RT_USING_RTC */
610
611 case CLOCK_MONOTONIC: // use cputimer
612 case CLOCK_MONOTONIC_COARSE:
613 case CLOCK_MONOTONIC_RAW:
614 case CLOCK_BOOTTIME:
615 case CLOCK_PROCESS_CPUTIME_ID:
616 case CLOCK_THREAD_CPUTIME_ID:
617 res->tv_sec = 0;
618 res->tv_nsec = (rt_ktime_cputimer_getres() / RT_KTIME_RESMUL);
619 return 0;
620
621 default:
622 rt_set_errno(EINVAL);
623 return -1;
624 }
625 }
626 RTM_EXPORT(clock_getres);
627
clock_gettime(clockid_t clockid,struct timespec * tp)628 int clock_gettime(clockid_t clockid, struct timespec *tp)
629 {
630 if (tp == RT_NULL)
631 {
632 rt_set_errno(EFAULT);
633 return -1;
634 }
635
636 switch (clockid)
637 {
638 case CLOCK_REALTIME: // use RTC
639 case CLOCK_REALTIME_COARSE:
640 #ifdef RT_USING_RTC
641 return _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMESPEC, tp);
642 #endif /* RT_USING_RTC */
643
644 case CLOCK_MONOTONIC: // use boottime
645 case CLOCK_MONOTONIC_COARSE:
646 case CLOCK_MONOTONIC_RAW:
647 case CLOCK_BOOTTIME:
648 return rt_ktime_boottime_get_ns(tp);
649
650 case CLOCK_PROCESS_CPUTIME_ID:
651 case CLOCK_THREAD_CPUTIME_ID:
652 return rt_ktime_boottime_get_ns(tp); // TODO not yet implemented
653
654 default:
655 tp->tv_sec = 0;
656 tp->tv_nsec = 0;
657 rt_set_errno(EINVAL);
658 return -1;
659 }
660 }
661 RTM_EXPORT(clock_gettime);
662
clock_nanosleep(clockid_t clockid,int flags,const struct timespec * rqtp,struct timespec * rmtp)663 int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp)
664 {
665 struct timespec ts = {0};
666 rt_err_t err = -RT_EINVAL;
667
668 if (rqtp == RT_NULL)
669 {
670 rt_set_errno(EFAULT);
671 return -1;
672 }
673
674 if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
675 {
676 rt_set_errno(EINVAL);
677 return -1;
678 }
679
680 switch (clockid)
681 {
682 case CLOCK_REALTIME: // use RTC
683 #ifdef RT_USING_RTC
684 if (flags & TIMER_ABSTIME)
685 err = _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMESPEC, &ts);
686 break;
687 #endif /* RT_USING_RTC */
688
689 case CLOCK_MONOTONIC: // use boottime
690 case CLOCK_PROCESS_CPUTIME_ID:
691 if (flags & TIMER_ABSTIME)
692 err = rt_ktime_boottime_get_ns(&ts);
693 break;
694
695 default:
696 rt_set_errno(EINVAL);
697 return -1;
698 }
699
700 if (err != RT_EOK)
701 return err;
702
703 int64_t ns = rqtp->tv_nsec - ts.tv_nsec + (rqtp->tv_sec - ts.tv_sec) * NANOSECOND_PER_SECOND;
704 if (ns <= 0)
705 return 0;
706
707 if (flags & TIMER_ABSTIME)
708 {
709 ts.tv_nsec = ns % NANOSECOND_PER_SECOND;
710 ts.tv_sec = ns / NANOSECOND_PER_SECOND;
711 return nanosleep(&ts, rmtp);
712 }
713 else
714 {
715 return nanosleep(rqtp, rmtp);
716 }
717 }
718 RTM_EXPORT(clock_nanosleep);
719
clock_settime(clockid_t clockid,const struct timespec * tp)720 int clock_settime(clockid_t clockid, const struct timespec *tp)
721 {
722 if (tp == RT_NULL)
723 {
724 rt_set_errno(EFAULT);
725 return -1;
726 }
727
728 if (tp->tv_sec < 0 || tp->tv_nsec < 0 || tp->tv_nsec >= NANOSECOND_PER_SECOND)
729 {
730 rt_set_errno(EINVAL);
731 return -1;
732 }
733
734 switch (clockid)
735 {
736 #ifdef RT_USING_RTC
737 case CLOCK_REALTIME:
738 return _control_rtc(RT_DEVICE_CTRL_RTC_SET_TIMESPEC, (void *)tp);
739 #endif /* RT_USING_RTC */
740
741 case CLOCK_REALTIME_COARSE:
742 case CLOCK_MONOTONIC:
743 case CLOCK_MONOTONIC_COARSE:
744 case CLOCK_MONOTONIC_RAW:
745 case CLOCK_BOOTTIME:
746 case CLOCK_PROCESS_CPUTIME_ID:
747 case CLOCK_THREAD_CPUTIME_ID:
748 rt_set_errno(EPERM);
749 return -1;
750
751 default:
752 rt_set_errno(EINVAL);
753 return -1;
754 }
755 }
756 RTM_EXPORT(clock_settime);
757
rt_timespec_to_tick(const struct timespec * time)758 int rt_timespec_to_tick(const struct timespec *time)
759 {
760 int tick;
761 int second;
762 long long nsecond;
763 struct timespec tp = {0};
764
765 RT_ASSERT(time != RT_NULL);
766
767 tick = RT_WAITING_FOREVER;
768 if (time != NULL)
769 {
770 /* get current tp */
771 clock_gettime(CLOCK_REALTIME, &tp);
772
773 if ((time->tv_nsec - tp.tv_nsec) < 0)
774 {
775 nsecond = NANOSECOND_PER_SECOND - (tp.tv_nsec - time->tv_nsec);
776 second = time->tv_sec - tp.tv_sec - 1;
777 }
778 else
779 {
780 nsecond = time->tv_nsec - tp.tv_nsec;
781 second = time->tv_sec - tp.tv_sec;
782 }
783
784 tick = second * RT_TICK_PER_SECOND + nsecond * RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND;
785 if (tick < 0) tick = 0;
786 }
787
788 return tick;
789 }
790 RTM_EXPORT(rt_timespec_to_tick);
791
792 #endif /* RT_USING_POSIX_CLOCK && RT_USING_KTIME */
793
794 #if defined(RT_USING_POSIX_TIMER) && defined(RT_USING_KTIME)
795
796 #include <resource_id.h>
797
798 #define ACTIVE 1
799 #define NOT_ACTIVE 0
800
801 struct timer_obj
802 {
803 struct rt_ktime_hrtimer hrtimer;
804 void (*sigev_notify_func)(union sigval val);
805 union sigval val;
806 struct timespec interval; /* Reload value */
807 struct timespec value; /* Reload value */
808 unsigned long reload; /* Reload value in ms */
809 rt_uint32_t status;
810 int sigev_signo;
811 clockid_t clockid;
812 timer_t timer_id;
813 #ifdef RT_USING_SMART
814 pid_t pid;
815 struct rt_work *work;
816 rt_list_t lwp_node;
817 #endif
818 };
819
820 #ifdef RT_USING_SMART
821 struct lwp_timer_event_param
822 {
823 struct rt_work work;
824
825 union
826 {
827 int tid;
828 pid_t pid;
829 };
830 int signo;
831 };
832
_lwp_timer_event_from_tid(struct rt_work * work,void * param)833 static void _lwp_timer_event_from_tid(struct rt_work *work, void *param)
834 {
835 rt_err_t ret;
836 struct lwp_timer_event_param *data = rt_container_of(work, struct lwp_timer_event_param, work);
837 rt_thread_t thread;
838
839 RT_ASSERT(data->tid);
840
841 /* stop others from delete thread */
842 thread = lwp_tid_get_thread_and_inc_ref(data->tid);
843 /** The tid of thread is a READ ONLY value, but here still facing the risk of thread already been delete error */
844 ret = lwp_thread_signal_kill(thread, data->signo, SI_TIMER, 0);
845 lwp_tid_dec_ref(thread);
846
847 if (ret)
848 {
849 LOG_D("%s: Do kill failed(tid %d) returned %d", __func__, data->tid, ret);
850 }
851 }
852
_lwp_timer_event_from_pid(struct rt_work * work,void * param)853 static void _lwp_timer_event_from_pid(struct rt_work *work, void *param)
854 {
855 rt_err_t ret;
856 struct lwp_timer_event_param *data = rt_container_of(work, struct lwp_timer_event_param, work);
857 struct rt_lwp *lwp;
858
859 lwp_pid_lock_take();
860 lwp = lwp_from_pid_locked(data->pid);
861 if (lwp)
862 lwp_ref_inc(lwp);
863 lwp_pid_lock_release();
864
865 ret = lwp_signal_kill(lwp, data->signo, SI_TIMER, 0);
866 if (lwp)
867 lwp_ref_dec(lwp);
868
869 if (ret)
870 {
871 LOG_D("%s: Do kill failed(pid %d) returned %d", __func__, data->pid, ret);
872 }
873 }
874
timer_list_free(rt_list_t * timer_list)875 int timer_list_free(rt_list_t *timer_list)
876 {
877 struct timer_obj *pos, *n;
878 rt_list_for_each_entry_safe(pos, n, timer_list, lwp_node)
879 {
880 timer_delete(pos->timer_id);
881 }
882 return 0;
883 }
884
885 #endif /* RT_USING_SMART */
886
rtthread_timer_wrapper(void * timerobj)887 static void rtthread_timer_wrapper(void *timerobj)
888 {
889 struct timer_obj *timer;
890
891 timer = (struct timer_obj *)timerobj;
892
893 if (timer->reload == 0U)
894 {
895 timer->status = NOT_ACTIVE;
896 }
897
898 timer->reload = ((timer->interval.tv_sec * NANOSECOND_PER_SECOND + timer->interval.tv_nsec) * RT_KTIME_RESMUL) /
899 rt_ktime_cputimer_getres();
900 if (timer->reload)
901 {
902 rt_ktime_hrtimer_start(&timer->hrtimer, timer->reload);
903 }
904 #ifdef RT_USING_SMART
905 /* this field is named as tid in musl */
906 void *ptid = &timer->sigev_notify_func;
907 int tid = *(int *)ptid;
908 struct lwp_timer_event_param *data = rt_container_of(timer->work, struct lwp_timer_event_param, work);
909 data->signo = timer->sigev_signo;
910
911 if (!tid)
912 {
913 data->pid = timer->pid;
914 rt_work_init(timer->work, _lwp_timer_event_from_pid, 0);
915 }
916 else
917 {
918 data->tid = tid;
919 rt_work_init(timer->work, _lwp_timer_event_from_tid, 0);
920 }
921
922 if (rt_work_submit(timer->work, 0))
923 RT_ASSERT(0);
924 #else
925 if(timer->sigev_notify_func != RT_NULL)
926 {
927 (timer->sigev_notify_func)(timer->val);
928 }
929 #endif /* RT_USING_SMART */
930 }
931
932 #define TIMER_ID_MAX 50
933 static struct rt_spinlock _timer_id_lock = RT_SPINLOCK_INIT;
934 static struct timer_obj *_g_timerid[TIMER_ID_MAX];
935 static void *timer_id[TIMER_ID_MAX];
936 static resource_id_t id_timer = RESOURCE_ID_INIT(TIMER_ID_MAX, timer_id);
937
938 /**
939 * @brief Create a per-process timer.
940 *
941 * This API does not accept SIGEV_THREAD as valid signal event notification
942 * type.
943 *
944 * See IEEE 1003.1
945 */
timer_create(clockid_t clockid,struct sigevent * evp,timer_t * timerid)946 int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
947 {
948 static int num = 0;
949 int _timerid = 0;
950 struct timer_obj *timer;
951 char timername[RT_NAME_MAX] = {0};
952
953 if (evp == RT_NULL || timerid == RT_NULL)
954 {
955 rt_set_errno(EINVAL);
956 return -1;
957 }
958
959 if (evp->sigev_notify == SIGEV_THREAD) // TODO need to implement
960 {
961 rt_set_errno(EINVAL);
962 return -1;
963 }
964
965 switch (clockid)
966 {
967 case CLOCK_REALTIME:
968 case CLOCK_REALTIME_ALARM:
969 case CLOCK_MONOTONIC:
970 case CLOCK_BOOTTIME:
971 case CLOCK_BOOTTIME_ALARM:
972 case CLOCK_PROCESS_CPUTIME_ID:
973 case CLOCK_THREAD_CPUTIME_ID:
974 break; // Only these ids are supported
975 default:
976 rt_set_errno(EINVAL);
977 return -1;
978 }
979
980 timer = rt_malloc(sizeof(struct timer_obj));
981 if(timer == RT_NULL)
982 {
983 rt_set_errno(ENOMEM);
984 return -1;
985 }
986
987 rt_snprintf(timername, RT_NAME_MAX, "psx_tm%02d", num++);
988 num %= 100;
989 timer->sigev_signo = evp->sigev_signo;
990 #ifdef RT_USING_SMART
991 struct rt_work *work;
992 struct rt_lwp *lwp = lwp_self();
993 struct lwp_timer_event_param *param;
994 param = rt_malloc(sizeof(struct lwp_timer_event_param));
995 work = ¶m->work;
996
997 if (!work)
998 {
999 rt_set_errno(ENOMEM);
1000 return -1;
1001 }
1002
1003 if (lwp)
1004 {
1005 timer->pid = lwp_self()->pid;
1006 rt_list_insert_after(&lwp->timer, &timer->lwp_node);
1007 }
1008 else
1009 {
1010 timer->pid = 0; /* pid 0 is never used */
1011 }
1012
1013 timer->work = work;
1014 #endif /* RT_USING_SMART */
1015 timer->sigev_notify_func = evp->sigev_notify_function;
1016 timer->val = evp->sigev_value;
1017 timer->interval.tv_sec = 0;
1018 timer->interval.tv_nsec = 0;
1019 timer->reload = 0U;
1020 timer->status = NOT_ACTIVE;
1021 timer->clockid = clockid;
1022
1023 rt_ktime_hrtimer_init(&timer->hrtimer, timername, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
1024 rtthread_timer_wrapper, timer);
1025
1026 _timerid = resource_id_get(&id_timer);
1027 if (_timerid < 0)
1028 {
1029 #ifdef RT_USING_SMART
1030 rt_free(param);
1031 #endif /* RT_USING_SMART */
1032
1033 rt_ktime_hrtimer_detach(&timer->hrtimer);
1034 rt_free(timer);
1035 rt_set_errno(ENOMEM);
1036 return -1;
1037 }
1038 _g_timerid[_timerid] = timer;
1039
1040 timer->timer_id = (timer_t)(rt_ubase_t)_timerid;
1041 *timerid = (timer_t)(rt_ubase_t)_timerid;
1042
1043 return 0;
1044 }
1045 RTM_EXPORT(timer_create);
1046
1047 /**
1048 * @brief Delete a per-process timer.
1049 *
1050 * See IEEE 1003.1
1051 */
timer_delete(timer_t timerid)1052 int timer_delete(timer_t timerid)
1053 {
1054 struct timer_obj *timer;
1055 rt_ubase_t ktimerid;
1056
1057 ktimerid = (rt_ubase_t)timerid;
1058
1059 if (ktimerid < 0 || ktimerid >= TIMER_ID_MAX)
1060 {
1061 rt_set_errno(EINVAL);
1062 return -1;
1063 }
1064
1065 RT_DEBUG_NOT_IN_INTERRUPT;
1066 rt_spin_lock(&_timer_id_lock);
1067 timer = _g_timerid[ktimerid];
1068 if (timer != NULL)
1069 {
1070 _g_timerid[ktimerid] = RT_NULL;
1071 resource_id_put(&id_timer, ktimerid);
1072 }
1073 rt_spin_unlock(&_timer_id_lock);
1074
1075 if (timer == RT_NULL)
1076 {
1077 rt_set_errno(EINVAL);
1078 LOG_D("can not find timer %ld", ktimerid);
1079 return -1;
1080 }
1081
1082 if (timer->status == ACTIVE)
1083 {
1084 timer->status = NOT_ACTIVE;
1085 rt_ktime_hrtimer_stop(&timer->hrtimer);
1086 }
1087 rt_ktime_hrtimer_detach(&timer->hrtimer);
1088
1089 #ifdef RT_USING_SMART
1090 if (timer->pid)
1091 rt_list_remove(&timer->lwp_node);
1092 rt_free(timer->work);
1093 #endif
1094 rt_free(timer);
1095 return 0;
1096 }
1097 RTM_EXPORT(timer_delete);
1098
1099 /**
1100 *
1101 * Return the overrun count for the last timer expiration.
1102 * It is subefficient to create a new structure to get overrun count.
1103 **/
timer_getoverrun(timer_t timerid)1104 int timer_getoverrun(timer_t timerid)
1105 {
1106 rt_set_errno(ENOSYS);
1107 return -1;
1108 }
1109
1110 /**
1111 * @brief Get amount of time left for expiration on a per-process timer.
1112 *
1113 * See IEEE 1003.1
1114 */
timer_gettime(timer_t timerid,struct itimerspec * its)1115 int timer_gettime(timer_t timerid, struct itimerspec *its)
1116 {
1117 struct timer_obj *timer;
1118 rt_uint32_t seconds, nanoseconds;
1119
1120 timer = _g_timerid[(rt_ubase_t)timerid];
1121
1122 if (timer == NULL)
1123 {
1124 rt_set_errno(EINVAL);
1125 return -1;
1126 }
1127
1128 if (its == NULL)
1129 {
1130 rt_set_errno(EFAULT);
1131 return -1;
1132 }
1133
1134 if (timer->status == ACTIVE)
1135 {
1136 unsigned long remain_cnt;
1137 rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_cnt);
1138 nanoseconds = ((remain_cnt - rt_ktime_cputimer_getcnt()) * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL;
1139 seconds = nanoseconds / NANOSECOND_PER_SECOND;
1140 nanoseconds = nanoseconds % NANOSECOND_PER_SECOND;
1141 its->it_value.tv_sec = (rt_int32_t)seconds;
1142 its->it_value.tv_nsec = (rt_int32_t)nanoseconds;
1143 }
1144 else
1145 {
1146 /* Timer is disarmed */
1147 its->it_value.tv_sec = 0;
1148 its->it_value.tv_nsec = 0;
1149 }
1150
1151 /* The interval last set by timer_settime() */
1152 its->it_interval = timer->interval;
1153 return 0;
1154 }
1155 RTM_EXPORT(timer_gettime);
1156
1157 /**
1158 * @brief Sets expiration time of per-process timer.
1159 *
1160 * See IEEE 1003.1
1161 */
timer_settime(timer_t timerid,int flags,const struct itimerspec * value,struct itimerspec * ovalue)1162 int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
1163 struct itimerspec *ovalue)
1164 {
1165 struct timespec ts = {0};
1166 rt_err_t err = RT_EOK;
1167
1168 struct timer_obj *timer;
1169 timer = _g_timerid[(rt_ubase_t)timerid];
1170 if (timer == NULL ||
1171 value->it_interval.tv_nsec < 0 ||
1172 value->it_interval.tv_nsec >= NANOSECOND_PER_SECOND ||
1173 value->it_interval.tv_sec < 0 ||
1174 value->it_value.tv_nsec < 0 ||
1175 value->it_value.tv_nsec >= NANOSECOND_PER_SECOND ||
1176 value->it_value.tv_sec < 0)
1177 {
1178 rt_set_errno(EINVAL);
1179 return -1;
1180 }
1181
1182 /* Save time to expire and old reload value. */
1183 if (ovalue != NULL)
1184 {
1185 timer_gettime(timerid, ovalue);
1186 }
1187
1188 /* Stop the timer if the value is 0 */
1189 if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0))
1190 {
1191 if (timer->status == ACTIVE)
1192 {
1193 rt_ktime_hrtimer_stop(&timer->hrtimer);
1194 }
1195
1196 timer->status = NOT_ACTIVE;
1197 return 0;
1198 }
1199
1200 switch (timer->clockid)
1201 {
1202 #ifdef RT_USING_RTC
1203 case CLOCK_REALTIME:
1204 case CLOCK_REALTIME_ALARM:
1205 if (flags & TIMER_ABSTIME)
1206 err = _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMESPEC, &ts);
1207 break;
1208 #endif /* RT_USING_RTC */
1209 case CLOCK_MONOTONIC:
1210 case CLOCK_BOOTTIME:
1211 case CLOCK_BOOTTIME_ALARM:
1212 case CLOCK_PROCESS_CPUTIME_ID:
1213 case CLOCK_THREAD_CPUTIME_ID:
1214 if (flags & TIMER_ABSTIME)
1215 err = rt_ktime_boottime_get_ns(&ts);
1216 break;
1217 default:
1218 rt_set_errno(EINVAL);
1219 return -1;
1220 }
1221
1222 if (err != RT_EOK)
1223 return err;
1224
1225 int64_t ns = value->it_value.tv_nsec - ts.tv_nsec + (value->it_value.tv_sec - ts.tv_sec) * NANOSECOND_PER_SECOND;
1226
1227 if (ns <= 0)
1228 return 0;
1229
1230 unsigned long res = rt_ktime_cputimer_getres();
1231 timer->reload = (ns * RT_KTIME_RESMUL) / res;
1232 timer->interval.tv_sec = value->it_interval.tv_sec;
1233 timer->interval.tv_nsec = value->it_interval.tv_nsec;
1234 timer->value.tv_sec = value->it_value.tv_sec;
1235 timer->value.tv_nsec = value->it_value.tv_nsec;
1236
1237 if (timer->status == ACTIVE)
1238 {
1239 rt_ktime_hrtimer_stop(&timer->hrtimer);
1240 }
1241 timer->status = ACTIVE;
1242
1243 if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0))
1244 rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL);
1245 else
1246 rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL);
1247
1248 rt_ktime_hrtimer_start(&timer->hrtimer, timer->reload);
1249
1250 return 0;
1251 }
1252 RTM_EXPORT(timer_settime);
1253 #endif /* RT_USING_POSIX_TIMER && RT_USING_KTIME */
1254