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