On Sat, 14 Nov 2020, 13:30 Mike Crowe via Libstdc++, <libstd...@gcc.gnu.org> wrote:
> On Saturday 14 November 2020 at 00:17:59 +0000, Jonathan Wakely via > Libstdc++ wrote: > > On 32-bit targets where userspace has switched to 64-bit time_t, we > > cannot pass struct timespec to SYS_futex or SYS_clock_gettime, because > > the userspace definition of struct timespec will not match what the > > kernel expects. > > > > We use the existence of the SYS_futex_time64 or SYS_clock_gettime_time64 > > macros to imply that userspace *might* have switched to the new timespec > > definition. This is a conservative assumption. It's possible that the > > new syscall numbers are defined in the libc headers but that timespec > > hasn't been updated yet (as is the case for glibc currently). But using > > the alternative struct with two longs is still OK, it's just redundant > > if userspace timespec still uses a 32-bit time_t. > > > > We also check that SYS_futex_time64 != SYS_futex so that we don't try > > to use a 32-bit tv_sec on modern targets that only support the 64-bit > > system calls and define the old macro to the same value as the new one. > > > > We could possibly check #ifdef __USE_TIME_BITS64 to see whether > > userspace has actually been updated, but it's not clear if user code > > is meant to inspect that or if it's only for libc internal use. > > > > libstdc++-v3/ChangeLog: > > > > PR libstdc++/93421 > > * src/c++11/chrono.cc [_GLIBCXX_USE_CLOCK_GETTIME_SYSCALL] > > (syscall_timespec): Define a type suitable for SYS_clock_gettime > > calls. > > (system_clock::now(), steady_clock::now()): Use syscall_timespec > > instead of timespec. > > * src/c++11/futex.cc (syscall_timespec): Define a type suitable > > for SYS_futex and SYS_clock_gettime calls. > > (relative_timespec): Use syscall_timespec instead of timespec. > > (__atomic_futex_unsigned_base::_M_futex_wait_until): Likewise. > > (__atomic_futex_unsigned_base::_M_futex_wait_until_steady): > > Likewise. > > > > Tested x86_64-linux, -m32 too. Committed to trunk. > > > > > commit 4d039cb9a1d0ffc6910fe09b726c3561b64527dc > > Author: Jonathan Wakely <jwak...@redhat.com> > > Date: Thu Sep 24 17:35:52 2020 > > > > libstdc++: Use custom timespec in system calls [PR 93421] > > > > On 32-bit targets where userspace has switched to 64-bit time_t, we > > cannot pass struct timespec to SYS_futex or SYS_clock_gettime, > because > > the userspace definition of struct timespec will not match what the > > kernel expects. > > > > We use the existence of the SYS_futex_time64 or > SYS_clock_gettime_time64 > > macros to imply that userspace *might* have switched to the new > timespec > > definition. This is a conservative assumption. It's possible that > the > > new syscall numbers are defined in the libc headers but that timespec > > hasn't been updated yet (as is the case for glibc currently). But > using > > the alternative struct with two longs is still OK, it's just > redundant > > if userspace timespec still uses a 32-bit time_t. > > > > We also check that SYS_futex_time64 != SYS_futex so that we don't try > > to use a 32-bit tv_sec on modern targets that only support the 64-bit > > system calls and define the old macro to the same value as the new > one. > > > > We could possibly check #ifdef __USE_TIME_BITS64 to see whether > > userspace has actually been updated, but it's not clear if user code > > is meant to inspect that or if it's only for libc internal use. > > Presumably this is change is only good for the short term? We really want > to be calling the 64-bit time_t versions of SYS_futex and SYS_clock_gettime > passing 64-bit struct timespec so that this code continues to work > correctly after 2038 (for CLOCK_REALTIME) or if someone is unlucky enough > to have a system uptime of over 68 years (for CLOCK_MONOTONIC.) Perhaps > that's part of the post-GCC11 work that you plan to do. > Right. This is definitely a short term solution, but I ran out of time to do something better for GCC 11. > (There's another comment on the patch itself below.) > > > libstdc++-v3/ChangeLog: > > > > PR libstdc++/93421 > > * src/c++11/chrono.cc [_GLIBCXX_USE_CLOCK_GETTIME_SYSCALL] > > (syscall_timespec): Define a type suitable for > SYS_clock_gettime > > calls. > > (system_clock::now(), steady_clock::now()): Use > syscall_timespec > > instead of timespec. > > * src/c++11/futex.cc (syscall_timespec): Define a type > suitable > > for SYS_futex and SYS_clock_gettime calls. > > (relative_timespec): Use syscall_timespec instead of > timespec. > > (__atomic_futex_unsigned_base::_M_futex_wait_until): > Likewise. > > (__atomic_futex_unsigned_base::_M_futex_wait_until_steady): > > Likewise. > > > > diff --git a/libstdc++-v3/src/c++11/chrono.cc > b/libstdc++-v3/src/c++11/chrono.cc > > index 723f3002d11a..f10be7d8c073 100644 > > --- a/libstdc++-v3/src/c++11/chrono.cc > > +++ b/libstdc++-v3/src/c++11/chrono.cc > > @@ -35,6 +35,17 @@ > > #ifdef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL > > #include <unistd.h> > > #include <sys/syscall.h> > > + > > +# if defined(SYS_clock_gettime_time64) \ > > + && SYS_clock_gettime_time64 != SYS_clock_gettime > > + // Userspace knows about the new time64 syscalls, so it's possible > that > > + // userspace has also updated timespec to use a 64-bit tv_sec. > > + // The SYS_clock_gettime syscall still uses the old definition > > + // of timespec where tv_sec is 32 bits, so define a type that matches > that. > > + struct syscall_timespec { long tv_sec; long tv_nsec; }; > > +# else > > + using syscall_timespec = ::timespec; > > +# endif > > #endif > > > > namespace std _GLIBCXX_VISIBILITY(default) > > @@ -52,11 +63,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > system_clock::now() noexcept > > { > > #ifdef _GLIBCXX_USE_CLOCK_REALTIME > > - timespec tp; > > // -EINVAL, -EFAULT > > #ifdef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL > > + syscall_timespec tp; > > syscall(SYS_clock_gettime, CLOCK_REALTIME, &tp); > > #else > > + timespec tp; > > clock_gettime(CLOCK_REALTIME, &tp); > > #endif > > return time_point(duration(chrono::seconds(tp.tv_sec) > > @@ -80,11 +92,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > steady_clock::now() noexcept > > { > > #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC > > - timespec tp; > > // -EINVAL, -EFAULT > > #ifdef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL > > + syscall_timespec tp; > > syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &tp); > > #else > > + timespec tp; > > clock_gettime(CLOCK_MONOTONIC, &tp); > > #endif > > return time_point(duration(chrono::seconds(tp.tv_sec) > > diff --git a/libstdc++-v3/src/c++11/futex.cc > b/libstdc++-v3/src/c++11/futex.cc > > index c008798318c9..9adfb898b4f1 100644 > > --- a/libstdc++-v3/src/c++11/futex.cc > > +++ b/libstdc++-v3/src/c++11/futex.cc > > @@ -58,13 +58,23 @@ namespace > > std::atomic<bool> futex_clock_realtime_unavailable; > > std::atomic<bool> futex_clock_monotonic_unavailable; > > > > +#if defined(SYS_futex_time64) && SYS_futex_time64 != SYS_futex > > + // Userspace knows about the new time64 syscalls, so it's possible > that > > + // userspace has also updated timespec to use a 64-bit tv_sec. > > + // The SYS_futex and SYS_clock_gettime syscalls still use the old > definition > > + // of timespec where tv_sec is 32 bits, so define a type that matches > that. > > + struct syscall_timespec { long tv_sec; long tv_nsec; }; > > +#else > > + using syscall_timespec = ::timespec; > > +#endif > > + > > // Return the relative duration from (now_s + now_ns) to (abs_s + > abs_ns) > > - // as a timespec. > > - struct timespec > > + // as a timespec suitable for syscalls. > > + syscall_timespec > > relative_timespec(chrono::seconds abs_s, chrono::nanoseconds abs_ns, > > time_t now_s, long now_ns) > > { > > - struct timespec rt; > > + syscall_timespec rt; > > > > // Did we already time out? > > if (now_s > abs_s.count()) > > @@ -119,7 +129,7 @@ namespace > > if (__s.count() < 0) > > return false; > > > > - struct timespec rt; > > + syscall_timespec rt; > > if (__s.count() > __int_traits<time_t>::__max) [[unlikely]] > > rt.tv_sec = __int_traits<time_t>::__max; > > else > > @@ -195,7 +205,7 @@ namespace > > if (__s.count() < 0) [[unlikely]] > > return false; > > > > - struct timespec rt; > > + syscall_timespec rt; > > if (__s.count() > __int_traits<time_t>::__max) [[unlikely]] > > rt.tv_sec = __int_traits<time_t>::__max; > > Do these now need to be __int_traits<long>::__max in case time_t is 64-bit > yet syscall_timespec is using 32-bit long? > Ah yes. Maybe decltype(rt.tv_sec).