There are three files that govern userspace struct timespec on glibc: 1. bits/wordsize.h, defining: (a) __WORDSIZE to 32 on ILP32 and 64 on LP64 (b) on x32: __SYSCALL_WORDSIZE to 64 2. bits/timesize.h, defining (a) __TIMESIZE to __WORDSIZE, except on x32 where it's 64 3. bits/types/struct_timespec.h, declaring struct timespec as: struct timespec { __time_t tv_sec; /* Seconds. */ #if __WORDSIZE == 64 \ || (defined __SYSCALL_WORDSIZE && __SYSCALL_WORDSIZE == 64) \ || __TIMESIZE == 32 __syscall_slong_t tv_nsec; /* Nanoseconds. */ #else # if __BYTE_ORDER == __BIG_ENDIAN int: 32; /* Padding. */ long int tv_nsec; /* Nanoseconds. */ # else long int tv_nsec; /* Nanoseconds. */ int: 32; /* Padding. */ # endif #endif }; this has two side-effects: struct timespec (a) is always sizeof==time_t+8, and (b) has tv_nsec as __syscall_slong_t *and* !is_same<__syscall_slong_t, long> if using LP64 syscalls on an ILP32 system, i.e. on x32. This means, that the simplified struct timespec { time_t tv_sec; /* Seconds */ long tv_nsec; /* Nanoseconds [0 .. 999999999] */ }; declaration is *invalid* for x32, where struct timespec::tv_nsec is an int64_t (long long). Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@xxxxxxxxxxxxxxxxxx> --- The reasoning is explained in the commit message, but I elucidated it in a more approachable way in the Notes, which also include the link from Jakub Wilk upthread. Nevertheless, log2(10^(3*3) - 1) <= 31 is a good point! I also added this as a slight portability guide toward the end. This replaces 3/4 and 4/4. man7/system_data_types.7 | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/man7/system_data_types.7 b/man7/system_data_types.7 index 1e6a3f74c..cce17fc3e 100644 --- a/man7/system_data_types.7 +++ b/man7/system_data_types.7 @@ -1553,6 +1553,36 @@ Describes times in seconds and nanoseconds. .IR "Conforming to" : C11 and later; POSIX.1-2001 and later. .PP +.IR Notes : +.I tv_nsec +is the +.I syscall +long, though this affects only fringe architectures like X32, +which is ILP32, but uses the LP64 AMD64 syscall ABI. +.br +In reality, the field ends up being defined as: +.EX +.in +4 +#if !(__x86_64__ && __ILP32__ /* == x32 */) + long tv_nsec; +#else + long long tv_nsec; +#endif +.in +.EE +.PP +This is a long-standing and long-enshrined +.UR https://sourceware.org/bugzilla/show_bug.cgi?id=16437 +glibc bug +.I #16437 +.UE , +an incompatible extension to the standards; +however, as even a 32-bit +.I long +can hold the entire +.I tv_nsec +range, it's safe to forcibly down-cast it to the standard type. +.PP .IR "See also" : .BR clock_gettime (2), .BR clock_nanosleep (2), -- 2.30.2
Attachment:
signature.asc
Description: PGP signature