1*9356374aSAndroid Build Coastguard Worker // Copyright 2020 The Abseil Authors. 2*9356374aSAndroid Build Coastguard Worker // 3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*9356374aSAndroid Build Coastguard Worker // 7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0 8*9356374aSAndroid Build Coastguard Worker // 9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*9356374aSAndroid Build Coastguard Worker // limitations under the License. 14*9356374aSAndroid Build Coastguard Worker #ifndef ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_ 15*9356374aSAndroid Build Coastguard Worker #define ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_ 16*9356374aSAndroid Build Coastguard Worker 17*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h" 18*9356374aSAndroid Build Coastguard Worker 19*9356374aSAndroid Build Coastguard Worker #ifndef _WIN32 20*9356374aSAndroid Build Coastguard Worker #include <sys/time.h> 21*9356374aSAndroid Build Coastguard Worker #include <unistd.h> 22*9356374aSAndroid Build Coastguard Worker #endif 23*9356374aSAndroid Build Coastguard Worker 24*9356374aSAndroid Build Coastguard Worker #ifdef __linux__ 25*9356374aSAndroid Build Coastguard Worker #include <linux/futex.h> 26*9356374aSAndroid Build Coastguard Worker #include <sys/syscall.h> 27*9356374aSAndroid Build Coastguard Worker #endif 28*9356374aSAndroid Build Coastguard Worker 29*9356374aSAndroid Build Coastguard Worker #include <errno.h> 30*9356374aSAndroid Build Coastguard Worker #include <stdio.h> 31*9356374aSAndroid Build Coastguard Worker #include <time.h> 32*9356374aSAndroid Build Coastguard Worker 33*9356374aSAndroid Build Coastguard Worker #include <atomic> 34*9356374aSAndroid Build Coastguard Worker #include <cstdint> 35*9356374aSAndroid Build Coastguard Worker #include <limits> 36*9356374aSAndroid Build Coastguard Worker 37*9356374aSAndroid Build Coastguard Worker #include "absl/base/optimization.h" 38*9356374aSAndroid Build Coastguard Worker #include "absl/synchronization/internal/kernel_timeout.h" 39*9356374aSAndroid Build Coastguard Worker 40*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_INTERNAL_HAVE_FUTEX 41*9356374aSAndroid Build Coastguard Worker #error ABSL_INTERNAL_HAVE_FUTEX may not be set on the command line 42*9356374aSAndroid Build Coastguard Worker #elif defined(__BIONIC__) 43*9356374aSAndroid Build Coastguard Worker // Bionic supports all the futex operations we need even when some of the futex 44*9356374aSAndroid Build Coastguard Worker // definitions are missing. 45*9356374aSAndroid Build Coastguard Worker #define ABSL_INTERNAL_HAVE_FUTEX 46*9356374aSAndroid Build Coastguard Worker #elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME) 47*9356374aSAndroid Build Coastguard Worker // FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28. 48*9356374aSAndroid Build Coastguard Worker #define ABSL_INTERNAL_HAVE_FUTEX 49*9356374aSAndroid Build Coastguard Worker #endif 50*9356374aSAndroid Build Coastguard Worker 51*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_INTERNAL_HAVE_FUTEX 52*9356374aSAndroid Build Coastguard Worker 53*9356374aSAndroid Build Coastguard Worker namespace absl { 54*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN 55*9356374aSAndroid Build Coastguard Worker namespace synchronization_internal { 56*9356374aSAndroid Build Coastguard Worker 57*9356374aSAndroid Build Coastguard Worker // Some Android headers are missing these definitions even though they 58*9356374aSAndroid Build Coastguard Worker // support these futex operations. 59*9356374aSAndroid Build Coastguard Worker #ifdef __BIONIC__ 60*9356374aSAndroid Build Coastguard Worker #ifndef SYS_futex 61*9356374aSAndroid Build Coastguard Worker #define SYS_futex __NR_futex 62*9356374aSAndroid Build Coastguard Worker #endif 63*9356374aSAndroid Build Coastguard Worker #ifndef FUTEX_WAIT_BITSET 64*9356374aSAndroid Build Coastguard Worker #define FUTEX_WAIT_BITSET 9 65*9356374aSAndroid Build Coastguard Worker #endif 66*9356374aSAndroid Build Coastguard Worker #ifndef FUTEX_PRIVATE_FLAG 67*9356374aSAndroid Build Coastguard Worker #define FUTEX_PRIVATE_FLAG 128 68*9356374aSAndroid Build Coastguard Worker #endif 69*9356374aSAndroid Build Coastguard Worker #ifndef FUTEX_CLOCK_REALTIME 70*9356374aSAndroid Build Coastguard Worker #define FUTEX_CLOCK_REALTIME 256 71*9356374aSAndroid Build Coastguard Worker #endif 72*9356374aSAndroid Build Coastguard Worker #ifndef FUTEX_BITSET_MATCH_ANY 73*9356374aSAndroid Build Coastguard Worker #define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF 74*9356374aSAndroid Build Coastguard Worker #endif 75*9356374aSAndroid Build Coastguard Worker #endif 76*9356374aSAndroid Build Coastguard Worker 77*9356374aSAndroid Build Coastguard Worker #if defined(__NR_futex_time64) && !defined(SYS_futex_time64) 78*9356374aSAndroid Build Coastguard Worker #define SYS_futex_time64 __NR_futex_time64 79*9356374aSAndroid Build Coastguard Worker #endif 80*9356374aSAndroid Build Coastguard Worker 81*9356374aSAndroid Build Coastguard Worker #if defined(SYS_futex_time64) && !defined(SYS_futex) 82*9356374aSAndroid Build Coastguard Worker #define SYS_futex SYS_futex_time64 83*9356374aSAndroid Build Coastguard Worker using FutexTimespec = struct timespec; 84*9356374aSAndroid Build Coastguard Worker #else 85*9356374aSAndroid Build Coastguard Worker // Some libc implementations have switched to an unconditional 64-bit `time_t` 86*9356374aSAndroid Build Coastguard Worker // definition. This means that `struct timespec` may not match the layout 87*9356374aSAndroid Build Coastguard Worker // expected by the kernel ABI on 32-bit platforms. So we define the 88*9356374aSAndroid Build Coastguard Worker // FutexTimespec that matches the kernel timespec definition. It should be safe 89*9356374aSAndroid Build Coastguard Worker // to use this struct for 64-bit userspace builds too, since it will use another 90*9356374aSAndroid Build Coastguard Worker // SYS_futex kernel call with 64-bit tv_sec inside timespec. 91*9356374aSAndroid Build Coastguard Worker struct FutexTimespec { 92*9356374aSAndroid Build Coastguard Worker long tv_sec; // NOLINT 93*9356374aSAndroid Build Coastguard Worker long tv_nsec; // NOLINT 94*9356374aSAndroid Build Coastguard Worker }; 95*9356374aSAndroid Build Coastguard Worker #endif 96*9356374aSAndroid Build Coastguard Worker 97*9356374aSAndroid Build Coastguard Worker class FutexImpl { 98*9356374aSAndroid Build Coastguard Worker public: 99*9356374aSAndroid Build Coastguard Worker // Atomically check that `*v == val`, and if it is, then sleep until the until 100*9356374aSAndroid Build Coastguard Worker // woken by `Wake()`. Wait(std::atomic<int32_t> * v,int32_t val)101*9356374aSAndroid Build Coastguard Worker static int Wait(std::atomic<int32_t>* v, int32_t val) { 102*9356374aSAndroid Build Coastguard Worker return WaitAbsoluteTimeout(v, val, nullptr); 103*9356374aSAndroid Build Coastguard Worker } 104*9356374aSAndroid Build Coastguard Worker 105*9356374aSAndroid Build Coastguard Worker // Atomically check that `*v == val`, and if it is, then sleep until 106*9356374aSAndroid Build Coastguard Worker // CLOCK_REALTIME reaches `*abs_timeout`, or until woken by `Wake()`. WaitAbsoluteTimeout(std::atomic<int32_t> * v,int32_t val,const struct timespec * abs_timeout)107*9356374aSAndroid Build Coastguard Worker static int WaitAbsoluteTimeout(std::atomic<int32_t>* v, int32_t val, 108*9356374aSAndroid Build Coastguard Worker const struct timespec* abs_timeout) { 109*9356374aSAndroid Build Coastguard Worker FutexTimespec ts; 110*9356374aSAndroid Build Coastguard Worker // https://locklessinc.com/articles/futex_cheat_sheet/ 111*9356374aSAndroid Build Coastguard Worker // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time. 112*9356374aSAndroid Build Coastguard Worker auto err = syscall( 113*9356374aSAndroid Build Coastguard Worker SYS_futex, reinterpret_cast<int32_t*>(v), 114*9356374aSAndroid Build Coastguard Worker FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val, 115*9356374aSAndroid Build Coastguard Worker ToFutexTimespec(abs_timeout, &ts), nullptr, FUTEX_BITSET_MATCH_ANY); 116*9356374aSAndroid Build Coastguard Worker if (err != 0) { 117*9356374aSAndroid Build Coastguard Worker return -errno; 118*9356374aSAndroid Build Coastguard Worker } 119*9356374aSAndroid Build Coastguard Worker return 0; 120*9356374aSAndroid Build Coastguard Worker } 121*9356374aSAndroid Build Coastguard Worker 122*9356374aSAndroid Build Coastguard Worker // Atomically check that `*v == val`, and if it is, then sleep until 123*9356374aSAndroid Build Coastguard Worker // `*rel_timeout` has elapsed, or until woken by `Wake()`. WaitRelativeTimeout(std::atomic<int32_t> * v,int32_t val,const struct timespec * rel_timeout)124*9356374aSAndroid Build Coastguard Worker static int WaitRelativeTimeout(std::atomic<int32_t>* v, int32_t val, 125*9356374aSAndroid Build Coastguard Worker const struct timespec* rel_timeout) { 126*9356374aSAndroid Build Coastguard Worker FutexTimespec ts; 127*9356374aSAndroid Build Coastguard Worker // Atomically check that the futex value is still 0, and if it 128*9356374aSAndroid Build Coastguard Worker // is, sleep until abs_timeout or until woken by FUTEX_WAKE. 129*9356374aSAndroid Build Coastguard Worker auto err = 130*9356374aSAndroid Build Coastguard Worker syscall(SYS_futex, reinterpret_cast<int32_t*>(v), FUTEX_PRIVATE_FLAG, 131*9356374aSAndroid Build Coastguard Worker val, ToFutexTimespec(rel_timeout, &ts)); 132*9356374aSAndroid Build Coastguard Worker if (err != 0) { 133*9356374aSAndroid Build Coastguard Worker return -errno; 134*9356374aSAndroid Build Coastguard Worker } 135*9356374aSAndroid Build Coastguard Worker return 0; 136*9356374aSAndroid Build Coastguard Worker } 137*9356374aSAndroid Build Coastguard Worker 138*9356374aSAndroid Build Coastguard Worker // Wakes at most `count` waiters that have entered the sleep state on `v`. Wake(std::atomic<int32_t> * v,int32_t count)139*9356374aSAndroid Build Coastguard Worker static int Wake(std::atomic<int32_t>* v, int32_t count) { 140*9356374aSAndroid Build Coastguard Worker auto err = syscall(SYS_futex, reinterpret_cast<int32_t*>(v), 141*9356374aSAndroid Build Coastguard Worker FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count); 142*9356374aSAndroid Build Coastguard Worker if (ABSL_PREDICT_FALSE(err < 0)) { 143*9356374aSAndroid Build Coastguard Worker return -errno; 144*9356374aSAndroid Build Coastguard Worker } 145*9356374aSAndroid Build Coastguard Worker return 0; 146*9356374aSAndroid Build Coastguard Worker } 147*9356374aSAndroid Build Coastguard Worker 148*9356374aSAndroid Build Coastguard Worker private: ToFutexTimespec(const struct timespec * userspace_ts,FutexTimespec * futex_ts)149*9356374aSAndroid Build Coastguard Worker static FutexTimespec* ToFutexTimespec(const struct timespec* userspace_ts, 150*9356374aSAndroid Build Coastguard Worker FutexTimespec* futex_ts) { 151*9356374aSAndroid Build Coastguard Worker if (userspace_ts == nullptr) { 152*9356374aSAndroid Build Coastguard Worker return nullptr; 153*9356374aSAndroid Build Coastguard Worker } 154*9356374aSAndroid Build Coastguard Worker 155*9356374aSAndroid Build Coastguard Worker using FutexSeconds = decltype(futex_ts->tv_sec); 156*9356374aSAndroid Build Coastguard Worker using FutexNanoseconds = decltype(futex_ts->tv_nsec); 157*9356374aSAndroid Build Coastguard Worker 158*9356374aSAndroid Build Coastguard Worker constexpr auto kMaxSeconds{(std::numeric_limits<FutexSeconds>::max)()}; 159*9356374aSAndroid Build Coastguard Worker if (userspace_ts->tv_sec > kMaxSeconds) { 160*9356374aSAndroid Build Coastguard Worker futex_ts->tv_sec = kMaxSeconds; 161*9356374aSAndroid Build Coastguard Worker } else { 162*9356374aSAndroid Build Coastguard Worker futex_ts->tv_sec = static_cast<FutexSeconds>(userspace_ts->tv_sec); 163*9356374aSAndroid Build Coastguard Worker } 164*9356374aSAndroid Build Coastguard Worker futex_ts->tv_nsec = static_cast<FutexNanoseconds>(userspace_ts->tv_nsec); 165*9356374aSAndroid Build Coastguard Worker return futex_ts; 166*9356374aSAndroid Build Coastguard Worker } 167*9356374aSAndroid Build Coastguard Worker }; 168*9356374aSAndroid Build Coastguard Worker 169*9356374aSAndroid Build Coastguard Worker class Futex : public FutexImpl {}; 170*9356374aSAndroid Build Coastguard Worker 171*9356374aSAndroid Build Coastguard Worker } // namespace synchronization_internal 172*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END 173*9356374aSAndroid Build Coastguard Worker } // namespace absl 174*9356374aSAndroid Build Coastguard Worker 175*9356374aSAndroid Build Coastguard Worker #endif // ABSL_INTERNAL_HAVE_FUTEX 176*9356374aSAndroid Build Coastguard Worker 177*9356374aSAndroid Build Coastguard Worker #endif // ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_ 178