xref: /aosp_15_r20/external/abseil-cpp/absl/synchronization/internal/futex.h (revision 9356374a3709195abf420251b3e825997ff56c0f)
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