Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/futex/include/futextest.h
29270 views
1
/* SPDX-License-Identifier: GPL-2.0-or-later */
2
/******************************************************************************
3
*
4
* Copyright © International Business Machines Corp., 2009
5
*
6
* DESCRIPTION
7
* Glibc independent futex library for testing kernel functionality.
8
*
9
* AUTHOR
10
* Darren Hart <[email protected]>
11
*
12
* HISTORY
13
* 2009-Nov-6: Initial version by Darren Hart <[email protected]>
14
*
15
*****************************************************************************/
16
17
#ifndef _FUTEXTEST_H
18
#define _FUTEXTEST_H
19
20
#include <unistd.h>
21
#include <sys/syscall.h>
22
#include <sys/types.h>
23
#include <linux/futex.h>
24
25
typedef volatile u_int32_t futex_t;
26
#define FUTEX_INITIALIZER 0
27
28
/* Define the newer op codes if the system header file is not up to date. */
29
#ifndef FUTEX_WAIT_BITSET
30
#define FUTEX_WAIT_BITSET 9
31
#endif
32
#ifndef FUTEX_WAKE_BITSET
33
#define FUTEX_WAKE_BITSET 10
34
#endif
35
#ifndef FUTEX_WAIT_REQUEUE_PI
36
#define FUTEX_WAIT_REQUEUE_PI 11
37
#endif
38
#ifndef FUTEX_CMP_REQUEUE_PI
39
#define FUTEX_CMP_REQUEUE_PI 12
40
#endif
41
#ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE
42
#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \
43
FUTEX_PRIVATE_FLAG)
44
#endif
45
#ifndef FUTEX_REQUEUE_PI_PRIVATE
46
#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \
47
FUTEX_PRIVATE_FLAG)
48
#endif
49
50
/*
51
* SYS_futex is expected from system C library, in glibc some 32-bit
52
* architectures (e.g. RV32) are using 64-bit time_t, therefore it doesn't have
53
* SYS_futex defined but just SYS_futex_time64. Define SYS_futex as
54
* SYS_futex_time64 in this situation to ensure the compilation and the
55
* compatibility.
56
*/
57
#if !defined(SYS_futex) && defined(SYS_futex_time64)
58
#define SYS_futex SYS_futex_time64
59
#endif
60
61
/*
62
* On 32bit systems if we use "-D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64" or if
63
* we are using a newer compiler then the size of the timestamps will be 64bit,
64
* however, the SYS_futex will still point to the 32bit futex system call.
65
*/
66
#if __SIZEOF_POINTER__ == 4 && defined(SYS_futex_time64) && \
67
defined(_TIME_BITS) && _TIME_BITS == 64
68
# undef SYS_futex
69
# define SYS_futex SYS_futex_time64
70
#endif
71
72
/**
73
* futex() - SYS_futex syscall wrapper
74
* @uaddr: address of first futex
75
* @op: futex op code
76
* @val: typically expected value of uaddr, but varies by op
77
* @timeout: typically an absolute struct timespec (except where noted
78
* otherwise). Overloaded by some ops
79
* @uaddr2: address of second futex for some ops\
80
* @val3: varies by op
81
* @opflags: flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
82
*
83
* futex() is used by all the following futex op wrappers. It can also be
84
* used for misuse and abuse testing. Generally, the specific op wrappers
85
* should be used instead. It is a macro instead of an static inline function as
86
* some of the types over overloaded (timeout is used for nr_requeue for
87
* example).
88
*
89
* These argument descriptions are the defaults for all
90
* like-named arguments in the following wrappers except where noted below.
91
*/
92
#define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \
93
syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3)
94
95
/**
96
* futex_wait() - block on uaddr with optional timeout
97
* @timeout: relative timeout
98
*/
99
static inline int
100
futex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags)
101
{
102
return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
103
}
104
105
/**
106
* futex_wake() - wake one or more tasks blocked on uaddr
107
* @nr_wake: wake up to this many tasks
108
*/
109
static inline int
110
futex_wake(futex_t *uaddr, int nr_wake, int opflags)
111
{
112
return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
113
}
114
115
/**
116
* futex_wait_bitset() - block on uaddr with bitset
117
* @bitset: bitset to be used with futex_wake_bitset
118
*/
119
static inline int
120
futex_wait_bitset(futex_t *uaddr, futex_t val, struct timespec *timeout,
121
u_int32_t bitset, int opflags)
122
{
123
return futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset,
124
opflags);
125
}
126
127
/**
128
* futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset
129
* @bitset: bitset to compare with that used in futex_wait_bitset
130
*/
131
static inline int
132
futex_wake_bitset(futex_t *uaddr, int nr_wake, u_int32_t bitset, int opflags)
133
{
134
return futex(uaddr, FUTEX_WAKE_BITSET, nr_wake, NULL, NULL, bitset,
135
opflags);
136
}
137
138
/**
139
* futex_lock_pi() - block on uaddr as a PI mutex
140
* @detect: whether (1) or not (0) to perform deadlock detection
141
*/
142
static inline int
143
futex_lock_pi(futex_t *uaddr, struct timespec *timeout, int detect,
144
int opflags)
145
{
146
return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags);
147
}
148
149
/**
150
* futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter
151
*/
152
static inline int
153
futex_unlock_pi(futex_t *uaddr, int opflags)
154
{
155
return futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags);
156
}
157
158
/**
159
* futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION
160
*/
161
static inline int
162
futex_wake_op(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_wake2,
163
int wake_op, int opflags)
164
{
165
return futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op,
166
opflags);
167
}
168
169
/**
170
* futex_requeue() - requeue without expected value comparison, deprecated
171
* @nr_wake: wake up to this many tasks
172
* @nr_requeue: requeue up to this many tasks
173
*
174
* Due to its inherently racy implementation, futex_requeue() is deprecated in
175
* favor of futex_cmp_requeue().
176
*/
177
static inline int
178
futex_requeue(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_requeue,
179
int opflags)
180
{
181
return futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0,
182
opflags);
183
}
184
185
/**
186
* futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
187
* @nr_wake: wake up to this many tasks
188
* @nr_requeue: requeue up to this many tasks
189
*/
190
static inline int
191
futex_cmp_requeue(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
192
int nr_requeue, int opflags)
193
{
194
return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
195
val, opflags);
196
}
197
198
/**
199
* futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2
200
* @uaddr: non-PI futex source
201
* @uaddr2: PI futex target
202
*
203
* This is the first half of the requeue_pi mechanism. It shall always be
204
* paired with futex_cmp_requeue_pi().
205
*/
206
static inline int
207
futex_wait_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2,
208
struct timespec *timeout, int opflags)
209
{
210
return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0,
211
opflags);
212
}
213
214
/**
215
* futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware)
216
* @uaddr: non-PI futex source
217
* @uaddr2: PI futex target
218
* @nr_wake: wake up to this many tasks
219
* @nr_requeue: requeue up to this many tasks
220
*/
221
static inline int
222
futex_cmp_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
223
int nr_requeue, int opflags)
224
{
225
return futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2,
226
val, opflags);
227
}
228
229
/**
230
* futex_cmpxchg() - atomic compare and exchange
231
* @uaddr: The address of the futex to be modified
232
* @oldval: The expected value of the futex
233
* @newval: The new value to try and assign the futex
234
*
235
* Implement cmpxchg using gcc atomic builtins.
236
* http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
237
*
238
* Return the old futex value.
239
*/
240
static inline u_int32_t
241
futex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval)
242
{
243
return __sync_val_compare_and_swap(uaddr, oldval, newval);
244
}
245
246
/**
247
* futex_dec() - atomic decrement of the futex value
248
* @uaddr: The address of the futex to be modified
249
*
250
* Return the new futex value.
251
*/
252
static inline u_int32_t
253
futex_dec(futex_t *uaddr)
254
{
255
return __sync_sub_and_fetch(uaddr, 1);
256
}
257
258
/**
259
* futex_inc() - atomic increment of the futex value
260
* @uaddr: the address of the futex to be modified
261
*
262
* Return the new futex value.
263
*/
264
static inline u_int32_t
265
futex_inc(futex_t *uaddr)
266
{
267
return __sync_add_and_fetch(uaddr, 1);
268
}
269
270
/**
271
* futex_set() - atomic decrement of the futex value
272
* @uaddr: the address of the futex to be modified
273
* @newval: New value for the atomic_t
274
*
275
* Return the new futex value.
276
*/
277
static inline u_int32_t
278
futex_set(futex_t *uaddr, u_int32_t newval)
279
{
280
*uaddr = newval;
281
return newval;
282
}
283
284
#endif
285
286