[PATCH v2 09/13] tools/nolibc: always use 64-bit time types

Thomas Weißschuh posted 13 patches 1 week, 2 days ago
[PATCH v2 09/13] tools/nolibc: always use 64-bit time types
Posted by Thomas Weißschuh 1 week, 2 days ago
32-bit time types will stop working in 2038.

Switch to 64-bit time types everywhere.

Suggested-by: Arnd Bergmann <arnd@arndb.de>
Link: https://lore.kernel.org/lkml/cec27d94-c99d-4c57-9a12-275ea663dda8@app.fastmail.com/
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
 tools/include/nolibc/std.h   | 2 +-
 tools/include/nolibc/types.h | 9 +++++----
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/tools/include/nolibc/std.h b/tools/include/nolibc/std.h
index 392f4dd94158..b9a116123902 100644
--- a/tools/include/nolibc/std.h
+++ b/tools/include/nolibc/std.h
@@ -29,6 +29,6 @@ typedef unsigned long       nlink_t;
 typedef  int64_t              off_t;
 typedef   signed long     blksize_t;
 typedef   signed long      blkcnt_t;
-typedef __kernel_time_t      time_t;
+typedef __kernel_time64_t    time_t;
 
 #endif /* _NOLIBC_STD_H */
diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h
index 5d180ffabcb6..8f3cb18df7f1 100644
--- a/tools/include/nolibc/types.h
+++ b/tools/include/nolibc/types.h
@@ -17,14 +17,15 @@
 #include <linux/wait.h>
 
 struct timespec {
-	__kernel_old_time_t	tv_sec;
-	long			tv_nsec;
+	time_t	tv_sec;
+	int64_t	tv_nsec;
 };
 #define _STRUCT_TIMESPEC
 
+/* Never use with system calls */
 struct timeval {
-	__kernel_old_time_t	tv_sec;
-	__kernel_suseconds_t	tv_usec;
+	time_t	tv_sec;
+	int64_t	tv_usec;
 };
 
 #define timeval __nolibc_kernel_timeval

-- 
2.52.0

Re: [PATCH v2 09/13] tools/nolibc: always use 64-bit time types
Posted by Willy Tarreau 1 day, 14 hours ago
Hi Thomas,

On Sat, Nov 22, 2025 at 05:59:15PM +0100, Thomas Weißschuh wrote:
> 32-bit time types will stop working in 2038.
> 
> Switch to 64-bit time types everywhere.
> 
> Suggested-by: Arnd Bergmann <arnd@arndb.de>
> Link: https://lore.kernel.org/lkml/cec27d94-c99d-4c57-9a12-275ea663dda8@app.fastmail.com/
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
>  tools/include/nolibc/std.h   | 2 +-
>  tools/include/nolibc/types.h | 9 +++++----
>  2 files changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/tools/include/nolibc/std.h b/tools/include/nolibc/std.h
> index 392f4dd94158..b9a116123902 100644
> --- a/tools/include/nolibc/std.h
> +++ b/tools/include/nolibc/std.h
> @@ -29,6 +29,6 @@ typedef unsigned long       nlink_t;
>  typedef  int64_t              off_t;
>  typedef   signed long     blksize_t;
>  typedef   signed long      blkcnt_t;
> -typedef __kernel_time_t      time_t;
> +typedef __kernel_time64_t    time_t;
>  
>  #endif /* _NOLIBC_STD_H */
> diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h
> index 5d180ffabcb6..8f3cb18df7f1 100644
> --- a/tools/include/nolibc/types.h
> +++ b/tools/include/nolibc/types.h
> @@ -17,14 +17,15 @@
>  #include <linux/wait.h>
>  
>  struct timespec {
> -	__kernel_old_time_t	tv_sec;
> -	long			tv_nsec;
> +	time_t	tv_sec;
> +	int64_t	tv_nsec;
>  };
>  #define _STRUCT_TIMESPEC
>  
> +/* Never use with system calls */
>  struct timeval {
> -	__kernel_old_time_t	tv_sec;
> -	__kernel_suseconds_t	tv_usec;
> +	time_t	tv_sec;
> +	int64_t	tv_usec;
>  };

It seems to me that glibc continues to make the effort of using a long
for tv_usec and tv_nsec. At least I'm seeing how that can make a
difference for application code given that these fields are constantly
multiplied or divided, forcing them to 64-bit when we know they'll never
be larger than 1 billion is extra burden for the application. Another
reason might be that the definition really changed from long to suseconds_t
in timeval a while ago, it's possible that it's used as a long in various
APIs (or even just printf formats).

