1 /*
2 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
3 * Copyright (c) 2016-2023 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "tests.h"
10
11 #include "scno.h"
12
13 #ifdef __NR_futex
14
15 # include <errno.h>
16 # include <stdarg.h>
17 # include <stdio.h>
18 # include <stdint.h>
19 # include <unistd.h>
20
21 # include <sys/time.h>
22
23 # ifndef FUTEX_PRIVATE_FLAG
24 # define FUTEX_PRIVATE_FLAG 128
25 # endif
26 # ifndef FUTEX_CLOCK_REALTIME
27 # define FUTEX_CLOCK_REALTIME 256
28 # endif
29 # ifndef FUTEX_CMD_MASK
30 # define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
31 # endif
32
33 # include "xlat.h"
34 # include "xlat/futexops.h"
35 # include "xlat/futexwakeops.h"
36 # include "xlat/futexwakecmps.h"
37
38 static void
39 futex_error(int *uaddr, int op, unsigned long val, unsigned long timeout,
40 int *uaddr2, unsigned long val3, int rc, const char *func, int line)
41 {
42 perror_msg_and_fail("%s:%d: futex(%p, %#x, %#x, %#lx, %p, %#x) = %d",
43 func, line, uaddr, op, (unsigned) val, timeout, uaddr,
44 (unsigned) val3, rc);
45 }
46
47 # define CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, \
48 enosys) \
49 do { \
50 errno = 0; \
51 rc = syscall(__NR_futex, (uaddr), (op), (val), (timeout), \
52 (uaddr2), (val3)); \
53 /* It is here due to EPERM on WAKE_OP on AArch64 */ \
54 if ((rc == -1) && (errno == EPERM)) \
55 break; \
56 if (enosys && (rc == -1) && (errno == ENOSYS)) \
57 break; \
58 if (!(check)) \
59 futex_error((uaddr), (op), (val), \
60 (unsigned long) (timeout), (int *) (uaddr2), \
61 (val3), rc, __func__, __LINE__); \
62 } while (0)
63
64 # define CHECK_FUTEX_ENOSYS(uaddr, op, val, timeout, uaddr2, val3, check) \
65 CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 1)
66
67 # define CHECK_FUTEX(uaddr, op, val, timeout, uaddr2, val3, check) \
68 CHECK_FUTEX_GENERIC(uaddr, op, val, timeout, uaddr2, val3, check, 0)
69
70 enum argmask {
71 ARG3 = 1 << 0,
72 ARG4 = 1 << 1,
73 ARG5 = 1 << 2,
74 ARG6 = 1 << 3,
75 };
76
77 static void
78 invalid_op(int *val, int op, uint32_t argmask, ...)
79 {
80 static const unsigned long args[] = {
81 (unsigned long) 0xface1e55deadbee1ULL,
82 (unsigned long) 0xface1e56deadbee2ULL,
83 (unsigned long) 0xface1e57deadbee3ULL,
84 (unsigned long) 0xface1e58deadbee4ULL,
85 };
86 /* Since timeout value is copied before full op check, we should provide
87 * some valid timeout address or NULL */
88 int cmd = op & FUTEX_CMD_MASK;
89 bool valid_timeout = (cmd == FUTEX_WAIT) || (cmd == FUTEX_LOCK_PI) || \
90 (cmd == FUTEX_LOCK_PI2) || (cmd == FUTEX_WAIT_BITSET) || \
91 (cmd == FUTEX_WAIT_REQUEUE_PI);
92 bool timeout_is_val2 = (cmd == FUTEX_REQUEUE) ||
93 (cmd == FUTEX_CMP_REQUEUE) || (cmd == FUTEX_WAKE_OP) ||
94 (cmd == FUTEX_CMP_REQUEUE_PI);
95 const char *fmt;
96 int saved_errno;
97 int rc;
98 va_list ap;
99
100
101 CHECK_FUTEX(val, op, args[0], valid_timeout ? 0 : args[1], args[2],
102 args[3], (rc == -1) && (errno == ENOSYS));
103 saved_errno = errno;
104 printf("futex(%p, %#x /* FUTEX_??? */", val, op);
105
106 va_start(ap, argmask);
107
108 for (int i = 0; i < 4; ++i) {
109 if (argmask & (1 << i)) {
110 fmt = va_arg(ap, const char *);
111
112 printf(", ");
113
114 if (((1 << i) == ARG3) || ((1 << i) == ARG6) ||
115 (((1 << i) == ARG4) && timeout_is_val2))
116 printf(fmt, (unsigned) args[i]);
117 else
118 printf(fmt, args[i]);
119 }
120 }
121
122 va_end(ap);
123
124 errno = saved_errno;
125 printf(") = -1 ENOSYS (%m)\n");
126 }
127
128 # define CHECK_INVALID_CLOCKRT(op, ...) \
129 do { \
130 invalid_op(uaddr, FUTEX_CLOCK_REALTIME | (op), __VA_ARGS__); \
131 invalid_op(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | \
132 (op), __VA_ARGS__); \
133 } while (0)
134
135 /* Value which differs from one stored in int *val */
136 # define VAL ((unsigned long) 0xbadda7a0facefeedLLU)
137 # define VAL_PR ((unsigned) VAL)
138
139 # define VALP ((unsigned long) 0xbadda7a01acefeedLLU)
140 # define VALP_PR ((unsigned) VALP)
141
142 # define VAL2 ((unsigned long) 0xbadda7a0ca7b100dLLU)
143 # define VAL2_PR ((unsigned) VAL2)
144
145 # define VAL2P ((unsigned long) 0xbadda7a07a7b100dLLU)
146 # define VAL2P_PR ((unsigned) VAL2P)
147
148 # define VAL3 ((unsigned long) 0xbadda7a09caffee1LLU)
149 # define VAL3_PR ((unsigned) VAL3)
150
151 # define VAL3A ((unsigned long) 0xbadda7a0ffffffffLLU)
152 # define VAL3A_PR "FUTEX_BITSET_MATCH_ANY"
153
154 int
155 main(int argc, char *argv[])
156 {
157 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr);
158 TAIL_ALLOC_OBJECT_CONST_PTR(int, uaddr2);
159 int rc;
160
161 uaddr[0] = 0x1deadead;
162 uaddr2[0] = 0xbadf00d;
163
164 TAIL_ALLOC_OBJECT_CONST_PTR(kernel_old_timespec_t, tmout);
165 tmout->tv_sec = 123;
166 tmout->tv_nsec = 0xbadc0de;
167
168 /* FUTEX_WAIT - check whether uaddr == val and sleep
169 * Possible flags: PRIVATE, CLOCK_RT (since 4.5)
170 * 1. uaddr - futex address
171 * 2. op - FUTEX_WAIT
172 * 3. val - expected value
173 * 4. timeout - address to timespec with timeout
174 * 5. uaddr2 - not used
175 * 6. val3 - not used
176 */
177
178 /* uaddr is NULL */
179 CHECK_FUTEX(NULL, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
180 (rc == -1) && (errno == EFAULT));
181 printf("futex(NULL, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
182 VAL_PR, (long long) tmout->tv_sec,
183 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
184
185 /* uaddr is faulty */
186 CHECK_FUTEX(uaddr + 1, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
187 (rc == -1) && (errno == EFAULT));
188 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
189 uaddr + 1, VAL_PR, (long long) tmout->tv_sec,
190 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
191
192 /* timeout is faulty */
193 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout + 1, uaddr2, VAL3,
194 (rc == -1) && (errno == EFAULT));
195 printf("futex(%p, FUTEX_WAIT, %u, %p) = %s\n",
196 uaddr, 0xfacefeed, tmout + 1, sprintrc(rc));
197
198 /* timeout is invalid */
199 tmout->tv_sec = 0xdeadbeefU;
200 tmout->tv_nsec = 0xfacefeedU;
201
202 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
203 (rc == -1) && (errno == EINVAL));
204 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
205 uaddr, VAL_PR, (long long) tmout->tv_sec,
206 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
207
208 tmout->tv_sec = (typeof(tmout->tv_sec)) 0xcafef00ddeadbeefLL;
209 tmout->tv_nsec = (long) 0xbadc0dedfacefeedLL;
210
211 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2, VAL3,
212 (rc == -1) && (errno == EINVAL));
213 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
214 uaddr, VAL_PR, (long long) tmout->tv_sec,
215 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
216
217 tmout->tv_sec = 123;
218 tmout->tv_nsec = 0xbadc0de;
219
220 /* uaddr is not as provided; uaddr2 is faulty but ignored */
221 CHECK_FUTEX(uaddr, FUTEX_WAIT, VAL, tmout, uaddr2 + 1, VAL3,
222 (rc == -1) && (errno == EAGAIN));
223 printf("futex(%p, FUTEX_WAIT, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
224 uaddr, VAL_PR, (long long) tmout->tv_sec,
225 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
226
227 /* uaddr is not as provided; uaddr2 is faulty but ignored */
228 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT, VAL, tmout,
229 uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
230 printf("futex(%p, FUTEX_WAIT_PRIVATE, %u, {tv_sec=%lld, tv_nsec=%llu})"
231 " = %s\n",
232 uaddr, VAL_PR, (long long) tmout->tv_sec,
233 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
234
235 /* Next 2 tests are with CLOCKRT bit set */
236
237 /* Valid after v4.4-rc2-27-g337f130 */
238 CHECK_FUTEX_ENOSYS(uaddr,
239 FUTEX_CLOCK_REALTIME | FUTEX_WAIT,
240 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
241 printf("futex(%p, FUTEX_WAIT|FUTEX_CLOCK_REALTIME, %u"
242 ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
243 uaddr, VAL_PR, (long long) tmout->tv_sec,
244 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
245
246 CHECK_FUTEX_ENOSYS(uaddr,
247 FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG | FUTEX_WAIT,
248 VAL, tmout, uaddr2, 0, (rc == -1) && (errno == EAGAIN));
249 printf("futex(%p, FUTEX_WAIT_PRIVATE|FUTEX_CLOCK_REALTIME, %u"
250 ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
251 uaddr, VAL_PR, (long long) tmout->tv_sec,
252 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
253
254 /* FUTEX_WAIT_BITSET - FUTEX_WAIT which provides additional bitmask
255 * which should be matched at least in one bit with
256 * wake mask in order to wake.
257 * Possible flags: PRIVATE, CLOCKRT
258 * 1. uaddr - futex address
259 * 2. op - FUTEX_TRYLOCK_PI
260 * 3. val - expected value stored in uaddr
261 * 4. timeout - timeout
262 * 5. uaddr2 - not used
263 * 6. val3 - bitmask
264 */
265
266 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1,
267 VAL3, (rc == -1) && (errno == EAGAIN));
268 printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%lld, tv_nsec=%llu}"
269 ", %#x) = %s\n",
270 uaddr, VAL_PR, (long long) tmout->tv_sec,
271 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
272 sprintrc(rc));
273
274 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1,
275 VAL3A, (rc == -1) && (errno == EAGAIN));
276 printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%lld, tv_nsec=%llu}"
277 ", %s) = %s\n",
278 uaddr, VAL_PR, (long long) tmout->tv_sec,
279 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3A_PR,
280 sprintrc(rc));
281
282 /* val3 of 0 is invalid */
283 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, 0,
284 (rc == -1) && (errno == EINVAL));
285 printf("futex(%p, FUTEX_WAIT_BITSET, %u, {tv_sec=%lld, tv_nsec=%llu}"
286 ", %#x) = %s\n",
287 uaddr, VAL_PR, (long long) tmout->tv_sec,
288 zero_extend_signed_to_ull(tmout->tv_nsec), 0, sprintrc(rc));
289
290 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_BITSET, VAL,
291 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
292 printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE, %u"
293 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
294 uaddr, VAL_PR, (long long) tmout->tv_sec,
295 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
296 sprintrc(rc));
297
298 /* Next 3 tests are with CLOCKRT bit set */
299
300 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL,
301 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EAGAIN));
302 printf("futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u"
303 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
304 uaddr, VAL_PR, (long long) tmout->tv_sec,
305 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
306 sprintrc(rc));
307
308 /* val3 of 0 is invalid */
309 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_BITSET, VAL,
310 tmout, uaddr2 + 1, 0, (rc == -1) && (errno == EINVAL));
311 printf("futex(%p, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %u"
312 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
313 uaddr, VAL_PR, (long long) tmout->tv_sec,
314 zero_extend_signed_to_ull(tmout->tv_nsec), 0, sprintrc(rc));
315
316 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
317 FUTEX_WAIT_BITSET, VAL, tmout, uaddr2 + 1, VAL3,
318 (rc == -1) && (errno == EAGAIN));
319 printf("futex(%p, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, %u"
320 ", {tv_sec=%lld, tv_nsec=%llu}, %#x) = %s\n",
321 uaddr, VAL_PR, (long long) tmout->tv_sec,
322 zero_extend_signed_to_ull(tmout->tv_nsec), VAL3_PR,
323 sprintrc(rc));
324
325 /* FUTEX_WAKE - wake val processes waiting for uaddr
326 * Possible flags: PRIVATE
327 * 1. uaddr - futex address
328 * 2. op - FUTEX_WAKE
329 * 3. val - how many processes to wake
330 * 4. timeout - not used
331 * 5. uaddr2 - not used
332 * 6. val3 - not used
333 */
334
335 /* Zero processes to wake is not a good idea, but it should return 0 */
336 CHECK_FUTEX(uaddr, FUTEX_WAKE, 0, NULL, NULL, 0, (rc == 0));
337 printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 0, sprintrc(rc));
338
339 /* Trying to wake some processes, but there's nothing to wake */
340 CHECK_FUTEX(uaddr, FUTEX_WAKE, 10, NULL, NULL, 0, (rc == 0));
341 printf("futex(%p, FUTEX_WAKE, %u) = %s\n", uaddr, 10, sprintrc(rc));
342
343 /* Trying to wake some processes, but there's nothing to wake */
344 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE, 10, NULL,
345 NULL, 0, (rc == 0));
346 printf("futex(%p, FUTEX_WAKE_PRIVATE, %u) = %s\n", uaddr, 10,
347 sprintrc(rc));
348
349 CHECK_INVALID_CLOCKRT(FUTEX_WAKE, ARG3, "%u");
350
351 /* FUTEX_WAKE_BITSET - wake val processes waiting for uaddr which has at
352 * least one common bit with bitset provided in
353 * val3.
354 * Possible flags: PRIVATE
355 * 1. uaddr - futex address
356 * 2. op - FUTEX_WAKE
357 * 3. val - how many processes to wake
358 * 4. timeout - not used
359 * 5. uaddr2 - not used
360 * 6. val3 - bitmask
361 */
362
363 /* Trying to wake some processes, but there's nothing to wake */
364 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL,
365 VAL3, (rc == 0));
366 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10,
367 VAL3_PR, sprintrc(rc));
368
369 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL,
370 VAL3A, (rc == 0));
371 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %s) = %s\n", uaddr, 10,
372 VAL3A_PR, sprintrc(rc));
373
374 /* bitset 0 is invalid */
375 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAKE_BITSET, 10, NULL, NULL, 0,
376 (rc == -1) && (errno == EINVAL));
377 printf("futex(%p, FUTEX_WAKE_BITSET, %u, %#x) = %s\n", uaddr, 10, 0,
378 sprintrc(rc));
379
380 /* Trying to wake some processes, but there's nothing to wake */
381 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAKE_BITSET, 10,
382 NULL, NULL, VAL3, (rc == 0));
383 printf("futex(%p, FUTEX_WAKE_BITSET_PRIVATE, %u, %#x) = %s\n", uaddr,
384 10, VAL3_PR, sprintrc(rc));
385
386 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_BITSET, ARG3 | ARG6, "%u", "%#x");
387
388 /* FUTEX_FD - deprecated
389 * Possible flags: PRIVATE
390 * 1. uaddr - futex address
391 * 2. op - FUTEX_FD
392 * 3. val - signal number
393 * 4. timeout - not used
394 * 5. uaddr2 - not used
395 * 6. val3 - not used
396 */
397
398 /* FUTEX_FD is not implemented since 2.6.26 */
399 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_FD, VAL, NULL, NULL, VAL3,
400 (rc == -1) && (errno == EINVAL));
401 printf("futex(%p, FUTEX_FD, %u) = %s\n", uaddr, VAL_PR, sprintrc(rc));
402
403 /* FUTEX_FD is not implemented since 2.6.26 */
404 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_FD, VAL, NULL,
405 NULL, VAL3, (rc == -1) && (errno == EINVAL));
406 printf("futex(%p, FUTEX_FD|FUTEX_PRIVATE_FLAG, %u) = %s\n", uaddr,
407 VAL_PR, sprintrc(rc));
408
409 CHECK_INVALID_CLOCKRT(FUTEX_FD, ARG3, "%u");
410
411 /* FUTEX_REQUEUE - wake val processes and re-queue rest on uaddr2
412 * Possible flags: PRIVATE
413 * 1. uaddr - futex address
414 * 2. op - FUTEX_REQUEUE
415 * 3. val - how many processes to wake
416 * 4. val2 - amount of processes to re-queue on uadr2
417 * 5. uaddr2 - another futex address, to re-queue waiting processes on
418 * 6. val3 - not used
419 */
420
421 /* Trying to re-queue some processes but there's nothing to re-queue */
422 CHECK_FUTEX(uaddr, FUTEX_REQUEUE, VAL, VAL2, uaddr2, VAL3,
423 (rc == 0) || ((rc == -1) && (errno == EINVAL)));
424 printf("futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s\n",
425 uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc));
426
427 CHECK_FUTEX(uaddr, FUTEX_REQUEUE, VALP, VAL2P, uaddr2, VAL3,
428 (rc == 0));
429 printf("futex(%p, FUTEX_REQUEUE, %u, %u, %p) = %s\n",
430 uaddr, VALP_PR, VAL2P_PR, uaddr2, sprintrc(rc));
431
432 /* Trying to re-queue some processes but there's nothing to re-queue */
433 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE, VAL, VAL2,
434 uaddr2, VAL3, (rc == 0) || ((rc == -1) && (errno == EINVAL)));
435 printf("futex(%p, FUTEX_REQUEUE_PRIVATE, %u, %u, %p) = %s\n",
436 uaddr, VAL_PR, VAL2_PR, uaddr2, sprintrc(rc));
437
438 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE, VALP,
439 VAL2P, uaddr2, VAL3, (rc == 0));
440 printf("futex(%p, FUTEX_REQUEUE_PRIVATE, %u, %u, %p) = %s\n",
441 uaddr, VALP_PR, VAL2P_PR, uaddr2, sprintrc(rc));
442
443 CHECK_INVALID_CLOCKRT(FUTEX_REQUEUE, ARG3 | ARG4 | ARG5, "%u", "%u",
444 "%#lx");
445
446 /* FUTEX_CMP_REQUEUE - wake val processes and re-queue rest on uaddr2
447 * if uaddr has value val3
448 * Possible flags: PRIVATE
449 * 1. uaddr - futex address
450 * 2. op - FUTEX_CMP_REQUEUE
451 * 3. val - how many processes to wake
452 * 4. val2 - amount of processes to re-queue on uadr2
453 * 5. uaddr2 - another futex address, to re-queue waiting processes on
454 * 6. val3 - expected value stored in uaddr
455 */
456
457 /* Comparison re-queue with wrong val value */
458 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, VAL3,
459 (rc == -1) && (errno == EAGAIN || errno == EINVAL));
460 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
461 uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc));
462
463 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VALP, VAL2P, uaddr2, VAL3,
464 (rc == -1) && (errno == EAGAIN));
465 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
466 uaddr, VALP_PR, VAL2P_PR, uaddr2, VAL3_PR, sprintrc(rc));
467
468 /* Successful comparison re-queue */
469 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VAL, VAL2, uaddr2, *uaddr,
470 (rc == 0) || ((rc == -1) && (errno == EINVAL)));
471 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
472 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
473
474 CHECK_FUTEX(uaddr, FUTEX_CMP_REQUEUE, VALP, VAL2P, uaddr2, *uaddr,
475 (rc == 0));
476 printf("futex(%p, FUTEX_CMP_REQUEUE, %u, %u, %p, %u) = %s\n",
477 uaddr, VALP_PR, VAL2P_PR, uaddr2, *uaddr, sprintrc(rc));
478
479 /* Successful comparison re-queue */
480 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE, VAL,
481 VAL2, uaddr2, *uaddr,
482 (rc == 0) || ((rc == -1) && (errno == EINVAL)));
483 printf("futex(%p, FUTEX_CMP_REQUEUE_PRIVATE, %u, %u, %p, %u) = %s\n",
484 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
485
486 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE, VALP,
487 VAL2P, uaddr2, *uaddr, (rc == 0));
488 printf("futex(%p, FUTEX_CMP_REQUEUE_PRIVATE, %u, %u, %p, %u) = %s\n",
489 uaddr, VALP_PR, VAL2P_PR, uaddr2, *uaddr, sprintrc(rc));
490
491 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE, ARG3 | ARG4 | ARG5 | ARG6,
492 "%u", "%u", "%#lx", "%u");
493
494 /* FUTEX_WAKE_OP - wake val processes waiting for uaddr, additionally
495 * wake val2 processes waiting for uaddr2 in case
496 * operation encoded in val3 (change of value at uaddr2
497 * and comparison of previous value against provided
498 * constant) succeeds with value at uaddr2. Operation
499 * result is written to value of uaddr2 (in any case).
500 * 1. uaddr - futex address
501 * 2. op - FUTEX_WAKE_OP
502 * 3. val - how many processes to wake
503 * 4. val2 - amount of processes to wake in case operation encoded in
504 * val3 returns true
505 * 5. uaddr2 - another futex address, for conditional wake of
506 * additional processes
507 * 6. val3 - encoded operation:
508 * 1. bit 31 - if 1 then value stored in field field 4
509 * should be interpreted as power of 2.
510 * 2. 28..30 - arithmetic operation which should be
511 * applied to previous value stored in
512 * uaddr2. Values available (from 2005 up to
513 * 2016): SET. ADD, OR, ANDN, XOR.
514 * 3. 24..29 - comparison operation which should be
515 * applied to the old value stored in uaddr2
516 * (before arithmetic operation is applied).
517 * Possible values: EQ, NE, LT, LE, GT, GE.
518 * 4. 12..23 - Second operand for arithmetic operation.
519 * If bit 31 is set, it is interpreted as
520 * power of 2.
521 * 5. 00..11 - Value against which old value stored in
522 * uaddr2 is compared.
523 */
524
525 static const struct {
526 uint32_t val;
527 const char *str;
528
529 /*
530 * Peculiar semantics:
531 * * err == 0 and err2 != 0 => expect both either the absence
532 * of error or presence of err2
533 * * err != 0 and err2 == 0 => expect err only, no success
534 * expected.
535 */
536 int err;
537 int err2;
538 } wake_ops[] = {
539 { 0x00000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
540 { 0x00fff000, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|"
541 "0" },
542 { 0x00000fff, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_EQ<<24|"
543 "0xfff" },
544 { 0x00ffffff, "FUTEX_OP_SET<<28|0xfff<<12|FUTEX_OP_CMP_EQ<<24|"
545 "0xfff" },
546 { 0x10000000, "FUTEX_OP_ADD<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
547 { 0x20000000, "FUTEX_OP_OR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
548 { 0x30000000, "FUTEX_OP_ANDN<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
549 { 0x40000000, "FUTEX_OP_XOR<<28|0<<12|FUTEX_OP_CMP_EQ<<24|0" },
550 { 0x50000000, "0x5<<28 /* FUTEX_OP_??? */|0<<12|"
551 "FUTEX_OP_CMP_EQ<<24|0", ENOSYS },
552 { 0x70000000, "0x7<<28 /* FUTEX_OP_??? */|0<<12|"
553 "FUTEX_OP_CMP_EQ<<24|0", ENOSYS },
554 { 0x80000000, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_SET<<28|0<<12|"
555 "FUTEX_OP_CMP_EQ<<24|0" },
556 { 0xa0caffee, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_OR<<28|"
557 "0xcaf<<12|FUTEX_OP_CMP_EQ<<24|0xfee", 0, EINVAL },
558 { 0x01000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_NE<<24|0" },
559 { 0x01234567, "FUTEX_OP_SET<<28|0x234<<12|FUTEX_OP_CMP_NE<<24|"
560 "0x567" },
561 { 0x02000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LT<<24|0" },
562 { 0x03000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_LE<<24|0" },
563 { 0x04000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GT<<24|0" },
564 { 0x05000000, "FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GE<<24|0" },
565 { 0x06000000, "FUTEX_OP_SET<<28|0<<12|"
566 "0x6<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS },
567 { 0x07000000, "FUTEX_OP_SET<<28|0<<12|"
568 "0x7<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS },
569 { 0x08000000, "FUTEX_OP_SET<<28|0<<12|"
570 "0x8<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS },
571 { 0x0f000000, "FUTEX_OP_SET<<28|0<<12|"
572 "0xf<<24 /* FUTEX_OP_CMP_??? */|0", ENOSYS },
573 { 0xbadfaced, "FUTEX_OP_OPARG_SHIFT<<28|FUTEX_OP_ANDN<<28|"
574 "0xdfa<<12|0xa<<24 /* FUTEX_OP_CMP_??? */|0xced",
575 ENOSYS, EINVAL },
576 { 0xffffffff, "FUTEX_OP_OPARG_SHIFT<<28|"
577 "0x7<<28 /* FUTEX_OP_??? */|0xfff<<12|"
578 "0xf<<24 /* FUTEX_OP_CMP_??? */|0xfff",
579 ENOSYS, EINVAL },
580 };
581
582 for (unsigned int i = 0; i < ARRAY_SIZE(wake_ops); ++i) {
583 for (unsigned int j = 0; j < 2; ++j) {
584 CHECK_FUTEX_ENOSYS(uaddr,
585 j ? FUTEX_WAKE_OP_PRIVATE : FUTEX_WAKE_OP,
586 VAL, i, uaddr2, wake_ops[i].val,
587 /*
588 * Either one of errs is 0 or rc == 0 is not
589 * allowed.
590 */
591 ((!wake_ops[i].err || !wake_ops[i].err2 ||
592 (rc != 0)) &&
593 ((!wake_ops[i].err && (rc == 0)) ||
594 (wake_ops[i].err && (rc == -1) &&
595 (errno == wake_ops[i].err)) ||
596 (wake_ops[i].err2 && (rc == -1) &&
597 (errno == wake_ops[i].err2)))));
598 printf("futex(%p, FUTEX_WAKE_OP%s, %u, %u, %p, %s)"
599 " = %s\n", uaddr, j ? "_PRIVATE" : "", VAL_PR,
600 i, uaddr2, wake_ops[i].str, sprintrc(rc));
601 }
602 }
603
604 CHECK_INVALID_CLOCKRT(FUTEX_WAKE_OP, ARG3 | ARG4 | ARG5 | ARG6,
605 "%u", "%u", "%#lx",
606 /* Decoding of the 0xdeadbee4 value */
607 "FUTEX_OP_OPARG_SHIFT<<28|0x5<<28 /* FUTEX_OP_??? */|0xadb<<12|"
608 "0xe<<24 /* FUTEX_OP_CMP_??? */|0xee4");
609
610 /* FUTEX_LOCK_PI - slow path for mutex lock with process inheritance
611 * support. Expect that futex has 0 in unlocked case and
612 * TID of owning process in locked case. Value can also
613 * contain FUTEX_WAITERS bit signalling the presence of
614 * waiters queue.
615 * Possible flags: PRIVATE
616 * 1. uaddr - futex address
617 * 2. op - FUTEX_LOCK_PI
618 * 3. val - not used
619 * 4. timeout - timeout
620 * 5. uaddr2 - not used
621 * 6. val3 - not used
622 */
623
624 *uaddr = getpid();
625
626 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_LOCK_PI, VAL, tmout, uaddr2 + 1,
627 VAL3, (rc == -1) && (errno == EFAULT));
628 printf("futex(%p, FUTEX_LOCK_PI, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
629 uaddr + 1, (long long) tmout->tv_sec,
630 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
631
632 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI, VAL,
633 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
634 printf("futex(%p, FUTEX_LOCK_PI_PRIVATE, {tv_sec=%lld, tv_nsec=%llu})"
635 " = %s\n",
636 uaddr + 1, (long long) tmout->tv_sec,
637 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
638
639 /* NULL is passed by invalid_op() in cases valid timeout address is
640 * needed */
641 CHECK_INVALID_CLOCKRT(FUTEX_LOCK_PI, ARG4, "NULL");
642
643 /* FUTEX_UNLOCK_PI - slow path for mutex unlock with process inheritance
644 * support. Expected to be called by process in case
645 * it failed to execute fast path (it usually means
646 * that FUTEX_WAITERS flag had been set while the lock
647 * has been held).
648 * Possible flags: PRIVATE
649 * 1. uaddr - futex address
650 * 2. op - FUTEX_UNLOCK_PI
651 * 3. val - not used
652 * 4. timeout - not used
653 * 5. uaddr2 - not used
654 * 6. val3 - not used
655 */
656
657 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_UNLOCK_PI, VAL, tmout, uaddr2 + 1,
658 VAL3, (rc == -1) && (errno == EFAULT));
659 printf("futex(%p, FUTEX_UNLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc));
660
661 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_UNLOCK_PI, VAL,
662 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
663 printf("futex(%p, FUTEX_UNLOCK_PI_PRIVATE) = %s\n", uaddr + 1,
664 sprintrc(rc));
665
666 CHECK_INVALID_CLOCKRT(FUTEX_UNLOCK_PI, 0);
667
668 /* FUTEX_TRYLOCK_PI - slow path for mutex trylock with process
669 * inheritance support.
670 * Possible flags: PRIVATE
671 * 1. uaddr - futex address
672 * 2. op - FUTEX_TRYLOCK_PI
673 * 3. val - not used
674 * 4. timeout - not used
675 * 5. uaddr2 - not used
676 * 6. val3 - not used
677 */
678
679 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_TRYLOCK_PI, VAL, tmout, uaddr2 + 1,
680 VAL3, (rc == -1) && (errno == EFAULT));
681 printf("futex(%p, FUTEX_TRYLOCK_PI) = %s\n", uaddr + 1, sprintrc(rc));
682
683 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_TRYLOCK_PI,
684 VAL, tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
685 printf("futex(%p, FUTEX_TRYLOCK_PI_PRIVATE) = %s\n", uaddr + 1,
686 sprintrc(rc));
687
688 CHECK_INVALID_CLOCKRT(FUTEX_TRYLOCK_PI, 0);
689
690 /* FUTEX_WAIT_REQUEUE_PI - kernel-side handling of special case when
691 * processes should be re-queued on PI-aware
692 * futexes. This is so special since PI futexes
693 * utilize rt_mutex and it should be at no time
694 * left free with a wait queue, so this should
695 * be performed atomically in-kernel.
696 * Possible flags: PRIVATE, CLOCKRT
697 * 1. uaddr - futex address
698 * 2. op - FUTEX_WAIT_REQUEUE_PI
699 * 3. val - expected value stored in uaddr
700 * 4. timeout - timeout
701 * 5. uaddr2 - (PI-aware) futex address to requeue process on
702 * 6. val3 - not used (in kernel, it always initialized to
703 * FUTEX_BITSET_MATCH_ANY and passed to
704 * futex_wait_requeue_pi())
705 */
706
707 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2,
708 VAL3, (rc == -1) && (errno == EAGAIN));
709 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI, %u"
710 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
711 uaddr, VAL_PR, (long long) tmout->tv_sec,
712 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
713
714 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_WAIT_REQUEUE_PI,
715 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
716 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE, %u"
717 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
718 uaddr, VAL_PR, (long long) tmout->tv_sec,
719 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
720
721 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_WAIT_REQUEUE_PI,
722 VAL, tmout, uaddr2, VAL3, (rc == -1) && (errno == EAGAIN));
723 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI|FUTEX_CLOCK_REALTIME, %u"
724 ", {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
725 uaddr, VAL_PR, (long long) tmout->tv_sec,
726 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
727
728 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CLOCK_REALTIME | FUTEX_PRIVATE_FLAG |
729 FUTEX_WAIT_REQUEUE_PI, VAL, tmout, uaddr2, VAL3,
730 (rc == -1) && (errno == EAGAIN));
731 printf("futex(%p, FUTEX_WAIT_REQUEUE_PI_PRIVATE|FUTEX_CLOCK_REALTIME"
732 ", %u, {tv_sec=%lld, tv_nsec=%llu}, %p) = %s\n",
733 uaddr, VAL_PR, (long long) tmout->tv_sec,
734 zero_extend_signed_to_ull(tmout->tv_nsec), uaddr2, sprintrc(rc));
735
736 /* FUTEX_CMP_REQUEUE_PI - version of FUTEX_CMP_REQUEUE which re-queues
737 * on PI-aware futex.
738 * Possible flags: PRIVATE
739 * 1. uaddr - futex address
740 * 2. op - FUTEX_CMP_REQUEUE
741 * 3. val - how many processes to wake
742 * 4. val2 - amount of processes to re-queue on uadr2
743 * 5. uaddr2 - (PI-aware) futex address, to re-queue waiting processes
744 * on
745 * 6. val3 - expected value stored in uaddr
746 */
747
748 /* All these should fail with EINVAL since we try to re-queue to non-PI
749 * futex.
750 */
751
752 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2, VAL3,
753 (rc == -1) && (errno == EINVAL));
754 printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n",
755 uaddr, VAL_PR, VAL2_PR, uaddr2, VAL3_PR, sprintrc(rc));
756
757 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_CMP_REQUEUE_PI, VAL, VAL2, uaddr2,
758 *uaddr, (rc == -1) && (errno == EINVAL));
759 printf("futex(%p, FUTEX_CMP_REQUEUE_PI, %u, %u, %p, %u) = %s\n",
760 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
761
762 CHECK_FUTEX_ENOSYS(uaddr, FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE_PI,
763 VAL, VAL2, uaddr2, *uaddr, (rc == -1) && (errno == EINVAL));
764 printf("futex(%p, FUTEX_CMP_REQUEUE_PI_PRIVATE, %u, %u, %p, %u) = %s\n",
765 uaddr, VAL_PR, VAL2_PR, uaddr2, *uaddr, sprintrc(rc));
766
767 CHECK_INVALID_CLOCKRT(FUTEX_CMP_REQUEUE_PI, ARG3 | ARG4 | ARG5 | ARG6,
768 "%u", "%u", "%#lx", "%u");
769
770 /* FUTEX_LOCK_PI2 - same as FUTEX_LOCK_PI, but with CLOCK_MONOTONIC
771 * instead of CLOCK_REALTIME.
772 * Possible flags: PRIVATE
773 * 1. uaddr - futex address
774 * 2. op - FUTEX_LOCK_PI2
775 * 3. val - not used
776 * 4. timeout - timeout
777 * 5. uaddr2 - not used
778 * 6. val3 - not used
779 */
780
781 *uaddr = getpid();
782
783 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_LOCK_PI2, VAL, tmout, uaddr2 + 1,
784 VAL3, (rc == -1) && (errno == EFAULT));
785 printf("futex(%p, FUTEX_LOCK_PI2, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
786 uaddr + 1, (long long) tmout->tv_sec,
787 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
788
789 CHECK_FUTEX_ENOSYS(uaddr + 1, FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI2, VAL,
790 tmout, uaddr2 + 1, VAL3, (rc == -1) && (errno == EFAULT));
791 printf("futex(%p, FUTEX_LOCK_PI2_PRIVATE, {tv_sec=%lld, tv_nsec=%llu})"
792 " = %s\n",
793 uaddr + 1, (long long) tmout->tv_sec,
794 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
795
796
797 /*
798 * Unknown commands
799 */
800
801 CHECK_FUTEX(uaddr, 0xe, VAL, tmout + 1, uaddr2 + 1, VAL3,
802 (rc == -1) && (errno == ENOSYS));
803 printf("futex(%p, 0xe /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n",
804 uaddr, VAL_PR, tmout + 1, uaddr2 + 1, VAL3_PR, sprintrc(rc));
805
806 CHECK_FUTEX(uaddr, 0xbefeeded, VAL, tmout + 1, uaddr2, VAL3,
807 (rc == -1) && (errno == ENOSYS));
808 printf("futex(%p, 0xbefeeded /* FUTEX_??? */, %u, %p, %p, %#x) = %s\n",
809 uaddr, VAL_PR, tmout + 1, uaddr2, VAL3_PR, sprintrc(rc));
810
811 puts("+++ exited with 0 +++");
812
813 return 0;
814 }
815
816 #else
817
818 SKIP_MAIN_UNDEFINED("__NR_futex")
819
820 #endif