Re: [PATCH] timespec_get.3: new page (timespec_get(), timespec_getres())
From: наб <hidden>
Date: 2024-09-06 14:01:06
Subsystem:
the rest · Maintainer:
Linus Torvalds
On Fri, Sep 06, 2024 at 02:16:40AM +0200, Alejandro Colomar wrote:
Hi Ahelenia, On Thu, Sep 05, 2024 at 01:41:58PM GMT, Ahelenia Ziemiańska wrote:quoted
If you're wondering how errno is affected, so am I; no-one really says; quoth POSIX: If base is TIME_UTC, the members of ts shall be set to the same values as would be set by a call to clock_gettime(CLOCK_REALTIME, ts). RETURN VALUE If the timespec_get( ) function is successful it shall return the non-zero value base; otherwise, it shall return zero. ERRORS See DESCRIPTION. But this is a moot point since clock_gettime() can't fail anyway (glibc doesn't even check the error).I see at least the following errors in clock_gettime(2): EFAULT tp points outside the accessible address space.
This one would be real..but clock_gettime() is widely implemented as a vDSO routine so it's a segfault on those architectures. (And for this reason POSIX never outlines EFAULT by name.) Thus, I'd call this just UB, not an EFAULT-style "error". glibc doesn't check for errors, musl will return 0 here tho.
EINVAL The clockid specified is invalid for one of two reasons.
EINVAL The clockid specified in a call to clock_settime() is not a
settable clock.
ENODEV The hot‐pluggable device (like USB for example) represented
ENOTSUPThe operation is not supported by the dynamic POSIX clockNot possible, since CLOCK_REALTIME is always valid.
EOVERFLOW The timestamp would not fit in time_t range.
I'm choosing to not see it, especially in in a.d. 2024 for a novel API. But, again, glibc doesn't check for errors, musl will return 0 tho. POSIX says
If the number of seconds will not fit in an object of type time_t, the function shall return zero.
But it defines t_g(T_U) as "the members of ts shall be set to the
same values as would be set by a call to clock_gettime(CLOCK_REALTIME, ts)."
and then adds that overflow sentence. Which doesn't indicate an
errno-setting condition to me? It's not defined as /literally/ calling
clock_gettime(), and the overflow sentence protects from the only error
condition in clock_gettime(). So this implies to me that errno isn't set?
To test this, I built a test program on buster/i386, then ran it on a
system with time set to 2^31 and 2^32.
I can't really trigger clock_gettime()'s EOVERFLOW... anyway, ever?
Now, musl ships compat/time32/timespec_get_time32.c, which does this:
int __timespec_get_time32(struct timespec32 *ts32, int base)
{
struct timespec ts;
int r = timespec_get(&ts, base);
if (!r) return r;
if (ts.tv_sec < INT32_MIN || ts.tv_sec > INT32_MAX) {
errno = EOVERFLOW;
it's unclear to me when this wrapper is used, however.
And I'd say it's... wrong per POSIX? Actually? A little bit?
Bypassing the vDSO so timespec_get() actually runs a syscall,
and giving it an invalid pointer (strace says EFAULT!),
got me 0/errno=0.
Which I'd say is correct per POSIX?
C says
Returns
If th etimespec_get function is successful it returns the nonzero
value base; otherwise, it returnszero.
and doesn't mention errno at all. So from this I'm going to opine that
(a) glibc is right to not set errno on -EFAULT,
(b) musl is wrong to set errno when it detects EOVERFLOW,
but also it doesn't matter.
All BSD implementations I looked through are
if(clock_gettime() == -1) return 0; return base;
and I don't think they have errno filtering that harsh.
So idk. I think it's fine
Scissor-patch below.
Best,
-- >8 --
Subject: [PATCH] timespec_get.3: new page (timespec_get(), timespec_getres())
Signed-off-by: Ahelenia Ziemiańska <redacted>
---
man/man3/timespec_get.3 | 95 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
create mode 100644 man/man3/timespec_get.3
diff --git a/man/man3/timespec_get.3 b/man/man3/timespec_get.3
new file mode 100644
index 000000000..bd32a600c
--- /dev/null
+++ b/man/man3/timespec_get.3@@ -0,0 +1,95 @@ +'\" t +.\" SPDX-License-Identifier: 0BSD +.\" +.TH timespec_get 3 (date) "Linux man-pages (unreleased)" +.SH NAME +timespec_get, timespec_getres \- standard C clock and time functions +.SH LIBRARY +Standard C library +.RI ( libc ,\~ \-lc ), +.SH SYNOPSIS +.nf +.B #include <time.h> +.P +.BI "int timespec_get(struct timespec *" res ", int " base ); +.BI "int timespec_getres(struct timespec *" tp ", int " base ); +.fi +.P +.RS -4 +Feature Test Macro Requirements for glibc (see +.BR feature_test_macros (7)): +.RE +.P +.BR timespec_get (): +.nf + _ISOC11_SOURCE || _ISOC2X_SOURCE + || __STDC_VERSION__ >= 201112L + || /* glibc <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE +.P +.BR timespec_getres (): +.nf + _ISOC2X_SOURCE || __STDC_VERSION__ > 201710L +.fi +.SH DESCRIPTION +.BI timespec_get\fR(\fP tp ", TIME_UTC)" +is defined as +.IR "clock_gettime(CLOCK_REALTIME, tp)" . +.P +.BI timespec_getres\fR(\fP res ", TIME_UTC)" +is equivalent to +.IR "timespec_getres(CLOCK_REALTIME, res)" . +.P +.BR TIME_UTC +is universally guaranteed to be a valid +.IR base , +and is the only one supported under Linux. +.SH RETURN VALUE +.B 0 +if base is unsupported or the call failed, otherwise +.IR base . +.SH ERRORS +Some C libraries +.I may +set +.I errno +to the same value as would be set by +.BR clock_gettime (2)/ clock_getres (2). +Neither C nor POSIX specify this, but they don't really indicate this shouldn't happen, either. +Don't rely on this. +.SH ATTRIBUTES +For an explanation of the terms used in this section, see +.BR attributes (7). +.TS +allbox; +lbx lb lb +l l l. +Interface Attribute Value +T{ +.na +.nh +.BR timespec_get (), +.BR timespec_getres () +T} Thread safety MT-Safe +.TE +.SH STANDARDS +.TP +.BR timespec_get () +.TQ +.B TIME_UTC +C23 (though note that C doesn't specify the time epoch), +POSIX.1-2024. +.TP +.BR timespec_getres () +C23. +.SH HISTORY +.TP +.BR timespec_get () +.TQ +.B TIME_UTC +C11, POSIX.1-2024, glibc 2.16, musl 1.1.10. +.TP +.BR timespec_getres () +C23, glibc 2.34. +.SH SEE ALSO +.BR clock_gettime (2), +.BR clock_getres (2)
--
2.39.2
Attachments
- signature.asc [application/pgp-signature] 833 bytes