mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
libc: Export timespec_getres(3) and add tests
timespec_getres() has been declared in <time.h> and built into libc,
but never listed in a symbol map. It is therefore local to libc.so,
and dynamically linked callers fail to link.
Reviewed by: ziaee, fuz, des
Approved by: fuz (mentor)
Fixes: 9b5d724cad ("libc: Add timespec_getres(3) as per C23.")
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D60799
This commit is contained in:
4 files changed
+132
-2
No files matched your search
@@ -483,6 +483,7 @@ FBSD_1.9 {
|
||||
posix_spawnattr_getprocdescp_np;
|
||||
posix_spawnattr_setexecfd_np;
|
||||
posix_spawnattr_setprocdescp_np;
|
||||
timespec_getres;
|
||||
uexterr_set;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.\"
|
||||
.\" SPDX-License-Identifier: BSD-2-Clause
|
||||
.\"
|
||||
.Dd May 14, 2026
|
||||
.Dd October 20, 2026
|
||||
.Dt TIMESPEC_GETRES 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -43,7 +43,11 @@ function conforms to
|
||||
.St -isoC-2023 .
|
||||
.Sh HISTORY
|
||||
This interface first appeared in
|
||||
.Fx 14 .
|
||||
.Fx 14.0 ,
|
||||
but it was not exported from the shared C library until
|
||||
.Fx 14.6
|
||||
and
|
||||
.Fx 15.2 .
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
|
||||
@@ -42,6 +42,7 @@ ATF_TESTS_C+= scandir_blocks_test
|
||||
.endif
|
||||
ATF_TESTS_C+= sig2str_test
|
||||
ATF_TESTS_C+= sigsetops_test
|
||||
ATF_TESTS_C+= timespec_getres_test
|
||||
ATF_TESTS_C+= wordexp_test
|
||||
|
||||
# TODO: t_closefrom, t_fmtcheck, t_randomid,
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Faraz Vahedi <kfv@FreeBSD.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tests for timespec_getres() as per ISO/IEC 9899:2024 §7.29.2.7.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
|
||||
static const struct {
|
||||
int base;
|
||||
clockid_t clock;
|
||||
} bases[] = {
|
||||
{ TIME_UTC, CLOCK_REALTIME },
|
||||
{ TIME_MONOTONIC, CLOCK_MONOTONIC },
|
||||
};
|
||||
|
||||
static const int bad_bases[] = {
|
||||
INT_MIN, -1, 0, INT_MAX,
|
||||
};
|
||||
|
||||
static void
|
||||
check_res(const struct timespec *ts)
|
||||
{
|
||||
ATF_CHECK(ts->tv_sec >= 0);
|
||||
ATF_CHECK(ts->tv_nsec >= 0 && ts->tv_nsec < 1000000000);
|
||||
ATF_CHECK(ts->tv_sec != 0 || ts->tv_nsec != 0);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(timespec_getres_supported);
|
||||
ATF_TC_BODY(timespec_getres_supported, tc)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
for (size_t i = 0; i < nitems(bases); i++) {
|
||||
ATF_CHECK_EQ(timespec_getres(&ts, bases[i].base),
|
||||
bases[i].base);
|
||||
check_res(&ts);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(timespec_getres_clock);
|
||||
ATF_TC_BODY(timespec_getres_clock, tc)
|
||||
{
|
||||
struct timespec ts, cts;
|
||||
|
||||
for (size_t i = 0; i < nitems(bases); i++) {
|
||||
ATF_REQUIRE_EQ(timespec_getres(&ts, bases[i].base),
|
||||
bases[i].base);
|
||||
ATF_REQUIRE_EQ(clock_getres(bases[i].clock, &cts), 0);
|
||||
ATF_CHECK_EQ(ts.tv_sec, cts.tv_sec);
|
||||
ATF_CHECK_EQ(ts.tv_nsec, cts.tv_nsec);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(timespec_getres_null);
|
||||
ATF_TC_BODY(timespec_getres_null, tc)
|
||||
{
|
||||
for (size_t i = 0; i < nitems(bases); i++)
|
||||
ATF_CHECK_EQ(timespec_getres(NULL, bases[i].base),
|
||||
bases[i].base);
|
||||
for (size_t i = 0; i < nitems(bad_bases); i++)
|
||||
ATF_CHECK_EQ(timespec_getres(NULL, bad_bases[i]), 0);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(timespec_getres_unsupported);
|
||||
ATF_TC_BODY(timespec_getres_unsupported, tc)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
for (size_t i = 0; i < nitems(bad_bases); i++) {
|
||||
ts.tv_sec = -1;
|
||||
ts.tv_nsec = -1;
|
||||
ATF_CHECK_EQ(timespec_getres(&ts, bad_bases[i]), 0);
|
||||
ATF_CHECK_EQ(ts.tv_sec, -1);
|
||||
ATF_CHECK_EQ(ts.tv_nsec, -1);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(timespec_getres_timespec_get);
|
||||
ATF_TC_BODY(timespec_getres_timespec_get, tc)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
for (int base = -1; base <= TIME_MONOTONIC + 8; base++)
|
||||
ATF_CHECK_EQ_MSG(timespec_getres(&ts, base) != 0,
|
||||
timespec_get(&ts, base) != 0, "base %d", base);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(timespec_getres_stable);
|
||||
ATF_TC_BODY(timespec_getres_stable, tc)
|
||||
{
|
||||
struct timespec first, ts;
|
||||
|
||||
for (size_t i = 0; i < nitems(bases); i++) {
|
||||
ATF_REQUIRE_EQ(timespec_getres(&first, bases[i].base),
|
||||
bases[i].base);
|
||||
for (int n = 0; n < 100; n++) {
|
||||
ATF_REQUIRE_EQ(timespec_getres(&ts, bases[i].base),
|
||||
bases[i].base);
|
||||
ATF_CHECK_EQ(ts.tv_sec, first.tv_sec);
|
||||
ATF_CHECK_EQ(ts.tv_nsec, first.tv_nsec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
ATF_TP_ADD_TC(tp, timespec_getres_supported);
|
||||
ATF_TP_ADD_TC(tp, timespec_getres_clock);
|
||||
ATF_TP_ADD_TC(tp, timespec_getres_null);
|
||||
ATF_TP_ADD_TC(tp, timespec_getres_unsupported);
|
||||
ATF_TP_ADD_TC(tp, timespec_getres_timespec_get);
|
||||
ATF_TP_ADD_TC(tp, timespec_getres_stable);
|
||||
|
||||
return (atf_no_error());
|
||||
}
|
||||
Reference in new issue
Block a user