IMHO it would be cleaner to keep it as a long here, or do you have a
particular reason for wanting int64_t (which BTW already forced a cast
in sys_gettimeofday()) ?

Thanks,
Willy
Re: [PATCH v2 09/13] tools/nolibc: always use 64-bit time types
Posted by Arnd Bergmann 17 hours ago
On Sun, Nov 30, 2025, at 11:58, Willy Tarreau wrote:
> On Sat, Nov 22, 2025 at 05:59:15PM +0100, Thomas Weißschuh wrote:

>>  struct timespec {
>> -	__kernel_old_time_t	tv_sec;
>> -	long			tv_nsec;
>> +	time_t	tv_sec;
>> +	int64_t	tv_nsec;
>>  };
>>  #define _STRUCT_TIMESPEC
>>  
>> +/* Never use with system calls */
>>  struct timeval {
>> -	__kernel_old_time_t	tv_sec;
>> -	__kernel_suseconds_t	tv_usec;
>> +	time_t	tv_sec;
>> +	int64_t	tv_usec;
>>  };
>
> It seems to me that glibc continues to make the effort of using a long
> for tv_usec and tv_nsec. At least I'm seeing how that can make a
> difference for application code given that these fields are constantly
> multiplied or divided, forcing them to 64-bit when we know they'll never
> be larger than 1 billion is extra burden for the application. Another
> reason might be that the definition really changed from long to suseconds_t
> in timeval a while ago, it's possible that it's used as a long in various
> APIs (or even just printf formats).
>
> IMHO it would be cleaner to keep it as a long here, or do you have a
> particular reason for wanting int64_t (which BTW already forced a cast
> in sys_gettimeofday()) ?

As far as I can tell, it's the other way round for suseconds_t,
which in glibc is defined as

#if __TIMESIZE == 64 && __WORDSIZE == 32
# define __TIME_T_TYPE          __SQUAD_TYPE
# define __SUSECONDS_T_TYPE     __SQUAD_TYPE
#else
# define __TIME_T_TYPE          __SLONGWORD_TYPE
# define __SUSECONDS_T_TYPE     __SLONGWORD_TYPE
#endif

so this one is explicitly the same width as tv_sec, which has all
the issues you listed, but avoids the need for padding.

As far as I remember, the one reason for having a 'long tv_nsec'
with complex padding in glibc and musl is that this is actually
required by both Unix[1] and C11/C11 [2] standards.

C23 has updated the definition and does allow int64_t tv_nsec.
I think it makes sense for nolibc to just follow the kernel's
definition here.

       Arnd

[1] https://pubs.opengroup.org/onlinepubs/009695399/basedefs/time.h.html
[2] https://en.cppreference.com/w/c/chrono/timespec.html
Re: [PATCH v2 09/13] tools/nolibc: always use 64-bit time types
Posted by Willy Tarreau 14 hours ago
Hi Arnd,

On Mon, Dec 01, 2025 at 08:45:00AM +0100, Arnd Bergmann wrote:
> On Sun, Nov 30, 2025, at 11:58, Willy Tarreau wrote:
> > On Sat, Nov 22, 2025 at 05:59:15PM +0100, Thomas Weißschuh wrote:
> 
> >>  struct timespec {
> >> -	__kernel_old_time_t	tv_sec;
> >> -	long			tv_nsec;
> >> +	time_t	tv_sec;
> >> +	int64_t	tv_nsec;
> >>  };
> >>  #define _STRUCT_TIMESPEC
> >>  
> >> +/* Never use with system calls */
> >>  struct timeval {
> >> -	__kernel_old_time_t	tv_sec;
> >> -	__kernel_suseconds_t	tv_usec;
> >> +	time_t	tv_sec;
> >> +	int64_t	tv_usec;
> >>  };
> >
> > It seems to me that glibc continues to make the effort of using a long
> > for tv_usec and tv_nsec. At least I'm seeing how that can make a
> > difference for application code given that these fields are constantly
> > multiplied or divided, forcing them to 64-bit when we know they'll never
> > be larger than 1 billion is extra burden for the application. Another
> > reason might be that the definition really changed from long to suseconds_t
> > in timeval a while ago, it's possible that it's used as a long in various
> > APIs (or even just printf formats).
> >
> > IMHO it would be cleaner to keep it as a long here, or do you have a
> > particular reason for wanting int64_t (which BTW already forced a cast
> > in sys_gettimeofday()) ?
> 
> As far as I can tell, it's the other way round for suseconds_t,
> which in glibc is defined as
> 
> #if __TIMESIZE == 64 && __WORDSIZE == 32
> # define __TIME_T_TYPE          __SQUAD_TYPE
> # define __SUSECONDS_T_TYPE     __SQUAD_TYPE
> #else
> # define __TIME_T_TYPE          __SLONGWORD_TYPE
> # define __SUSECONDS_T_TYPE     __SLONGWORD_TYPE
> #endif
> 
> so this one is explicitly the same width as tv_sec, which has all
> the issues you listed, but avoids the need for padding.

