summaryrefslogtreecommitdiff
path: root/tools/perf/bench/futex.h
blob: ebdc2b032afc16432b9415985ffb433f2ff55bd3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Glibc independent futex library for testing kernel functionality.
 * Shamelessly stolen from Darren Hart <dvhltc@us.ibm.com>
 *    http://git.kernel.org/cgit/linux/kernel/git/dvhart/futextest.git/
 */

#ifndef _FUTEX_H
#define _FUTEX_H

#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/futex.h>

struct bench_futex_parameters {
	bool silent;
	bool fshared;
	bool mlockall;
	bool multi; /* lock-pi */
	bool pi; /* requeue-pi */
	bool broadcast; /* requeue */
	unsigned int runtime; /* seconds*/
	unsigned int nthreads;
	unsigned int nfutexes;
	unsigned int nwakes;
	unsigned int nrequeue;
};

/**
 * futex_syscall() - SYS_futex syscall wrapper
 * @uaddr:	address of first futex
 * @op:		futex op code
 * @val:	typically expected value of uaddr, but varies by op
 * @timeout:	typically an absolute struct timespec (except where noted
 *		otherwise). Overloaded by some ops
 * @uaddr2:	address of second futex for some ops
 * @val3:	varies by op
 * @opflags:	flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
 *
 * futex_syscall() is used by all the following futex op wrappers. It can also be
 * used for misuse and abuse testing. Generally, the specific op wrappers
 * should be used instead.
 *
 * These argument descriptions are the defaults for all
 * like-named arguments in the following wrappers except where noted below.
 */
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)
{
	return syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3);
}

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)
{
	return syscall(SYS_futex, uaddr, op | opflags, val, nr_requeue, uaddr2, val3);
}

/**
 * futex_wait() - block on uaddr with optional timeout
 * @timeout:	relative timeout
 */
static inline int
futex_wait(u_int32_t *uaddr, u_int32_t val, struct timespec *timeout, int opflags)
{
	return futex_syscall(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
}

/**
 * futex_wake() - wake one or more tasks blocked on uaddr
 * @nr_wake:	wake up to this many tasks
 */
static inline int
futex_wake(u_int32_t *uaddr, int nr_wake, int opflags)
{
	return futex_syscall(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
}

/**
 * futex_lock_pi() - block on uaddr as a PI mutex
 */
static inline int
futex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int opflags)
{
	return futex_syscall(uaddr, FUTEX_LOCK_PI, 0, timeout, NULL, 0, opflags);
}

/**
 * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter
 */
static inline int
futex_unlock_pi(u_int32_t *uaddr, int opflags)
{
	return futex_syscall(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags);
}

/**
* futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
* @nr_wake:        wake up to this many tasks
* @nr_requeue:     requeue up to this many tasks
*/
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)
{
	return futex_syscall_nr_requeue(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
					val, opflags);
}

/**
 * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2
 * @uaddr:	non-PI futex source
 * @uaddr2:	PI futex target
 *
 * This is the first half of the requeue_pi mechanism. It shall always be
 * paired with futex_cmp_requeue_pi().
 */
static inline int
futex_wait_requeue_pi(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2,
		      struct timespec *timeout, int opflags)
{
	return futex_syscall(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0,
			     opflags);
}

/**
 * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2
 * @uaddr:	non-PI futex source
 * @uaddr2:	PI futex target
 * @nr_requeue:	requeue up to this many tasks
 *
 * This is the second half of the requeue_pi mechanism. It shall always be
 * paired with futex_wait_requeue_pi(). The first waker is always awoken.
 */
static inline int
futex_cmp_requeue_pi(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2,
		     int nr_requeue, int opflags)
{
	return futex_syscall_nr_requeue(uaddr, FUTEX_CMP_REQUEUE_PI, 1, nr_requeue, uaddr2,
					val, opflags);
}

#endif /* _FUTEX_H */