1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /****************************************************************************** 3 * 4 * Copyright © International Business Machines Corp., 2009 5 * 6 * DESCRIPTION 7 * Glibc independent futex library for testing kernel functionality. 8 * 9 * AUTHOR 10 * Darren Hart <dvhart@linux.intel.com> 11 * 12 * HISTORY 13 * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com> 14 * 15 *****************************************************************************/ 16 17 #ifndef _FUTEXTEST_H 18 #define _FUTEXTEST_H 19 20 #include <unistd.h> 21 #include <sys/syscall.h> 22 #include <sys/types.h> 23 #include <linux/futex.h> 24 25 typedef volatile u_int32_t futex_t; 26 #define FUTEX_INITIALIZER 0 27 28 /* Define the newer op codes if the system header file is not up to date. */ 29 #ifndef FUTEX_WAIT_BITSET 30 #define FUTEX_WAIT_BITSET 9 31 #endif 32 #ifndef FUTEX_WAKE_BITSET 33 #define FUTEX_WAKE_BITSET 10 34 #endif 35 #ifndef FUTEX_WAIT_REQUEUE_PI 36 #define FUTEX_WAIT_REQUEUE_PI 11 37 #endif 38 #ifndef FUTEX_CMP_REQUEUE_PI 39 #define FUTEX_CMP_REQUEUE_PI 12 40 #endif 41 #ifndef FUTEX_ROBUST_UNLOCK 42 #define FUTEX_ROBUST_UNLOCK 512 43 #endif 44 #ifndef FUTEX_ROBUST_LIST32 45 #define FUTEX_ROBUST_LIST32 1024 46 #endif 47 #ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE 48 #define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \ 49 FUTEX_PRIVATE_FLAG) 50 #endif 51 #ifndef FUTEX_REQUEUE_PI_PRIVATE 52 #define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ 53 FUTEX_PRIVATE_FLAG) 54 #endif 55 56 /* 57 * SYS_futex is expected from system C library, in glibc some 32-bit 58 * architectures (e.g. RV32) are using 64-bit time_t, therefore it doesn't have 59 * SYS_futex defined but just SYS_futex_time64. Define SYS_futex as 60 * SYS_futex_time64 in this situation to ensure the compilation and the 61 * compatibility. 62 */ 63 #if !defined(SYS_futex) && defined(SYS_futex_time64) 64 #define SYS_futex SYS_futex_time64 65 #endif 66 67 /* 68 * On 32bit systems if we use "-D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64" or if 69 * we are using a newer compiler then the size of the timestamps will be 64bit, 70 * however, the SYS_futex will still point to the 32bit futex system call. 71 */ 72 #if __SIZEOF_POINTER__ == 4 && defined(SYS_futex_time64) && \ 73 defined(_TIME_BITS) && _TIME_BITS == 64 74 # undef SYS_futex 75 # define SYS_futex SYS_futex_time64 76 #endif 77 78 /** 79 * futex() - SYS_futex syscall wrapper 80 * @uaddr: address of first futex 81 * @op: futex op code 82 * @val: typically expected value of uaddr, but varies by op 83 * @timeout: typically an absolute struct timespec (except where noted 84 * otherwise). Overloaded by some ops 85 * @uaddr2: address of second futex for some ops\ 86 * @val3: varies by op 87 * @opflags: flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG 88 * 89 * futex() is used by all the following futex op wrappers. It can also be 90 * used for misuse and abuse testing. Generally, the specific op wrappers 91 * should be used instead. It is a macro instead of an static inline function as 92 * some of the types over overloaded (timeout is used for nr_requeue for 93 * example). 94 * 95 * These argument descriptions are the defaults for all 96 * like-named arguments in the following wrappers except where noted below. 97 */ 98 #define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \ 99 syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3) 100 101 /** 102 * futex_wait() - block on uaddr with optional timeout 103 * @timeout: relative timeout 104 */ 105 static inline int 106 futex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags) 107 { 108 return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags); 109 } 110 111 /** 112 * futex_wake() - wake one or more tasks blocked on uaddr 113 * @nr_wake: wake up to this many tasks 114 */ 115 static inline int 116 futex_wake(futex_t *uaddr, int nr_wake, int opflags) 117 { 118 return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags); 119 } 120 121 /** 122 * futex_wait_bitset() - block on uaddr with bitset 123 * @bitset: bitset to be used with futex_wake_bitset 124 */ 125 static inline int 126 futex_wait_bitset(futex_t *uaddr, futex_t val, struct timespec *timeout, 127 u_int32_t bitset, int opflags) 128 { 129 return futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset, 130 opflags); 131 } 132 133 /** 134 * futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset 135 * @bitset: bitset to compare with that used in futex_wait_bitset 136 */ 137 static inline int 138 futex_wake_bitset(futex_t *uaddr, int nr_wake, u_int32_t bitset, int opflags) 139 { 140 return futex(uaddr, FUTEX_WAKE_BITSET, nr_wake, NULL, NULL, bitset, 141 opflags); 142 } 143 144 /** 145 * futex_lock_pi() - block on uaddr as a PI mutex 146 * @detect: whether (1) or not (0) to perform deadlock detection 147 */ 148 static inline int 149 futex_lock_pi(futex_t *uaddr, struct timespec *timeout, int detect, 150 int opflags) 151 { 152 return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags); 153 } 154 155 /** 156 * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter 157 */ 158 static inline int 159 futex_unlock_pi(futex_t *uaddr, int opflags) 160 { 161 return futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags); 162 } 163 164 /** 165 * futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION 166 */ 167 static inline int 168 futex_wake_op(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_wake2, 169 int wake_op, int opflags) 170 { 171 return futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op, 172 opflags); 173 } 174 175 /** 176 * futex_requeue() - requeue without expected value comparison, deprecated 177 * @nr_wake: wake up to this many tasks 178 * @nr_requeue: requeue up to this many tasks 179 * 180 * Due to its inherently racy implementation, futex_requeue() is deprecated in 181 * favor of futex_cmp_requeue(). 182 */ 183 static inline int 184 futex_requeue(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_requeue, 185 int opflags) 186 { 187 return futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0, 188 opflags); 189 } 190 191 /** 192 * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2 193 * @nr_wake: wake up to this many tasks 194 * @nr_requeue: requeue up to this many tasks 195 */ 196 static inline int 197 futex_cmp_requeue(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake, 198 int nr_requeue, int opflags) 199 { 200 return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2, 201 val, opflags); 202 } 203 204 /** 205 * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2 206 * @uaddr: non-PI futex source 207 * @uaddr2: PI futex target 208 * 209 * This is the first half of the requeue_pi mechanism. It shall always be 210 * paired with futex_cmp_requeue_pi(). 211 */ 212 static inline int 213 futex_wait_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, 214 struct timespec *timeout, int opflags) 215 { 216 return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0, 217 opflags); 218 } 219 220 /** 221 * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware) 222 * @uaddr: non-PI futex source 223 * @uaddr2: PI futex target 224 * @nr_wake: wake up to this many tasks 225 * @nr_requeue: requeue up to this many tasks 226 */ 227 static inline int 228 futex_cmp_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake, 229 int nr_requeue, int opflags) 230 { 231 return futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2, 232 val, opflags); 233 } 234 235 /** 236 * futex_cmpxchg() - atomic compare and exchange 237 * @uaddr: The address of the futex to be modified 238 * @oldval: The expected value of the futex 239 * @newval: The new value to try and assign the futex 240 * 241 * Implement cmpxchg using gcc atomic builtins. 242 * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html 243 * 244 * Return the old futex value. 245 */ 246 static inline u_int32_t 247 futex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval) 248 { 249 return __sync_val_compare_and_swap(uaddr, oldval, newval); 250 } 251 252 /** 253 * futex_dec() - atomic decrement of the futex value 254 * @uaddr: The address of the futex to be modified 255 * 256 * Return the new futex value. 257 */ 258 static inline u_int32_t 259 futex_dec(futex_t *uaddr) 260 { 261 return __sync_sub_and_fetch(uaddr, 1); 262 } 263 264 /** 265 * futex_inc() - atomic increment of the futex value 266 * @uaddr: the address of the futex to be modified 267 * 268 * Return the new futex value. 269 */ 270 static inline u_int32_t 271 futex_inc(futex_t *uaddr) 272 { 273 return __sync_add_and_fetch(uaddr, 1); 274 } 275 276 /** 277 * futex_set() - atomic decrement of the futex value 278 * @uaddr: the address of the futex to be modified 279 * @newval: New value for the atomic_t 280 * 281 * Return the new futex value. 282 */ 283 static inline u_int32_t 284 futex_set(futex_t *uaddr, u_int32_t newval) 285 { 286 *uaddr = newval; 287 return newval; 288 } 289 290 #endif 291