Ah we seem to just have checked different versions then,
as in mine there was still some extra padding left depending
on the endianness :-)

> As far as I remember, the one reason for having a 'long tv_nsec'
> with complex padding in glibc and musl is that this is actually
> required by both Unix[1] and C11/C11 [2] standards.

That's what I found as well and was my initial compatibility
concern (e.g. referencing &tv->tv_nsec as a long).

> C23 has updated the definition and does allow int64_t tv_nsec.

So it purposely breaks existing apps or does it apply only to those
compiled with -mstd=c23 ?

> I think it makes sense for nolibc to just follow the kernel's
> definition here.

Given the very narrow range of existing code that can be impacted,
I'm fine, but in general I try to remain extremely cautious about
portability: as a general rule, ifdefs needed to address possible
incompatibilities, if any, should rather be in the libc code itself
and not in the user application. I just ran a quick check and don't
have code using &tv_usec nor &tv_nsec so here the risk remains quite
low.

Thanks,
Willy
Re: [PATCH v2 09/13] tools/nolibc: always use 64-bit time types
Posted by Arnd Bergmann 14 hours ago
On Mon, Dec 1, 2025, at 11:35, Willy Tarreau wrote:
> On Mon, Dec 01, 2025 at 08:45:00AM +0100, Arnd Bergmann wrote:
>> On Sun, Nov 30, 2025, at 11:58, Willy Tarreau wrote:
>>
>> #if __TIMESIZE == 64 && __WORDSIZE == 32
>> # define __TIME_T_TYPE          __SQUAD_TYPE
>> # define __SUSECONDS_T_TYPE     __SQUAD_TYPE
>> #else
>> # define __TIME_T_TYPE          __SLONGWORD_TYPE
>> # define __SUSECONDS_T_TYPE     __SLONGWORD_TYPE
>> #endif
>> 
>> so this one is explicitly the same width as tv_sec, which has all
>> the issues you listed, but avoids the need for padding.
>
> Ah we seem to just have checked different versions then,
> as in mine there was still some extra padding left depending
> on the endianness :-)

The padding is definitely there in timespec around tv_nsec,
just not in timeval.

Oddly, the version I quoted is from my arm64 /usr/include/
installation and looks different from what I see in the glibc
history, though that also uses a 64-bit tv_usec:

bits/typesizes.h:#define __SUSECONDS64_T_TYPE   __SQUAD_TYPE
posix/bits/types.h:__STD_TYPE __SUSECONDS64_T_TYPE __suseconds64_t;
struct timeval
{
#ifdef __USE_TIME64_REDIRECTS
  __time64_t tv_sec;            /* Seconds.  */
  __suseconds64_t tv_usec;      /* Microseconds.  */
#else
  __time_t tv_sec;              /* Seconds.  */
  __suseconds_t tv_usec;        /* Microseconds.  */
#endif
};

>> C23 has updated the definition and does allow int64_t tv_nsec.
>
> So it purposely breaks existing apps or does it apply only to those
> compiled with -mstd=c23 ?

Neither, it's just that nolibc with a 64-bit tv_nsec would
be compliant with c23, just not earlier versions.

I expect glibc to stick with 32-bit timespec and padding, which
is still compliant with the new definition of

|   The type of tv_nsec is an implementation-defined signed integer type
|   that can represent integers in [​0​, 999999999]. 

>> I think it makes sense for nolibc to just follow the kernel's
>> definition here.
>
> Given the very narrow range of existing code that can be impacted,
> I'm fine, but in general I try to remain extremely cautious about
> portability: as a general rule, ifdefs needed to address possible
> incompatibilities, if any, should rather be in the libc code itself
> and not in the user application. I just ran a quick check and don't
> have code using &tv_usec nor &tv_nsec so here the risk remains quite
> low.

Ok

     ARnd