22 * Copyright (C) 2024 Grenoble INP - ESISAR. All rights reserved.
33 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
44 */
5-
65#include "platform_api_extension.h"
76
8- // #include <zephyr/kernel.h>
9-
107/*
11- * Assuming CONFIG_POSIX_API=n
12- * Inspired zephyr/lib/posix/options/clock.c
8+ * In Zephyr v3.7, there is no simple way to get a `nanosleep` implementation.
9+ * But in the later version the Zephyr community introduced some clock APIs
10+ * and their POSIX compatibility layer.
11+ *
12+ * Relevant Zephyr sources:
13+ * - zephyr/include/zephyr/sys/clock.h
14+ * - Zephyr/lib/os/clock.c
15+ * POSIX layer:
16+ * - zephyr/lib/posix/options/clock.c
17+ *
18+ * Instead of re-implementing the full Clock APIs, this file provides a naive
19+ * `nanosleep` implementation based on the Zephyr thread API (`k_sleep`).
20+ *
21+ * Limitations:
22+ * Maximum sleep duration is limited by UINT32_MAX or UINT64_MAX ticks
23+ * (≈ 4,294,967,295 and 18,446,744,073,709,551,615 respectively).
24+ *
25+ * Example at a "slow" clock rate of 50 kHz:
26+ * - UINT32_MAX: ~85 899s (~23 hours)
27+ * - UINT64_MAX: ~368 934 881 474 191s (~11.7 millions years)
28+ * Clearly, `nanosleep` should not be used for such long durations.
29+ *
30+ * Note: this assumes `CONFIG_POSIX_API=n` in the Zephyr application.
1331 */
1432
33+ #ifdef CONFIG_TIMEOUT_64BIT
34+ static int64_t timespec_to_ticks (const os_timespec * ts );
35+ #else
36+ static uint32_t timespec_to_ticks (const os_timespec * ts );
37+ #endif
38+
1539__wasi_errno_t
16- os_nanosleep (os_timespec * req , os_timespec * rem )
40+ os_nanosleep (const os_timespec * req , os_timespec * rem )
1741{
18- // __wasi_errno_t ret;
19-
20- // if (req == NULL){
21- // return __WASI_EINVAL;
22- // }
23-
24- // /*
25- // * os_timespec is typedef'ed to struct timespec so it's one to one.
26- // * Also sys_clock_nanosleep return either:
27- // * * 0 on sucess
28- // * * -EINVAL on failure
29- // */
30- // int rc = sys_clock_nanosleep(SYS_CLOCK_REALTIME, 0, req, rem);
31- // if (0 > rc){
32- // return __WASI_EINVAL;
33- // }
42+ k_timeout_t timeout ;
43+
44+ if (req == NULL ){
45+ return __WASI_EINVAL ;
46+ }
47+
48+ timeout .ticks = (k_ticks_t ) timespec_to_ticks (req );
49+
50+ /*
51+ * The function `int32_t k_sleep(k_timeout_t timeout)` return either:
52+ * * 0 requested time elaspsed.
53+ * * >0 remaining time in ms (due to k_wakeup).
54+ */
55+ int32_t rc = k_sleep (timeout );
56+ if (rem != NULL && 0 < rc ){
57+ rem -> tv_sec = rc / 1000 ;
58+ rem -> tv_nsec = ( rc % 1000 ) * 1000000 ;
59+ }
3460
3561 return __WASI_ESUCCESS ;
3662}
3763
38- /*
39- * Don't exist in v3.7
40- *
41- * Inspired zephyr/lib/posix/options/clock.c on main
42- */
4364
44- // int sys_clock_nanosleep(int clock_id, int flags, const struct timespec *rqtp,
45- // struct timespec *rmtp)
46- // {
47- // k_timepoint_t end;
48- // k_timeout_t timeout;
49- // struct timespec duration;
50- // const bool update_rmtp = rmtp != NULL;
51- // const bool abstime = (flags & SYS_TIMER_ABSTIME) != 0;
52-
53-
54- // /*
55- // * Arguments checks
56- // */
57- // if((clock_id != SYS_CLOCK_MONOTONIC) &&
58- // (clock_id != SYS_CLOCK_REALTIME)){
59- // return __WASI_EINVAL;
60- // }
61-
62- // if((rqtp->tv_sec < 0) ||
63- // (rqtp->tv_nsec < 0) ||
64- // (rqtp->tv_nsec >= (long)NSEC_PER_SEC)){
65- // return __WASI_EINVAL;
66- // }
67-
68-
69- // if (abstime) {
70- // /* convert absolute time to relative time duration */
71- // (void)sys_clock_gettime(clock_id, &duration);
72- // (void)timespec_negate(&duration);
73- // (void)timespec_add(&duration, rqtp);
74- // } else {
75- // duration = *rqtp;
76- // }
77-
78- // /* sleep for relative time duration */
79- // if ((sizeof(rqtp->tv_sec) == sizeof(int64_t)) &&
80- // unlikely(rqtp->tv_sec >= (time_t)(UINT64_MAX / NSEC_PER_SEC))) {
81- // uint64_t ns = (uint64_t)k_sleep(K_SECONDS(duration.tv_sec - 1)) * NSEC_PER_MSEC;
82- // struct timespec rem = {
83- // .tv_sec = (time_t)(ns / NSEC_PER_SEC),
84- // .tv_nsec = ns % NSEC_PER_MSEC,
85- // };
86-
87- // duration.tv_sec = 1;
88- // (void)timespec_add(&duration, &rem);
89- // }
90-
91- // timeout = timespec_to_timeout(&duration, NULL);
92- // end = sys_timepoint_calc(timeout);
93- // do {
94- // (void)k_sleep(timeout);
95- // timeout = sys_timepoint_timeout(end);
96- // } while (!K_TIMEOUT_EQ(timeout, K_NO_WAIT));
97-
98- // if (update_rmtp) {
99- // *rmtp = (struct timespec){
100- // .tv_sec = 0,
101- // .tv_nsec = 0,
102- // };
103- // }
104-
105- // return 0;
106- // }
65+ #ifdef CONFIG_TIMEOUT_64BIT
66+
67+ static int64_t timespec_to_ticks (const os_timespec * ts )
68+ {
69+ const uint64_t ticks_per_sec = CONFIG_SYS_CLOCK_TICKS_PER_SEC ;
70+ uint64_t ticks = 0 ;
71+
72+ if (ts -> tv_sec > UINT64_MAX / ticks_per_sec ) {
73+ return UINT64_MAX ;
74+ }
75+
76+ ticks = (uint64_t )ts -> tv_sec * ticks_per_sec ;
77+
78+ if (ts -> tv_nsec > 0 ) {
79+ uint64_t add = (uint64_t )ts -> tv_nsec * ticks_per_sec / 1000000000ULL ;
80+ if (ticks > UINT64_MAX - add ) {
81+ return UINT64_MAX ;
82+ }
83+ ticks += add ;
84+ }
85+
86+ return ticks ;
87+ }
88+
89+ #else /* CONFIG_TIMEOUT_32BIT */
90+
91+ static uint32_t timespec_to_ticks (const os_timespec * ts )
92+ {
93+ const uint32_t ticks_per_sec = CONFIG_SYS_CLOCK_TICKS_PER_SEC ;
94+ uint32_t ticks = 0 ;
95+
96+ if (ts -> tv_sec > UINT32_MAX / ticks_per_sec ) {
97+ return UINT32_MAX ;
98+ }
99+
100+ ticks = (uint32_t )ts -> tv_sec * ticks_per_sec ;
101+
102+ if (ts -> tv_nsec > 0 ) {
103+ uint64_t add64 = (uint64_t )ts -> tv_nsec * ticks_per_sec ;
104+ uint32_t add = (uint32_t )(add64 / 1000000000ULL );
105+ if (ticks > UINT32_MAX - add ) {
106+ return UINT32_MAX ;
107+ }
108+ ticks += add ;
109+ }
110+
111+ return ticks ;
112+ }
113+
114+ #endif /* CONFIG_TIMEOUT_64BIT */
0 commit comments