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