kern/59127: clock_getres(2) returns EINVAL for CLOCK_{PROCESS,THREAD}_CPUTIME_ID

PHO <[email protected]>
Newsgroups gmane.os.netbsd.devel.kernel
Message-ID <[email protected]>
Hi,


I just filed a PR with the attached patch to make clock_getres(2) 
support these two clocks. I will commit the patch in a week or two if no 
one objects:
https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=59127

The reason why this matters to me is that lang/ghc910 has been silently 
broken. Its function System.CPUTime.cpuTimePrecision tries to call 
clock_getres(CLOCK_PROCESS_CPUTIME_ID) if:

   #elif _POSIX_TIMERS > 0 && defined(_POSIX_CPUTIME) && _POSIX_CPUTIME >= 0

which holds true on NetBSD, but then the syscall returns EINVAL:

   % ghci
   GHCi, version 9.10.1: https://www.haskell.org/ghc/  :? for help
   Loaded GHCi configuration from /home/pho/.ghci
   ghci> :m System.CPUTime
   ghci> cpuTimePrecision
   *** Exception: clock_getres: invalid argument (Invalid argument)

GHC still needs to be patched in the meantime but I believe the kernel 
should support this.
clock_getres.patch (text/x-patch, 2.6 KB)
From ebf335048a3a4684b05c4efd07acaeae2b8c0cf0 Mon Sep 17 00:00:00 2001
From: PHO <[email protected]>
Date: Tue, 4 Mar 2025 21:28:46 +0900
Subject: [PATCH] clock_getres(2): Support CLOCK_{PROCESS,THREAD}_CPUTIME_ID

The syscall previously returned EINVAL for these two clocks. It still has
no support for CLOCK_VIRTUAL and CLOCK_PROF but clock_gettime(2) doesn't
either.
---
 sys/kern/kern_time.c                 |  2 ++
 tests/lib/libc/sys/t_clock_gettime.c | 34 ++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index 91d259d810ac5..213a151b6b506 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -339,6 +339,8 @@ clock_getres1(clockid_t clock_id, struct timespec *ts)
 	switch (clock_id) {
 	case CLOCK_REALTIME:
 	case CLOCK_MONOTONIC:
+	case CLOCK_PROCESS_CPUTIME_ID:
+	case CLOCK_THREAD_CPUTIME_ID:
 		ts->tv_sec = 0;
 		if (tc_getfrequency() > 1000000000)
 			ts->tv_nsec = 1;
diff --git a/tests/lib/libc/sys/t_clock_gettime.c b/tests/lib/libc/sys/t_clock_gettime.c
index 6421b1ab0cb8c..7e0954c1244aa 100644
--- a/tests/lib/libc/sys/t_clock_gettime.c
+++ b/tests/lib/libc/sys/t_clock_gettime.c
@@ -285,12 +285,46 @@ ATF_TC_BODY(clock_gettime_thread_cputime_is_monotonic, tc)
 	    CLOCK_THREAD_CPUTIME_ID, &waste_user_time);
 }
 
+static void
+check_resolution(const char *clockname, clockid_t clockid)
+{
+	struct timespec ts;
+	int rv;
+
+	RLF(rv = clock_getres(clockid, &ts), "%s", clockname);
+	if (rv != -1) {
+		ATF_CHECK_MSG(ts.tv_sec == 0,
+		    "The resolution of the clock %s is reported as %jd.%09jd which is"
+		    " lower than a second; most likely an wrong value",
+		    clockname, ts.tv_sec, ts.tv_nsec);
+	}
+}
+
+ATF_TC(clock_getres);
+ATF_TC_HEAD(clock_getres, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Checks that clock_getres(2) returns some reasonable resolution for all supported clocks");
+}
+ATF_TC_BODY(clock_getres, tc)
+{
+	check_resolution("CLOCK_REALTIME", CLOCK_REALTIME);
+	check_resolution("CLOCK_MONOTONIC", CLOCK_MONOTONIC);
+	atf_tc_expect_fail("These clocks aren't supported but are documented in clock_gettime(2) for some reason");
+	check_resolution("CLOCK_VIRTUAL", CLOCK_VIRTUAL);
+	check_resolution("CLOCK_PROF", CLOCK_PROF);
+	atf_tc_expect_pass();
+	check_resolution("CLOCK_PROCESS_CPUTIME_ID", CLOCK_PROCESS_CPUTIME_ID);
+	check_resolution("CLOCK_THREAD_CPUTIME_ID", CLOCK_THREAD_CPUTIME_ID);
+}
+
 ATF_TP_ADD_TCS(tp)
 {
 
 	ATF_TP_ADD_TC(tp, clock_gettime_real);
 	ATF_TP_ADD_TC(tp, clock_gettime_process_cputime_is_monotonic);
 	ATF_TP_ADD_TC(tp, clock_gettime_thread_cputime_is_monotonic);
+	ATF_TP_ADD_TC(tp, clock_getres);
 
 	return atf_no_error();
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.