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 = &param->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