diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 0f5888b0f51a..7a5bd4dec5a7 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -332,7 +332,7 @@ POSIX_TIMERS :header: API, Supported :widths: 50,10 - clock_getres(), + clock_getres(),yes clock_gettime(),yes clock_settime(),yes nanosleep(),yes diff --git a/include/zephyr/posix/time.h b/include/zephyr/posix/time.h index 417923c4377b..8038e783030f 100644 --- a/include/zephyr/posix/time.h +++ b/include/zephyr/posix/time.h @@ -87,6 +87,7 @@ static inline int32_t _ts_to_ms(const struct timespec *to) } int clock_gettime(clockid_t clock_id, struct timespec *ts); +int clock_getres(clockid_t clock_id, struct timespec *ts); int clock_settime(clockid_t clock_id, const struct timespec *ts); int clock_getcpuclockid(pid_t pid, clockid_t *clock_id); /* Timer APIs */ diff --git a/lib/posix/options/clock.c b/lib/posix/options/clock.c index a8835a442484..48789ae49c25 100644 --- a/lib/posix/options/clock.c +++ b/lib/posix/options/clock.c @@ -97,6 +97,28 @@ int clock_gettime(clockid_t clock_id, struct timespec *ts) return 0; } +int clock_getres(clockid_t clock_id, struct timespec *res) +{ + BUILD_ASSERT(CONFIG_SYS_CLOCK_TICKS_PER_SEC > 0 && + CONFIG_SYS_CLOCK_TICKS_PER_SEC <= NSEC_PER_SEC, + "CONFIG_SYS_CLOCK_TICKS_PER_SEC must be > 0 and <= NSEC_PER_SEC"); + + if (!(clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_REALTIME || + clock_id == CLOCK_PROCESS_CPUTIME_ID)) { + errno = EINVAL; + return -1; + } + + if (res != NULL) { + *res = (struct timespec){ + .tv_sec = 0, + .tv_nsec = NSEC_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC, + }; + } + + return 0; +} + /** * @brief Set the time of the specified clock. * diff --git a/tests/posix/common/src/clock.c b/tests/posix/common/src/clock.c index 07a825434c5e..bb7a6729b5ab 100644 --- a/tests/posix/common/src/clock.c +++ b/tests/posix/common/src/clock.c @@ -227,4 +227,48 @@ ZTEST(clock, test_clock_getcpuclockid) zassert_equal(ret, EPERM, "POSIX clock_getcpuclock id failed"); } +ZTEST(clock, test_clock_getres) +{ + int ret; + struct timespec res; + const struct timespec one_ns = { + .tv_sec = 0, + .tv_nsec = 1, + }; + + struct arg { + clockid_t clock_id; + struct timespec *res; + int expect; + }; + + const struct arg args[] = { + /* permuting over "invalid" inputs */ + {CLOCK_INVALID, NULL, -1}, + {CLOCK_INVALID, &res, -1}, + {CLOCK_REALTIME, NULL, 0}, + {CLOCK_MONOTONIC, NULL, 0}, + {CLOCK_PROCESS_CPUTIME_ID, NULL, 0}, + + /* all valid inputs */ + {CLOCK_REALTIME, &res, 0}, + {CLOCK_MONOTONIC, &res, 0}, + {CLOCK_PROCESS_CPUTIME_ID, &res, 0}, + }; + + ARRAY_FOR_EACH_PTR(args, arg) { + errno = 0; + res = (struct timespec){0}; + ret = clock_getres(arg->clock_id, arg->res); + zassert_equal(ret, arg->expect); + if (ret != 0) { + zassert_equal(errno, EINVAL); + continue; + } + if (arg->res != NULL) { + zassert_true(tp_ge(arg->res, &one_ns)); + } + } +} + ZTEST_SUITE(clock, NULL, NULL, NULL, NULL, NULL);