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