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