1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <stdint.h>
6 #include <time.h>
7 
8 #include <aos/errno.h>
9 #include <aos/kernel.h>
10 
clock_getres(clockid_t clock_id,struct timespec * res)11 int clock_getres(clockid_t clock_id, struct timespec *res)
12 {
13     /* At now, only support CLOCK_REALTIME/CLOCK_MONOTONIC clock. */
14     if (((clock_id != CLOCK_REALTIME) && (clock_id != CLOCK_MONOTONIC)) || (res == NULL)) {
15         errno = EINVAL;
16         return -1;
17     }
18 
19     res->tv_sec = 0;
20     res->tv_nsec = 1000000;
21 
22     return 0;
23 }
24 
clock_gettime(clockid_t clock_id,struct timespec * tp)25 int clock_gettime(clockid_t clock_id, struct timespec *tp)
26 {
27     uint64_t time_ms = 0;
28 
29     if (tp == NULL) {
30         errno = EINVAL;
31         return -1;
32     }
33 
34     if (clock_id == CLOCK_MONOTONIC) {
35         time_ms = aos_now_ms();
36         tp->tv_sec = time_ms / 1000;
37         tp->tv_nsec = (time_ms % 1000) * 1000000;
38     } else if (clock_id == CLOCK_REALTIME) {
39         time_ms = aos_calendar_time_get();
40         tp->tv_sec = time_ms / 1000;
41         tp->tv_nsec = (time_ms % 1000) * 1000000;
42     } else {
43         errno = EINVAL;
44         return -1;
45     }
46 
47     return 0;
48 }
49 
clock_settime(clockid_t clock_id,const struct timespec * tp)50 int clock_settime(clockid_t clock_id, const struct timespec *tp)
51 {
52     uint64_t time_ms = 0;
53 
54     /* only CLOCK_REALTIME can be set */
55     if ((clock_id != CLOCK_REALTIME) || (tp == NULL) ||
56         (tp->tv_nsec < 0) || (tp->tv_nsec >= 1000000000UL)) {
57         errno = EINVAL;
58         return -1;
59     }
60 
61     time_ms = (tp->tv_sec * 1000) + (tp->tv_nsec / 1000000);
62     aos_calendar_time_set(time_ms);
63 
64     return 0;
65 }
66 
clock_nanosleep(clockid_t clock_id,int flags,const struct timespec * rqtp,struct timespec * rmtp)67 int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp,
68                     struct timespec *rmtp)
69 {
70     int ret = 0;
71     int64_t time_ms = 0;
72     struct timespec tp = {0};
73 
74     (void)rmtp;
75 
76     if ((rqtp == NULL) || (rqtp->tv_sec < 0) || (rqtp->tv_nsec < 0)
77                        || (rqtp->tv_nsec >= 1000000000UL)) {
78         return EINVAL;
79     }
80 
81     if ((clock_id != CLOCK_MONOTONIC) && (clock_id != CLOCK_REALTIME)) {
82         return EINVAL;
83     }
84 
85     if (flags == TIMER_ABSTIME) {
86         /* absolute time */
87         ret = clock_gettime(clock_id, &tp);
88         if (ret != 0) {
89             return ENOTSUP;
90         }
91 
92         time_ms = (rqtp->tv_sec - tp.tv_sec) * 1000 + (rqtp->tv_nsec - tp.tv_nsec) / 1000000;
93         if (time_ms <= 0) {
94             /* The absolute time has passed, do not need to sleep. */
95             return 0;
96         }
97 
98     } else {
99         /* relative time */
100         time_ms = rqtp->tv_sec * 1000 + rqtp->tv_nsec / 1000000;
101     }
102 
103     aos_msleep(time_ms);
104 
105     return 0;
106 }
107 
108 /* Only support milliseconds resulation now by system tick. */
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)109 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
110 {
111     uint64_t time_ms = 0;
112 
113     /* The rmtp parameter is not supported, because signal is not supported. */
114     (void)rmtp;
115 
116     if ((rqtp == NULL) || (rqtp->tv_sec < 0) || (rqtp->tv_nsec < 0)
117                        || (rqtp->tv_nsec >= 1000000000UL)) {
118         errno = EINVAL;
119         return -1;
120     }
121 
122     time_ms = (rqtp->tv_sec * 1000) + (rqtp->tv_nsec / 1000000);
123     aos_msleep(time_ms);
124 
125     return 0;
126 }
127 
sleep(unsigned int seconds)128 unsigned int sleep(unsigned int seconds)
129 {
130     struct timespec tv = { .tv_sec = seconds, .tv_nsec = 0 };
131 
132     if (nanosleep(&tv, &tv))
133         return tv.tv_sec;
134 
135     return 0;
136 }
137 
usleep(useconds_t us)138 int usleep(useconds_t us)
139 {
140     struct timespec tv = {
141         .tv_sec = us / 1000000,
142         .tv_nsec = (us % 1000000) * 1000
143     };
144 
145     return nanosleep(&tv, &tv);
146 }
147