Skip to content

Commit 01dff3a

Browse files
committed
fix(zephyr): Provide a Zephyr naive implementation for os_nanosleep.
1 parent 3b56bf1 commit 01dff3a

File tree

3 files changed

+100
-92
lines changed

3 files changed

+100
-92
lines changed

core/shared/platform/common/posix/posix_sleep.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ os_usleep(uint32 usec)
2121
}
2222

2323
__wasi_errno_t
24-
os_nanosleep(os_timespec *req, os_timespec *rem)
24+
os_nanosleep(const os_timespec *req, os_timespec *rem)
2525
{
2626
int ret;
2727

core/shared/platform/include/platform_api_extension.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1770,7 +1770,7 @@ os_compare_file_handle(os_file_handle handle1, os_file_handle handle2);
17701770
* __WASI_EINVAL The req input is badly formed.
17711771
*/
17721772
__wasi_errno_t
1773-
os_nanosleep(os_timespec *req, os_timespec *rem);
1773+
os_nanosleep(const os_timespec *req, os_timespec *rem);
17741774

17751775

17761776
#ifdef __cplusplus

core/shared/platform/zephyr/zephyr_sleep.c

Lines changed: 98 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2,105 +2,113 @@
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

Comments
 (0)