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