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