[PATCH v3 3/3] system_data_types.7: note struct timespec::tv_nsec type for x32 and portability

Alejandro Colomar (man-pages) alx.manpages@gmail.com
Tue Dec 7 00:52:52 GMT 2021


Hi, Zack!

On 12/7/21 01:18, Zack Weinberg wrote:
> Depending on the kernel, the architecture, the ABI, and the state of _TIME_BITS, the format of `struct timespec` as expected by system calls may be any of
> 
> struct timespec { int32_t tv_sec; int32_t tv_nsec; };
> struct timespec { int64_t tv_sec; int64_t tv_nsec; };
> struct timespec { int64_t tv_sec; int32_t __padding; int32_t tv_nsec; }
> struct timespec { int64_t tv_sec; int32_t tv_nsec; int32_t __padding; }
> 
> These may be incompatible with using bare `long` for tv_nsec in the user space headers.  The problem cases are when the kernel expects option 2 but user space's `long` is only 32 bits wide, or if the kernel expects option 3 or 4 when `long` is 64 bits wide and the endianness of `long` doesn't agree with the position of the padding.  I don't remember which ABIs actually manifest an incompatibility, but I remember this being discussed repeatedly during the project to make 64-bit time_t available to ILP32 ABIs.
> 
> The C library CANNOT paper over the incompatibility by converting formats in the syscall wrappers, because `struct timespec` objects get embedded in an unbounded set of `ioctl` parameter blocks, `sendmsg` ancillary data structures, etc. etc. etc.  We can't even make a list.
> 
> Personally I consider the situation a defect in POSIX and C11; the definition of `struct timespec` should always have been
> 
> struct timespec { time_t tv_sec; nsec_t tv_nsec; };

I can agree with that.

> 
> where nsec_t is an integer type that can represent the range [0, 10**9).  Last time this came up, Joseph didn't think there was any chance of persuading either the Austin Group or WG14 to make this change, unfortunately.

Okay, I can understand that.

How about defining ns[ec[onds]]_t (and possibly ms[ec[onds]]_t) in 
glibc, and using them wherever ms or ns are used, such as in this case, 
instead of a random type?

I think since glibc already ignores POSIX, it could go a bit further and 
use an interface that is consistent (use nseconds_t always instead of 
sometimes long sometimes long long), more readable than POSIX (a 
variable of type nseconds_t already tells you a lot about it), and again 
consistent (since we already have useconds_t, using nseconds_t would add 
consistency to the types used in <time.h>.

Also, that would make clear that you should cast it to long to print it 
(and using pointers would already make sure that you have the correct 
pointer using a nseconds_t one).  And of course, if a program wants to 
be portable, it can just typedef it to long when using other libcs not 
using nseconds_t.

Thanks,
Alex


-- 
Alejandro Colomar
Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/
http://www.alejandro-colomar.es/


More information about the Libc-alpha mailing list