1 /*
2 * Copyright (c) 2018 Intel Corporation
3 * Copyright (c) 2018 Friedt Professional Engineering Services, Inc
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include "posix_clock.h"
9
10 #include <zephyr/kernel.h>
11 #include <errno.h>
12 #include <zephyr/posix/time.h>
13 #include <zephyr/posix/sys/time.h>
14 #include <zephyr/posix/unistd.h>
15 #include <zephyr/internal/syscall_handler.h>
16 #include <zephyr/spinlock.h>
17
18 /*
19 * `k_uptime_get` returns a timestamp based on an always increasing
20 * value from the system start. To support the `CLOCK_REALTIME`
21 * clock, this `rt_clock_base` records the time that the system was
22 * started. This can either be set via 'clock_settime', or could be
23 * set from a real time clock, if such hardware is present.
24 */
25 static struct timespec rt_clock_base;
26 static struct k_spinlock rt_clock_base_lock;
27
28 /**
29 * @brief Get clock time specified by clock_id.
30 *
31 * See IEEE 1003.1
32 */
z_impl___posix_clock_get_base(clockid_t clock_id,struct timespec * base)33 int z_impl___posix_clock_get_base(clockid_t clock_id, struct timespec *base)
34 {
35 switch (clock_id) {
36 case CLOCK_MONOTONIC:
37 base->tv_sec = 0;
38 base->tv_nsec = 0;
39 break;
40
41 case CLOCK_REALTIME:
42 K_SPINLOCK(&rt_clock_base_lock) {
43 *base = rt_clock_base;
44 }
45 break;
46
47 default:
48 errno = EINVAL;
49 return -1;
50 }
51
52 return 0;
53 }
54
55 #ifdef CONFIG_USERSPACE
z_vrfy___posix_clock_get_base(clockid_t clock_id,struct timespec * ts)56 int z_vrfy___posix_clock_get_base(clockid_t clock_id, struct timespec *ts)
57 {
58 K_OOPS(K_SYSCALL_MEMORY_WRITE(ts, sizeof(*ts)));
59 return z_impl___posix_clock_get_base(clock_id, ts);
60 }
61 #include <zephyr/syscalls/__posix_clock_get_base_mrsh.c>
62 #endif
63
clock_gettime(clockid_t clock_id,struct timespec * ts)64 int clock_gettime(clockid_t clock_id, struct timespec *ts)
65 {
66 struct timespec base;
67
68 switch (clock_id) {
69 case CLOCK_MONOTONIC:
70 base.tv_sec = 0;
71 base.tv_nsec = 0;
72 break;
73
74 case CLOCK_REALTIME:
75 (void)__posix_clock_get_base(clock_id, &base);
76 break;
77
78 default:
79 errno = EINVAL;
80 return -1;
81 }
82
83 uint64_t ticks = k_uptime_ticks();
84 uint64_t elapsed_secs = ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
85 uint64_t nremainder = ticks - elapsed_secs * CONFIG_SYS_CLOCK_TICKS_PER_SEC;
86
87 ts->tv_sec = (time_t) elapsed_secs;
88 /* For ns 32 bit conversion can be used since its smaller than 1sec. */
89 ts->tv_nsec = (int32_t) k_ticks_to_ns_floor32(nremainder);
90
91 ts->tv_sec += base.tv_sec;
92 ts->tv_nsec += base.tv_nsec;
93 if (ts->tv_nsec >= NSEC_PER_SEC) {
94 ts->tv_sec++;
95 ts->tv_nsec -= NSEC_PER_SEC;
96 }
97
98 return 0;
99 }
100
clock_getres(clockid_t clock_id,struct timespec * res)101 int clock_getres(clockid_t clock_id, struct timespec *res)
102 {
103 BUILD_ASSERT(CONFIG_SYS_CLOCK_TICKS_PER_SEC > 0 &&
104 CONFIG_SYS_CLOCK_TICKS_PER_SEC <= NSEC_PER_SEC,
105 "CONFIG_SYS_CLOCK_TICKS_PER_SEC must be > 0 and <= NSEC_PER_SEC");
106
107 if (!(clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_REALTIME ||
108 clock_id == CLOCK_PROCESS_CPUTIME_ID)) {
109 errno = EINVAL;
110 return -1;
111 }
112
113 if (res != NULL) {
114 *res = (struct timespec){
115 .tv_sec = 0,
116 .tv_nsec = NSEC_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC,
117 };
118 }
119
120 return 0;
121 }
122
123 /**
124 * @brief Set the time of the specified clock.
125 *
126 * See IEEE 1003.1.
127 *
128 * Note that only the `CLOCK_REALTIME` clock can be set using this
129 * call.
130 */
clock_settime(clockid_t clock_id,const struct timespec * tp)131 int clock_settime(clockid_t clock_id, const struct timespec *tp)
132 {
133 struct timespec base;
134 k_spinlock_key_t key;
135
136 if (clock_id != CLOCK_REALTIME) {
137 errno = EINVAL;
138 return -1;
139 }
140
141 if (tp->tv_nsec < 0 || tp->tv_nsec >= NSEC_PER_SEC) {
142 errno = EINVAL;
143 return -1;
144 }
145
146 uint64_t elapsed_nsecs = k_ticks_to_ns_floor64(k_uptime_ticks());
147 int64_t delta = (int64_t)NSEC_PER_SEC * tp->tv_sec + tp->tv_nsec
148 - elapsed_nsecs;
149
150 base.tv_sec = delta / NSEC_PER_SEC;
151 base.tv_nsec = delta % NSEC_PER_SEC;
152
153 key = k_spin_lock(&rt_clock_base_lock);
154 rt_clock_base = base;
155 k_spin_unlock(&rt_clock_base_lock, key);
156
157 return 0;
158 }
159
160 /*
161 * Note: usleep() was removed in Issue 7.
162 *
163 * It is kept here for compatibility purposes.
164 *
165 * For more information, please see
166 * https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap01.html
167 * https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap03.html
168 */
usleep(useconds_t useconds)169 int usleep(useconds_t useconds)
170 {
171 int32_t rem;
172
173 if (useconds >= USEC_PER_SEC) {
174 errno = EINVAL;
175 return -1;
176 }
177
178 rem = k_usleep(useconds);
179 __ASSERT_NO_MSG(rem >= 0);
180 if (rem > 0) {
181 /* sleep was interrupted by a call to k_wakeup() */
182 errno = EINTR;
183 return -1;
184 }
185
186 return 0;
187 }
188
189 /**
190 * @brief Suspend execution for a nanosecond interval, or
191 * until some absolute time relative to the specified clock.
192 *
193 * See IEEE 1003.1
194 */
__z_clock_nanosleep(clockid_t clock_id,int flags,const struct timespec * rqtp,struct timespec * rmtp)195 static int __z_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp,
196 struct timespec *rmtp)
197 {
198 uint64_t ns;
199 uint64_t us;
200 uint64_t uptime_ns;
201 k_spinlock_key_t key;
202 const bool update_rmtp = rmtp != NULL;
203
204 if (!((clock_id == CLOCK_REALTIME) || (clock_id == CLOCK_MONOTONIC))) {
205 errno = EINVAL;
206 return -1;
207 }
208
209 if (rqtp == NULL) {
210 errno = EFAULT;
211 return -1;
212 }
213
214 if ((rqtp->tv_sec < 0) || (rqtp->tv_nsec < 0) || (rqtp->tv_nsec >= NSEC_PER_SEC)) {
215 errno = EINVAL;
216 return -1;
217 }
218
219 if ((flags & TIMER_ABSTIME) == 0 && unlikely(rqtp->tv_sec >= ULLONG_MAX / NSEC_PER_SEC)) {
220 ns = rqtp->tv_nsec + NSEC_PER_SEC +
221 (uint64_t)k_sleep(K_SECONDS(rqtp->tv_sec - 1)) * NSEC_PER_MSEC;
222 } else {
223 ns = (uint64_t)rqtp->tv_sec * NSEC_PER_SEC + rqtp->tv_nsec;
224 }
225
226 uptime_ns = k_ticks_to_ns_ceil64(sys_clock_tick_get());
227
228 if (flags & TIMER_ABSTIME && clock_id == CLOCK_REALTIME) {
229 key = k_spin_lock(&rt_clock_base_lock);
230 ns -= rt_clock_base.tv_sec * NSEC_PER_SEC + rt_clock_base.tv_nsec;
231 k_spin_unlock(&rt_clock_base_lock, key);
232 }
233
234 if ((flags & TIMER_ABSTIME) == 0) {
235 ns += uptime_ns;
236 }
237
238 if (ns <= uptime_ns) {
239 goto do_rmtp_update;
240 }
241
242 us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
243 do {
244 us = k_sleep(K_TIMEOUT_ABS_US(us)) * 1000;
245 } while (us != 0);
246
247 do_rmtp_update:
248 if (update_rmtp) {
249 rmtp->tv_sec = 0;
250 rmtp->tv_nsec = 0;
251 }
252
253 return 0;
254 }
255
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)256 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
257 {
258 return __z_clock_nanosleep(CLOCK_MONOTONIC, 0, rqtp, rmtp);
259 }
260
clock_nanosleep(clockid_t clock_id,int flags,const struct timespec * rqtp,struct timespec * rmtp)261 int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp,
262 struct timespec *rmtp)
263 {
264 return __z_clock_nanosleep(clock_id, flags, rqtp, rmtp);
265 }
266
267 /**
268 * @brief Get current real time.
269 *
270 * See IEEE 1003.1
271 */
gettimeofday(struct timeval * tv,void * tz)272 int gettimeofday(struct timeval *tv, void *tz)
273 {
274 struct timespec ts;
275 int res;
276
277 /* As per POSIX, "if tzp is not a null pointer, the behavior
278 * is unspecified." "tzp" is the "tz" parameter above. */
279 ARG_UNUSED(tz);
280
281 res = clock_gettime(CLOCK_REALTIME, &ts);
282 tv->tv_sec = ts.tv_sec;
283 tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
284
285 return res;
286 }
287
clock_getcpuclockid(pid_t pid,clockid_t * clock_id)288 int clock_getcpuclockid(pid_t pid, clockid_t *clock_id)
289 {
290 /* We don't allow any process ID but our own. */
291 if (pid != 0 && pid != getpid()) {
292 return EPERM;
293 }
294
295 *clock_id = CLOCK_PROCESS_CPUTIME_ID;
296
297 return 0;
298 }
299
300 #ifdef CONFIG_ZTEST
301 #include <zephyr/ztest.h>
reset_clock_base(void)302 static void reset_clock_base(void)
303 {
304 K_SPINLOCK(&rt_clock_base_lock) {
305 rt_clock_base = (struct timespec){0};
306 }
307 }
308
clock_base_reset_rule_after(const struct ztest_unit_test * test,void * data)309 static void clock_base_reset_rule_after(const struct ztest_unit_test *test, void *data)
310 {
311 ARG_UNUSED(test);
312 ARG_UNUSED(data);
313
314 reset_clock_base();
315 }
316
317 ZTEST_RULE(clock_base_reset_rule, NULL, clock_base_reset_rule_after);
318 #endif /* CONFIG_ZTEST */
319