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