libstdc++: Use FUTEX_CLOCK_REALTIME for futex wait
authorMike Crowe <mac@mcrowe.com>
Fri, 11 Sep 2020 13:24:59 +0000 (14:24 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Fri, 11 Sep 2020 13:24:59 +0000 (14:24 +0100)
commit5bad23ceec0bfc9fea7c3da10b187366052de369
tree66830168b76011e89065e48eb73d478020815350
parentf639343dc8c4fa65342a8c1fd43384999cf9f9d0
libstdc++: Use FUTEX_CLOCK_REALTIME for futex wait

The futex system call supports waiting for an absolute time if
FUTEX_WAIT_BITSET is used rather than FUTEX_WAIT.  Doing so provides two
benefits:

1. The call to gettimeofday is not required in order to calculate a
   relative timeout.

2. If someone changes the system clock during the wait then the futex
   timeout will correctly expire earlier or later.  Currently that only
   happens if the clock is changed prior to the call to gettimeofday.

According to futex(2), support for FUTEX_CLOCK_REALTIME was added in the
v2.6.28 Linux kernel and FUTEX_WAIT_BITSET was added in v2.6.25.  To
ensure that the code still works correctly with earlier kernel versions,
an ENOSYS error from futex[1] results in the
futex_clock_realtime_unavailable flag being set.  This flag is used to
avoid the unnecessary unsupported futex call in the future and to fall
back to the previous gettimeofday and relative time implementation.

glibc applied an equivalent switch in pthread_cond_timedwait to use
FUTEX_CLOCK_REALTIME and FUTEX_WAIT_BITSET rather than FUTEX_WAIT for
glibc-2.10 back in 2009.  See
glibc:cbd8aeb836c8061c23a5e00419e0fb25a34abee7

The futex_clock_realtime_unavailable flag is accessed using
std::memory_order_relaxed to stop it becoming a bottleneck.  If the
first two calls to _M_futex_wait_until happen to happen simultaneously
then the only consequence is that both will try to use
FUTEX_CLOCK_REALTIME, both risk discovering that it doesn't work and, if
so, both set the flag.

[1] This is how glibc's nptl-init.c determines whether these flags are
    supported.

libstdc++-v3/ChangeLog:

* src/c++11/futex.cc: Add new constants for required futex
flags.  Add futex_clock_realtime_unavailable flag to store
result of trying to use FUTEX_CLOCK_REALTIME.
(__atomic_futex_unsigned_base::_M_futex_wait_until): Try to
use FUTEX_WAIT_BITSET with FUTEX_CLOCK_REALTIME and only
fall back to using gettimeofday and FUTEX_WAIT if that's not
supported.
libstdc++-v3/src/c++11/futex.cc