162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © International Business Machines Corp., 2009 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * DESCRIPTION 762306a36Sopenharmony_ci * Glibc independent futex library for testing kernel functionality. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * AUTHOR 1062306a36Sopenharmony_ci * Darren Hart <dvhart@linux.intel.com> 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * HISTORY 1362306a36Sopenharmony_ci * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com> 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci *****************************************************************************/ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#ifndef _FUTEXTEST_H 1862306a36Sopenharmony_ci#define _FUTEXTEST_H 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <unistd.h> 2162306a36Sopenharmony_ci#include <sys/syscall.h> 2262306a36Sopenharmony_ci#include <sys/types.h> 2362306a36Sopenharmony_ci#include <linux/futex.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_citypedef volatile u_int32_t futex_t; 2662306a36Sopenharmony_ci#define FUTEX_INITIALIZER 0 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* Define the newer op codes if the system header file is not up to date. */ 2962306a36Sopenharmony_ci#ifndef FUTEX_WAIT_BITSET 3062306a36Sopenharmony_ci#define FUTEX_WAIT_BITSET 9 3162306a36Sopenharmony_ci#endif 3262306a36Sopenharmony_ci#ifndef FUTEX_WAKE_BITSET 3362306a36Sopenharmony_ci#define FUTEX_WAKE_BITSET 10 3462306a36Sopenharmony_ci#endif 3562306a36Sopenharmony_ci#ifndef FUTEX_WAIT_REQUEUE_PI 3662306a36Sopenharmony_ci#define FUTEX_WAIT_REQUEUE_PI 11 3762306a36Sopenharmony_ci#endif 3862306a36Sopenharmony_ci#ifndef FUTEX_CMP_REQUEUE_PI 3962306a36Sopenharmony_ci#define FUTEX_CMP_REQUEUE_PI 12 4062306a36Sopenharmony_ci#endif 4162306a36Sopenharmony_ci#ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE 4262306a36Sopenharmony_ci#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \ 4362306a36Sopenharmony_ci FUTEX_PRIVATE_FLAG) 4462306a36Sopenharmony_ci#endif 4562306a36Sopenharmony_ci#ifndef FUTEX_REQUEUE_PI_PRIVATE 4662306a36Sopenharmony_ci#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ 4762306a36Sopenharmony_ci FUTEX_PRIVATE_FLAG) 4862306a36Sopenharmony_ci#endif 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/** 5162306a36Sopenharmony_ci * futex() - SYS_futex syscall wrapper 5262306a36Sopenharmony_ci * @uaddr: address of first futex 5362306a36Sopenharmony_ci * @op: futex op code 5462306a36Sopenharmony_ci * @val: typically expected value of uaddr, but varies by op 5562306a36Sopenharmony_ci * @timeout: typically an absolute struct timespec (except where noted 5662306a36Sopenharmony_ci * otherwise). Overloaded by some ops 5762306a36Sopenharmony_ci * @uaddr2: address of second futex for some ops\ 5862306a36Sopenharmony_ci * @val3: varies by op 5962306a36Sopenharmony_ci * @opflags: flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * futex() is used by all the following futex op wrappers. It can also be 6262306a36Sopenharmony_ci * used for misuse and abuse testing. Generally, the specific op wrappers 6362306a36Sopenharmony_ci * should be used instead. It is a macro instead of an static inline function as 6462306a36Sopenharmony_ci * some of the types over overloaded (timeout is used for nr_requeue for 6562306a36Sopenharmony_ci * example). 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * These argument descriptions are the defaults for all 6862306a36Sopenharmony_ci * like-named arguments in the following wrappers except where noted below. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci#define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \ 7162306a36Sopenharmony_ci syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/** 7462306a36Sopenharmony_ci * futex_wait() - block on uaddr with optional timeout 7562306a36Sopenharmony_ci * @timeout: relative timeout 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistatic inline int 7862306a36Sopenharmony_cifutex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/** 8462306a36Sopenharmony_ci * futex_wake() - wake one or more tasks blocked on uaddr 8562306a36Sopenharmony_ci * @nr_wake: wake up to this many tasks 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_cistatic inline int 8862306a36Sopenharmony_cifutex_wake(futex_t *uaddr, int nr_wake, int opflags) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/** 9462306a36Sopenharmony_ci * futex_wait_bitset() - block on uaddr with bitset 9562306a36Sopenharmony_ci * @bitset: bitset to be used with futex_wake_bitset 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_cistatic inline int 9862306a36Sopenharmony_cifutex_wait_bitset(futex_t *uaddr, futex_t val, struct timespec *timeout, 9962306a36Sopenharmony_ci u_int32_t bitset, int opflags) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset, 10262306a36Sopenharmony_ci opflags); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/** 10662306a36Sopenharmony_ci * futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset 10762306a36Sopenharmony_ci * @bitset: bitset to compare with that used in futex_wait_bitset 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistatic inline int 11062306a36Sopenharmony_cifutex_wake_bitset(futex_t *uaddr, int nr_wake, u_int32_t bitset, int opflags) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci return futex(uaddr, FUTEX_WAKE_BITSET, nr_wake, NULL, NULL, bitset, 11362306a36Sopenharmony_ci opflags); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/** 11762306a36Sopenharmony_ci * futex_lock_pi() - block on uaddr as a PI mutex 11862306a36Sopenharmony_ci * @detect: whether (1) or not (0) to perform deadlock detection 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_cistatic inline int 12162306a36Sopenharmony_cifutex_lock_pi(futex_t *uaddr, struct timespec *timeout, int detect, 12262306a36Sopenharmony_ci int opflags) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/** 12862306a36Sopenharmony_ci * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_cistatic inline int 13162306a36Sopenharmony_cifutex_unlock_pi(futex_t *uaddr, int opflags) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci return futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/** 13762306a36Sopenharmony_ci * futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_cistatic inline int 14062306a36Sopenharmony_cifutex_wake_op(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_wake2, 14162306a36Sopenharmony_ci int wake_op, int opflags) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci return futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op, 14462306a36Sopenharmony_ci opflags); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/** 14862306a36Sopenharmony_ci * futex_requeue() - requeue without expected value comparison, deprecated 14962306a36Sopenharmony_ci * @nr_wake: wake up to this many tasks 15062306a36Sopenharmony_ci * @nr_requeue: requeue up to this many tasks 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * Due to its inherently racy implementation, futex_requeue() is deprecated in 15362306a36Sopenharmony_ci * favor of futex_cmp_requeue(). 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_cistatic inline int 15662306a36Sopenharmony_cifutex_requeue(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_requeue, 15762306a36Sopenharmony_ci int opflags) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci return futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0, 16062306a36Sopenharmony_ci opflags); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/** 16462306a36Sopenharmony_ci * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2 16562306a36Sopenharmony_ci * @nr_wake: wake up to this many tasks 16662306a36Sopenharmony_ci * @nr_requeue: requeue up to this many tasks 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_cistatic inline int 16962306a36Sopenharmony_cifutex_cmp_requeue(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake, 17062306a36Sopenharmony_ci int nr_requeue, int opflags) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2, 17362306a36Sopenharmony_ci val, opflags); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/** 17762306a36Sopenharmony_ci * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2 17862306a36Sopenharmony_ci * @uaddr: non-PI futex source 17962306a36Sopenharmony_ci * @uaddr2: PI futex target 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * This is the first half of the requeue_pi mechanism. It shall always be 18262306a36Sopenharmony_ci * paired with futex_cmp_requeue_pi(). 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_cistatic inline int 18562306a36Sopenharmony_cifutex_wait_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, 18662306a36Sopenharmony_ci struct timespec *timeout, int opflags) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0, 18962306a36Sopenharmony_ci opflags); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/** 19362306a36Sopenharmony_ci * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware) 19462306a36Sopenharmony_ci * @uaddr: non-PI futex source 19562306a36Sopenharmony_ci * @uaddr2: PI futex target 19662306a36Sopenharmony_ci * @nr_wake: wake up to this many tasks 19762306a36Sopenharmony_ci * @nr_requeue: requeue up to this many tasks 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_cistatic inline int 20062306a36Sopenharmony_cifutex_cmp_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake, 20162306a36Sopenharmony_ci int nr_requeue, int opflags) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci return futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2, 20462306a36Sopenharmony_ci val, opflags); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/** 20862306a36Sopenharmony_ci * futex_cmpxchg() - atomic compare and exchange 20962306a36Sopenharmony_ci * @uaddr: The address of the futex to be modified 21062306a36Sopenharmony_ci * @oldval: The expected value of the futex 21162306a36Sopenharmony_ci * @newval: The new value to try and assign the futex 21262306a36Sopenharmony_ci * 21362306a36Sopenharmony_ci * Implement cmpxchg using gcc atomic builtins. 21462306a36Sopenharmony_ci * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * Return the old futex value. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_cistatic inline u_int32_t 21962306a36Sopenharmony_cifutex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci return __sync_val_compare_and_swap(uaddr, oldval, newval); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/** 22562306a36Sopenharmony_ci * futex_dec() - atomic decrement of the futex value 22662306a36Sopenharmony_ci * @uaddr: The address of the futex to be modified 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * Return the new futex value. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_cistatic inline u_int32_t 23162306a36Sopenharmony_cifutex_dec(futex_t *uaddr) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci return __sync_sub_and_fetch(uaddr, 1); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/** 23762306a36Sopenharmony_ci * futex_inc() - atomic increment of the futex value 23862306a36Sopenharmony_ci * @uaddr: the address of the futex to be modified 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * Return the new futex value. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_cistatic inline u_int32_t 24362306a36Sopenharmony_cifutex_inc(futex_t *uaddr) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci return __sync_add_and_fetch(uaddr, 1); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/** 24962306a36Sopenharmony_ci * futex_set() - atomic decrement of the futex value 25062306a36Sopenharmony_ci * @uaddr: the address of the futex to be modified 25162306a36Sopenharmony_ci * @newval: New value for the atomic_t 25262306a36Sopenharmony_ci * 25362306a36Sopenharmony_ci * Return the new futex value. 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_cistatic inline u_int32_t 25662306a36Sopenharmony_cifutex_set(futex_t *uaddr, u_int32_t newval) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci *uaddr = newval; 25962306a36Sopenharmony_ci return newval; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci#endif 263