18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/******************************************************************************
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *   Copyright © International Business Machines  Corp., 2009
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * DESCRIPTION
78c2ecf20Sopenharmony_ci *      Glibc independent futex library for testing kernel functionality.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * AUTHOR
108c2ecf20Sopenharmony_ci *      Darren Hart <dvhart@linux.intel.com>
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * HISTORY
138c2ecf20Sopenharmony_ci *      2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *****************************************************************************/
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#ifndef _FUTEXTEST_H
188c2ecf20Sopenharmony_ci#define _FUTEXTEST_H
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <unistd.h>
218c2ecf20Sopenharmony_ci#include <sys/syscall.h>
228c2ecf20Sopenharmony_ci#include <sys/types.h>
238c2ecf20Sopenharmony_ci#include <linux/futex.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_citypedef volatile u_int32_t futex_t;
268c2ecf20Sopenharmony_ci#define FUTEX_INITIALIZER 0
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Define the newer op codes if the system header file is not up to date. */
298c2ecf20Sopenharmony_ci#ifndef FUTEX_WAIT_BITSET
308c2ecf20Sopenharmony_ci#define FUTEX_WAIT_BITSET		9
318c2ecf20Sopenharmony_ci#endif
328c2ecf20Sopenharmony_ci#ifndef FUTEX_WAKE_BITSET
338c2ecf20Sopenharmony_ci#define FUTEX_WAKE_BITSET		10
348c2ecf20Sopenharmony_ci#endif
358c2ecf20Sopenharmony_ci#ifndef FUTEX_WAIT_REQUEUE_PI
368c2ecf20Sopenharmony_ci#define FUTEX_WAIT_REQUEUE_PI		11
378c2ecf20Sopenharmony_ci#endif
388c2ecf20Sopenharmony_ci#ifndef FUTEX_CMP_REQUEUE_PI
398c2ecf20Sopenharmony_ci#define FUTEX_CMP_REQUEUE_PI		12
408c2ecf20Sopenharmony_ci#endif
418c2ecf20Sopenharmony_ci#ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE
428c2ecf20Sopenharmony_ci#define FUTEX_WAIT_REQUEUE_PI_PRIVATE	(FUTEX_WAIT_REQUEUE_PI | \
438c2ecf20Sopenharmony_ci					 FUTEX_PRIVATE_FLAG)
448c2ecf20Sopenharmony_ci#endif
458c2ecf20Sopenharmony_ci#ifndef FUTEX_REQUEUE_PI_PRIVATE
468c2ecf20Sopenharmony_ci#define FUTEX_CMP_REQUEUE_PI_PRIVATE	(FUTEX_CMP_REQUEUE_PI | \
478c2ecf20Sopenharmony_ci					 FUTEX_PRIVATE_FLAG)
488c2ecf20Sopenharmony_ci#endif
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/**
518c2ecf20Sopenharmony_ci * futex() - SYS_futex syscall wrapper
528c2ecf20Sopenharmony_ci * @uaddr:	address of first futex
538c2ecf20Sopenharmony_ci * @op:		futex op code
548c2ecf20Sopenharmony_ci * @val:	typically expected value of uaddr, but varies by op
558c2ecf20Sopenharmony_ci * @timeout:	typically an absolute struct timespec (except where noted
568c2ecf20Sopenharmony_ci *              otherwise). Overloaded by some ops
578c2ecf20Sopenharmony_ci * @uaddr2:	address of second futex for some ops\
588c2ecf20Sopenharmony_ci * @val3:	varies by op
598c2ecf20Sopenharmony_ci * @opflags:	flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * futex() is used by all the following futex op wrappers. It can also be
628c2ecf20Sopenharmony_ci * used for misuse and abuse testing. Generally, the specific op wrappers
638c2ecf20Sopenharmony_ci * should be used instead. It is a macro instead of an static inline function as
648c2ecf20Sopenharmony_ci * some of the types over overloaded (timeout is used for nr_requeue for
658c2ecf20Sopenharmony_ci * example).
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci * These argument descriptions are the defaults for all
688c2ecf20Sopenharmony_ci * like-named arguments in the following wrappers except where noted below.
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_ci#define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \
718c2ecf20Sopenharmony_ci	syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3)
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/**
748c2ecf20Sopenharmony_ci * futex_wait() - block on uaddr with optional timeout
758c2ecf20Sopenharmony_ci * @timeout:	relative timeout
768c2ecf20Sopenharmony_ci */
778c2ecf20Sopenharmony_cistatic inline int
788c2ecf20Sopenharmony_cifutex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/**
848c2ecf20Sopenharmony_ci * futex_wake() - wake one or more tasks blocked on uaddr
858c2ecf20Sopenharmony_ci * @nr_wake:	wake up to this many tasks
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_cistatic inline int
888c2ecf20Sopenharmony_cifutex_wake(futex_t *uaddr, int nr_wake, int opflags)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/**
948c2ecf20Sopenharmony_ci * futex_wait_bitset() - block on uaddr with bitset
958c2ecf20Sopenharmony_ci * @bitset:	bitset to be used with futex_wake_bitset
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_cistatic inline int
988c2ecf20Sopenharmony_cifutex_wait_bitset(futex_t *uaddr, futex_t val, struct timespec *timeout,
998c2ecf20Sopenharmony_ci		  u_int32_t bitset, int opflags)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset,
1028c2ecf20Sopenharmony_ci		     opflags);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/**
1068c2ecf20Sopenharmony_ci * futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset
1078c2ecf20Sopenharmony_ci * @bitset:	bitset to compare with that used in futex_wait_bitset
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_cistatic inline int
1108c2ecf20Sopenharmony_cifutex_wake_bitset(futex_t *uaddr, int nr_wake, u_int32_t bitset, int opflags)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_WAKE_BITSET, nr_wake, NULL, NULL, bitset,
1138c2ecf20Sopenharmony_ci		     opflags);
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci/**
1178c2ecf20Sopenharmony_ci * futex_lock_pi() - block on uaddr as a PI mutex
1188c2ecf20Sopenharmony_ci * @detect:	whether (1) or not (0) to perform deadlock detection
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_cistatic inline int
1218c2ecf20Sopenharmony_cifutex_lock_pi(futex_t *uaddr, struct timespec *timeout, int detect,
1228c2ecf20Sopenharmony_ci	      int opflags)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/**
1288c2ecf20Sopenharmony_ci * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter
1298c2ecf20Sopenharmony_ci */
1308c2ecf20Sopenharmony_cistatic inline int
1318c2ecf20Sopenharmony_cifutex_unlock_pi(futex_t *uaddr, int opflags)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/**
1378c2ecf20Sopenharmony_ci * futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION
1388c2ecf20Sopenharmony_ci */
1398c2ecf20Sopenharmony_cistatic inline int
1408c2ecf20Sopenharmony_cifutex_wake_op(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_wake2,
1418c2ecf20Sopenharmony_ci	      int wake_op, int opflags)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op,
1448c2ecf20Sopenharmony_ci		     opflags);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci/**
1488c2ecf20Sopenharmony_ci * futex_requeue() - requeue without expected value comparison, deprecated
1498c2ecf20Sopenharmony_ci * @nr_wake:	wake up to this many tasks
1508c2ecf20Sopenharmony_ci * @nr_requeue:	requeue up to this many tasks
1518c2ecf20Sopenharmony_ci *
1528c2ecf20Sopenharmony_ci * Due to its inherently racy implementation, futex_requeue() is deprecated in
1538c2ecf20Sopenharmony_ci * favor of futex_cmp_requeue().
1548c2ecf20Sopenharmony_ci */
1558c2ecf20Sopenharmony_cistatic inline int
1568c2ecf20Sopenharmony_cifutex_requeue(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_requeue,
1578c2ecf20Sopenharmony_ci	      int opflags)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0,
1608c2ecf20Sopenharmony_ci		     opflags);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/**
1648c2ecf20Sopenharmony_ci * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
1658c2ecf20Sopenharmony_ci * @nr_wake:	wake up to this many tasks
1668c2ecf20Sopenharmony_ci * @nr_requeue:	requeue up to this many tasks
1678c2ecf20Sopenharmony_ci */
1688c2ecf20Sopenharmony_cistatic inline int
1698c2ecf20Sopenharmony_cifutex_cmp_requeue(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
1708c2ecf20Sopenharmony_ci		  int nr_requeue, int opflags)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
1738c2ecf20Sopenharmony_ci		     val, opflags);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/**
1778c2ecf20Sopenharmony_ci * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2
1788c2ecf20Sopenharmony_ci * @uaddr:	non-PI futex source
1798c2ecf20Sopenharmony_ci * @uaddr2:	PI futex target
1808c2ecf20Sopenharmony_ci *
1818c2ecf20Sopenharmony_ci * This is the first half of the requeue_pi mechanism. It shall always be
1828c2ecf20Sopenharmony_ci * paired with futex_cmp_requeue_pi().
1838c2ecf20Sopenharmony_ci */
1848c2ecf20Sopenharmony_cistatic inline int
1858c2ecf20Sopenharmony_cifutex_wait_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2,
1868c2ecf20Sopenharmony_ci		      struct timespec *timeout, int opflags)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0,
1898c2ecf20Sopenharmony_ci		     opflags);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/**
1938c2ecf20Sopenharmony_ci * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware)
1948c2ecf20Sopenharmony_ci * @uaddr:	non-PI futex source
1958c2ecf20Sopenharmony_ci * @uaddr2:	PI futex target
1968c2ecf20Sopenharmony_ci * @nr_wake:	wake up to this many tasks
1978c2ecf20Sopenharmony_ci * @nr_requeue:	requeue up to this many tasks
1988c2ecf20Sopenharmony_ci */
1998c2ecf20Sopenharmony_cistatic inline int
2008c2ecf20Sopenharmony_cifutex_cmp_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
2018c2ecf20Sopenharmony_ci		     int nr_requeue, int opflags)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	return futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2,
2048c2ecf20Sopenharmony_ci		     val, opflags);
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/**
2088c2ecf20Sopenharmony_ci * futex_cmpxchg() - atomic compare and exchange
2098c2ecf20Sopenharmony_ci * @uaddr:	The address of the futex to be modified
2108c2ecf20Sopenharmony_ci * @oldval:	The expected value of the futex
2118c2ecf20Sopenharmony_ci * @newval:	The new value to try and assign the futex
2128c2ecf20Sopenharmony_ci *
2138c2ecf20Sopenharmony_ci * Implement cmpxchg using gcc atomic builtins.
2148c2ecf20Sopenharmony_ci * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
2158c2ecf20Sopenharmony_ci *
2168c2ecf20Sopenharmony_ci * Return the old futex value.
2178c2ecf20Sopenharmony_ci */
2188c2ecf20Sopenharmony_cistatic inline u_int32_t
2198c2ecf20Sopenharmony_cifutex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	return __sync_val_compare_and_swap(uaddr, oldval, newval);
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/**
2258c2ecf20Sopenharmony_ci * futex_dec() - atomic decrement of the futex value
2268c2ecf20Sopenharmony_ci * @uaddr:	The address of the futex to be modified
2278c2ecf20Sopenharmony_ci *
2288c2ecf20Sopenharmony_ci * Return the new futex value.
2298c2ecf20Sopenharmony_ci */
2308c2ecf20Sopenharmony_cistatic inline u_int32_t
2318c2ecf20Sopenharmony_cifutex_dec(futex_t *uaddr)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	return __sync_sub_and_fetch(uaddr, 1);
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci/**
2378c2ecf20Sopenharmony_ci * futex_inc() - atomic increment of the futex value
2388c2ecf20Sopenharmony_ci * @uaddr:	the address of the futex to be modified
2398c2ecf20Sopenharmony_ci *
2408c2ecf20Sopenharmony_ci * Return the new futex value.
2418c2ecf20Sopenharmony_ci */
2428c2ecf20Sopenharmony_cistatic inline u_int32_t
2438c2ecf20Sopenharmony_cifutex_inc(futex_t *uaddr)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	return __sync_add_and_fetch(uaddr, 1);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/**
2498c2ecf20Sopenharmony_ci * futex_set() - atomic decrement of the futex value
2508c2ecf20Sopenharmony_ci * @uaddr:	the address of the futex to be modified
2518c2ecf20Sopenharmony_ci * @newval:	New value for the atomic_t
2528c2ecf20Sopenharmony_ci *
2538c2ecf20Sopenharmony_ci * Return the new futex value.
2548c2ecf20Sopenharmony_ci */
2558c2ecf20Sopenharmony_cistatic inline u_int32_t
2568c2ecf20Sopenharmony_cifutex_set(futex_t *uaddr, u_int32_t newval)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	*uaddr = newval;
2598c2ecf20Sopenharmony_ci	return newval;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci#endif
263