xref: /openbmc/linux/tools/perf/bench/futex.h (revision ba4026b0)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2a0439711SDavidlohr Bueso /*
3a0439711SDavidlohr Bueso  * Glibc independent futex library for testing kernel functionality.
4a0439711SDavidlohr Bueso  * Shamelessly stolen from Darren Hart <dvhltc@us.ibm.com>
5a0439711SDavidlohr Bueso  *    http://git.kernel.org/cgit/linux/kernel/git/dvhart/futextest.git/
6a0439711SDavidlohr Bueso  */
7a0439711SDavidlohr Bueso 
8a0439711SDavidlohr Bueso #ifndef _FUTEX_H
9a0439711SDavidlohr Bueso #define _FUTEX_H
10a0439711SDavidlohr Bueso 
11a0439711SDavidlohr Bueso #include <unistd.h>
12a0439711SDavidlohr Bueso #include <sys/syscall.h>
13a0439711SDavidlohr Bueso #include <sys/types.h>
14a0439711SDavidlohr Bueso #include <linux/futex.h>
15a0439711SDavidlohr Bueso 
1609590463SDavidlohr Bueso struct bench_futex_parameters {
1709590463SDavidlohr Bueso 	bool silent;
1809590463SDavidlohr Bueso 	bool fshared;
199f9a3ffeSDavidlohr Bueso 	bool mlockall;
2009590463SDavidlohr Bueso 	bool multi; /* lock-pi */
2146f81532SDavidlohr Bueso 	bool pi; /* requeue-pi */
22d262e6a9SDavidlohr Bueso 	bool broadcast; /* requeue */
2309590463SDavidlohr Bueso 	unsigned int runtime; /* seconds*/
2409590463SDavidlohr Bueso 	unsigned int nthreads;
2509590463SDavidlohr Bueso 	unsigned int nfutexes;
2609590463SDavidlohr Bueso 	unsigned int nwakes;
2709590463SDavidlohr Bueso 	unsigned int nrequeue;
2809590463SDavidlohr Bueso };
2909590463SDavidlohr Bueso 
30a0439711SDavidlohr Bueso /**
31*ba4026b0SArnaldo Carvalho de Melo  * futex_syscall() - SYS_futex syscall wrapper
32a0439711SDavidlohr Bueso  * @uaddr:	address of first futex
33a0439711SDavidlohr Bueso  * @op:		futex op code
34a0439711SDavidlohr Bueso  * @val:	typically expected value of uaddr, but varies by op
35a0439711SDavidlohr Bueso  * @timeout:	typically an absolute struct timespec (except where noted
36a0439711SDavidlohr Bueso  *		otherwise). Overloaded by some ops
37b2105a75SDavidlohr Bueso  * @uaddr2:	address of second futex for some ops
38a0439711SDavidlohr Bueso  * @val3:	varies by op
39a0439711SDavidlohr Bueso  * @opflags:	flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
40a0439711SDavidlohr Bueso  *
41fec5c3a5SAlistair Francis  * futex_syscall() is used by all the following futex op wrappers. It can also be
42a0439711SDavidlohr Bueso  * used for misuse and abuse testing. Generally, the specific op wrappers
43fec5c3a5SAlistair Francis  * should be used instead.
44a0439711SDavidlohr Bueso  *
45a0439711SDavidlohr Bueso  * These argument descriptions are the defaults for all
46a0439711SDavidlohr Bueso  * like-named arguments in the following wrappers except where noted below.
47a0439711SDavidlohr Bueso  */
48fec5c3a5SAlistair Francis static inline int
futex_syscall(volatile u_int32_t * uaddr,int op,u_int32_t val,struct timespec * timeout,volatile u_int32_t * uaddr2,int val3,int opflags)49fec5c3a5SAlistair Francis futex_syscall(volatile u_int32_t *uaddr, int op, u_int32_t val, struct timespec *timeout,
50fec5c3a5SAlistair Francis 	      volatile u_int32_t *uaddr2, int val3, int opflags)
51fec5c3a5SAlistair Francis {
52*ba4026b0SArnaldo Carvalho de Melo 	return syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3);
53fec5c3a5SAlistair Francis }
54fec5c3a5SAlistair Francis 
55fec5c3a5SAlistair Francis static inline int
futex_syscall_nr_requeue(volatile u_int32_t * uaddr,int op,u_int32_t val,int nr_requeue,volatile u_int32_t * uaddr2,int val3,int opflags)56fec5c3a5SAlistair Francis futex_syscall_nr_requeue(volatile u_int32_t *uaddr, int op, u_int32_t val, int nr_requeue,
57fec5c3a5SAlistair Francis 			 volatile u_int32_t *uaddr2, int val3, int opflags)
58fec5c3a5SAlistair Francis {
59*ba4026b0SArnaldo Carvalho de Melo 	return syscall(SYS_futex, uaddr, op | opflags, val, nr_requeue, uaddr2, val3);
60fec5c3a5SAlistair Francis }
61a0439711SDavidlohr Bueso 
62a0439711SDavidlohr Bueso /**
63a0439711SDavidlohr Bueso  * futex_wait() - block on uaddr with optional timeout
64a0439711SDavidlohr Bueso  * @timeout:	relative timeout
65a0439711SDavidlohr Bueso  */
66a0439711SDavidlohr Bueso static inline int
futex_wait(u_int32_t * uaddr,u_int32_t val,struct timespec * timeout,int opflags)67a0439711SDavidlohr Bueso futex_wait(u_int32_t *uaddr, u_int32_t val, struct timespec *timeout, int opflags)
68a0439711SDavidlohr Bueso {
69fec5c3a5SAlistair Francis 	return futex_syscall(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
70a0439711SDavidlohr Bueso }
71a0439711SDavidlohr Bueso 
7227db7830SDavidlohr Bueso /**
7327db7830SDavidlohr Bueso  * futex_wake() - wake one or more tasks blocked on uaddr
7427db7830SDavidlohr Bueso  * @nr_wake:	wake up to this many tasks
7527db7830SDavidlohr Bueso  */
7627db7830SDavidlohr Bueso static inline int
futex_wake(u_int32_t * uaddr,int nr_wake,int opflags)7727db7830SDavidlohr Bueso futex_wake(u_int32_t *uaddr, int nr_wake, int opflags)
7827db7830SDavidlohr Bueso {
79fec5c3a5SAlistair Francis 	return futex_syscall(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
8027db7830SDavidlohr Bueso }
8127db7830SDavidlohr Bueso 
820fb298cfSDavidlohr Bueso /**
83d2f3f5d2SDavidlohr Bueso  * futex_lock_pi() - block on uaddr as a PI mutex
84d2f3f5d2SDavidlohr Bueso  */
85d2f3f5d2SDavidlohr Bueso static inline int
futex_lock_pi(u_int32_t * uaddr,struct timespec * timeout,int opflags)8673b1794eSDavidlohr Bueso futex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int opflags)
87d2f3f5d2SDavidlohr Bueso {
88fec5c3a5SAlistair Francis 	return futex_syscall(uaddr, FUTEX_LOCK_PI, 0, timeout, NULL, 0, opflags);
89d2f3f5d2SDavidlohr Bueso }
90d2f3f5d2SDavidlohr Bueso 
91d2f3f5d2SDavidlohr Bueso /**
92d2f3f5d2SDavidlohr Bueso  * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter
93d2f3f5d2SDavidlohr Bueso  */
94d2f3f5d2SDavidlohr Bueso static inline int
futex_unlock_pi(u_int32_t * uaddr,int opflags)95d2f3f5d2SDavidlohr Bueso futex_unlock_pi(u_int32_t *uaddr, int opflags)
96d2f3f5d2SDavidlohr Bueso {
97fec5c3a5SAlistair Francis 	return futex_syscall(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags);
98d2f3f5d2SDavidlohr Bueso }
99d2f3f5d2SDavidlohr Bueso 
100d2f3f5d2SDavidlohr Bueso /**
1010fb298cfSDavidlohr Bueso * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
1020fb298cfSDavidlohr Bueso * @nr_wake:        wake up to this many tasks
1030fb298cfSDavidlohr Bueso * @nr_requeue:     requeue up to this many tasks
1040fb298cfSDavidlohr Bueso */
1050fb298cfSDavidlohr Bueso static inline int
futex_cmp_requeue(u_int32_t * uaddr,u_int32_t val,u_int32_t * uaddr2,int nr_wake,int nr_requeue,int opflags)1060fb298cfSDavidlohr Bueso futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wake,
1070fb298cfSDavidlohr Bueso 		 int nr_requeue, int opflags)
1080fb298cfSDavidlohr Bueso {
109fec5c3a5SAlistair Francis 	return futex_syscall_nr_requeue(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
1100fb298cfSDavidlohr Bueso 					val, opflags);
1110fb298cfSDavidlohr Bueso }
11246f81532SDavidlohr Bueso 
11346f81532SDavidlohr Bueso /**
11446f81532SDavidlohr Bueso  * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2
11546f81532SDavidlohr Bueso  * @uaddr:	non-PI futex source
11646f81532SDavidlohr Bueso  * @uaddr2:	PI futex target
11746f81532SDavidlohr Bueso  *
11846f81532SDavidlohr Bueso  * This is the first half of the requeue_pi mechanism. It shall always be
11946f81532SDavidlohr Bueso  * paired with futex_cmp_requeue_pi().
12046f81532SDavidlohr Bueso  */
12146f81532SDavidlohr Bueso static inline int
futex_wait_requeue_pi(u_int32_t * uaddr,u_int32_t val,u_int32_t * uaddr2,struct timespec * timeout,int opflags)12246f81532SDavidlohr Bueso futex_wait_requeue_pi(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2,
12346f81532SDavidlohr Bueso 		      struct timespec *timeout, int opflags)
12446f81532SDavidlohr Bueso {
125fec5c3a5SAlistair Francis 	return futex_syscall(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0,
12646f81532SDavidlohr Bueso 			     opflags);
12746f81532SDavidlohr Bueso }
12846f81532SDavidlohr Bueso 
12946f81532SDavidlohr Bueso /**
13046f81532SDavidlohr Bueso  * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2
13146f81532SDavidlohr Bueso  * @uaddr:	non-PI futex source
13246f81532SDavidlohr Bueso  * @uaddr2:	PI futex target
13346f81532SDavidlohr Bueso  * @nr_requeue:	requeue up to this many tasks
13446f81532SDavidlohr Bueso  *
13546f81532SDavidlohr Bueso  * This is the second half of the requeue_pi mechanism. It shall always be
13646f81532SDavidlohr Bueso  * paired with futex_wait_requeue_pi(). The first waker is always awoken.
13746f81532SDavidlohr Bueso  */
13846f81532SDavidlohr Bueso static inline int
futex_cmp_requeue_pi(u_int32_t * uaddr,u_int32_t val,u_int32_t * uaddr2,int nr_requeue,int opflags)13946f81532SDavidlohr Bueso futex_cmp_requeue_pi(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2,
14046f81532SDavidlohr Bueso 		     int nr_requeue, int opflags)
14146f81532SDavidlohr Bueso {
142fec5c3a5SAlistair Francis 	return futex_syscall_nr_requeue(uaddr, FUTEX_CMP_REQUEUE_PI, 1, nr_requeue, uaddr2,
14346f81532SDavidlohr Bueso 					val, opflags);
14446f81532SDavidlohr Bueso }
14546f81532SDavidlohr Bueso 
146a0439711SDavidlohr Bueso #endif /* _FUTEX_H */
147