162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Glibc independent futex library for testing kernel functionality.
462306a36Sopenharmony_ci * Shamelessly stolen from Darren Hart <dvhltc@us.ibm.com>
562306a36Sopenharmony_ci *    http://git.kernel.org/cgit/linux/kernel/git/dvhart/futextest.git/
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef _FUTEX_H
962306a36Sopenharmony_ci#define _FUTEX_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <unistd.h>
1262306a36Sopenharmony_ci#include <sys/syscall.h>
1362306a36Sopenharmony_ci#include <sys/types.h>
1462306a36Sopenharmony_ci#include <linux/futex.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct bench_futex_parameters {
1762306a36Sopenharmony_ci	bool silent;
1862306a36Sopenharmony_ci	bool fshared;
1962306a36Sopenharmony_ci	bool mlockall;
2062306a36Sopenharmony_ci	bool multi; /* lock-pi */
2162306a36Sopenharmony_ci	bool pi; /* requeue-pi */
2262306a36Sopenharmony_ci	bool broadcast; /* requeue */
2362306a36Sopenharmony_ci	unsigned int runtime; /* seconds*/
2462306a36Sopenharmony_ci	unsigned int nthreads;
2562306a36Sopenharmony_ci	unsigned int nfutexes;
2662306a36Sopenharmony_ci	unsigned int nwakes;
2762306a36Sopenharmony_ci	unsigned int nrequeue;
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/**
3162306a36Sopenharmony_ci * futex_syscall() - SYS_futex syscall wrapper
3262306a36Sopenharmony_ci * @uaddr:	address of first futex
3362306a36Sopenharmony_ci * @op:		futex op code
3462306a36Sopenharmony_ci * @val:	typically expected value of uaddr, but varies by op
3562306a36Sopenharmony_ci * @timeout:	typically an absolute struct timespec (except where noted
3662306a36Sopenharmony_ci *		otherwise). Overloaded by some ops
3762306a36Sopenharmony_ci * @uaddr2:	address of second futex for some ops
3862306a36Sopenharmony_ci * @val3:	varies by op
3962306a36Sopenharmony_ci * @opflags:	flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * futex_syscall() is used by all the following futex op wrappers. It can also be
4262306a36Sopenharmony_ci * used for misuse and abuse testing. Generally, the specific op wrappers
4362306a36Sopenharmony_ci * should be used instead.
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * These argument descriptions are the defaults for all
4662306a36Sopenharmony_ci * like-named arguments in the following wrappers except where noted below.
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_cistatic inline int
4962306a36Sopenharmony_cifutex_syscall(volatile u_int32_t *uaddr, int op, u_int32_t val, struct timespec *timeout,
5062306a36Sopenharmony_ci	      volatile u_int32_t *uaddr2, int val3, int opflags)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	return syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline int
5662306a36Sopenharmony_cifutex_syscall_nr_requeue(volatile u_int32_t *uaddr, int op, u_int32_t val, int nr_requeue,
5762306a36Sopenharmony_ci			 volatile u_int32_t *uaddr2, int val3, int opflags)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	return syscall(SYS_futex, uaddr, op | opflags, val, nr_requeue, uaddr2, val3);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/**
6362306a36Sopenharmony_ci * futex_wait() - block on uaddr with optional timeout
6462306a36Sopenharmony_ci * @timeout:	relative timeout
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_cistatic inline int
6762306a36Sopenharmony_cifutex_wait(u_int32_t *uaddr, u_int32_t val, struct timespec *timeout, int opflags)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	return futex_syscall(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/**
7362306a36Sopenharmony_ci * futex_wake() - wake one or more tasks blocked on uaddr
7462306a36Sopenharmony_ci * @nr_wake:	wake up to this many tasks
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_cistatic inline int
7762306a36Sopenharmony_cifutex_wake(u_int32_t *uaddr, int nr_wake, int opflags)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	return futex_syscall(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/**
8362306a36Sopenharmony_ci * futex_lock_pi() - block on uaddr as a PI mutex
8462306a36Sopenharmony_ci */
8562306a36Sopenharmony_cistatic inline int
8662306a36Sopenharmony_cifutex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int opflags)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	return futex_syscall(uaddr, FUTEX_LOCK_PI, 0, timeout, NULL, 0, opflags);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/**
9262306a36Sopenharmony_ci * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cistatic inline int
9562306a36Sopenharmony_cifutex_unlock_pi(u_int32_t *uaddr, int opflags)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	return futex_syscall(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/**
10162306a36Sopenharmony_ci* futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
10262306a36Sopenharmony_ci* @nr_wake:        wake up to this many tasks
10362306a36Sopenharmony_ci* @nr_requeue:     requeue up to this many tasks
10462306a36Sopenharmony_ci*/
10562306a36Sopenharmony_cistatic inline int
10662306a36Sopenharmony_cifutex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wake,
10762306a36Sopenharmony_ci		 int nr_requeue, int opflags)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	return futex_syscall_nr_requeue(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
11062306a36Sopenharmony_ci					val, opflags);
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/**
11462306a36Sopenharmony_ci * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2
11562306a36Sopenharmony_ci * @uaddr:	non-PI futex source
11662306a36Sopenharmony_ci * @uaddr2:	PI futex target
11762306a36Sopenharmony_ci *
11862306a36Sopenharmony_ci * This is the first half of the requeue_pi mechanism. It shall always be
11962306a36Sopenharmony_ci * paired with futex_cmp_requeue_pi().
12062306a36Sopenharmony_ci */
12162306a36Sopenharmony_cistatic inline int
12262306a36Sopenharmony_cifutex_wait_requeue_pi(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2,
12362306a36Sopenharmony_ci		      struct timespec *timeout, int opflags)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	return futex_syscall(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0,
12662306a36Sopenharmony_ci			     opflags);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/**
13062306a36Sopenharmony_ci * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2
13162306a36Sopenharmony_ci * @uaddr:	non-PI futex source
13262306a36Sopenharmony_ci * @uaddr2:	PI futex target
13362306a36Sopenharmony_ci * @nr_requeue:	requeue up to this many tasks
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * This is the second half of the requeue_pi mechanism. It shall always be
13662306a36Sopenharmony_ci * paired with futex_wait_requeue_pi(). The first waker is always awoken.
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_cistatic inline int
13962306a36Sopenharmony_cifutex_cmp_requeue_pi(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2,
14062306a36Sopenharmony_ci		     int nr_requeue, int opflags)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	return futex_syscall_nr_requeue(uaddr, FUTEX_CMP_REQUEUE_PI, 1, nr_requeue, uaddr2,
14362306a36Sopenharmony_ci					val, opflags);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#endif /* _FUTEX_H */
147