1 /*
2 * Check decoding of futex_waitv syscall.
3 *
4 * Copyright (c) 2015-2022 Dmitry V. Levin <ldv@strace.io>
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include "scno.h"
12 #include "kernel_timespec.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <time.h>
16 #include <unistd.h>
17 #include <linux/futex.h>
18
19 static const char *errstr;
20
21 static long
22 k_futex_waitv(const void *const waiters,
23 const unsigned int nr_futexes,
24 const unsigned int flags,
25 const void *const timeout,
26 const unsigned int clockid)
27 {
28 const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
29 const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
30 const kernel_ulong_t arg1 = (uintptr_t) waiters;
31 const kernel_ulong_t arg2 = fill | nr_futexes;
32 const kernel_ulong_t arg3 = fill | flags;
33 const kernel_ulong_t arg4 = (uintptr_t) timeout;
34 const kernel_ulong_t arg5 = fill | clockid;
35 const long rc = syscall(__NR_futex_waitv,
36 arg1, arg2, arg3, arg4, arg5, bad);
37 errstr = sprintrc(rc);
38 return rc;
39 }
40
41 int
42 main(void)
43 {
44 TAIL_ALLOC_OBJECT_CONST_PTR(uint32_t, futex);
45 TAIL_ALLOC_OBJECT_CONST_PTR(struct futex_waitv, waiter);
46 TAIL_ALLOC_OBJECT_CONST_PTR(kernel_timespec64_t, ts);
47 ts->tv_sec = 1;
48 ts->tv_nsec = 2;
49
50 k_futex_waitv(0, 1, -1U, 0, 1);
51 printf("futex_waitv(NULL, 1, %#x, NULL, CLOCK_MONOTONIC) = %s\n",
52 -1U, errstr);
53
54 k_futex_waitv(waiter + 1, 0, 1, ts + 1, -1U);
55 printf("futex_waitv([], 0, %#x, %p, %#x /* CLOCK_??? */) = %s\n",
56 1, ts + 1, -1U, errstr);
57
58 k_futex_waitv((void *) waiter + 1, 1, 0, ts, 0);
59 printf("futex_waitv(%p, 1, 0, {tv_sec=1, tv_nsec=2}, CLOCK_REALTIME)"
60 " = %s\n",
61 (void *) waiter + 1, errstr);
62
63 waiter->uaddr = 0;
64 k_futex_waitv(waiter, 1, 0, 0, 1);
65 printf("futex_waitv([{val=%#llx, uaddr=NULL, flags=%s|%#x"
66 ", __reserved=%#x}], 1, 0, NULL, CLOCK_MONOTONIC) = %s\n",
67 (unsigned long long) waiter->val,
68 "FUTEX_32|FUTEX_PRIVATE_FLAG",
69 waiter->flags & ~(FUTEX_32|FUTEX_PRIVATE_FLAG),
70 waiter->__reserved, errstr);
71
72 waiter->val = 0xdeadbeeffacefeedULL;
73 waiter->uaddr = -1ULL;
74 waiter->flags = 0;
75 waiter->__reserved = 0;
76 k_futex_waitv(waiter, 1, 0, 0, 2);
77 printf("futex_waitv([{val=%#llx, uaddr=%#llx, flags=0}], 1, 0, NULL"
78 ", CLOCK_PROCESS_CPUTIME_ID) = %s\n",
79 (unsigned long long) waiter->val,
80 (unsigned long long) waiter->uaddr,
81 errstr);
82
83 waiter->val = 0;
84 waiter->uaddr = (uintptr_t) futex;
85 waiter->flags = FUTEX_PRIVATE_FLAG;
86 k_futex_waitv(waiter, 1, 0, 0, 0);
87 printf("futex_waitv([{val=0, uaddr=%p, flags=%s}], 1, 0, NULL"
88 ", CLOCK_REALTIME) = %s\n",
89 futex, "FUTEX_PRIVATE_FLAG", errstr);
90
91 waiter->flags = FUTEX_32;
92 k_futex_waitv(waiter, 2, 0, 0, 1);
93 printf("futex_waitv([{val=0, uaddr=%p, flags=%s}, ... /* %p */], 2, 0, NULL"
94 ", CLOCK_MONOTONIC) = %s\n",
95 futex, "FUTEX_32", waiter + 1, errstr);
96
97 waiter->flags = FUTEX_32|FUTEX_PRIVATE_FLAG;
98 k_futex_waitv(waiter, 1, 0, ts, 1);
99 printf("futex_waitv([{val=0, uaddr=%p, flags=%s}], 1, 0"
100 ", {tv_sec=1, tv_nsec=2}, CLOCK_MONOTONIC) = %s\n",
101 futex, "FUTEX_32|FUTEX_PRIVATE_FLAG", errstr);
102
103 unsigned int nr = FUTEX_WAITV_MAX + 1;
104 uint32_t * const futexes = tail_alloc(nr * sizeof(*futexes));
105 struct futex_waitv * const waiters = tail_alloc(nr * sizeof(*waiters));
106 for (unsigned int i = 0; i < nr; ++i) {
107 futexes[i] = i;
108 waiters[i].val = i;
109 waiters[i].uaddr = (uintptr_t) &futexes[i];
110 waiters[i].flags = FUTEX_32|FUTEX_PRIVATE_FLAG;
111 waiters[i].__reserved = 0;
112 }
113 k_futex_waitv(waiters, nr, 0, ts, 1);
114 printf("futex_waitv([");
115 for (unsigned int i = 0; i < FUTEX_WAITV_MAX; ++i) {
116 printf("%s{val=%#x, uaddr=%p, flags=%s}",
117 i ? ", " : "",
118 i, &futexes[i], "FUTEX_32|FUTEX_PRIVATE_FLAG");
119 }
120 printf(", ...], %u, 0, {tv_sec=1, tv_nsec=2}, CLOCK_MONOTONIC) = %s\n",
121 nr, errstr);
122
123 nr = FUTEX_WAITV_MAX;
124 k_futex_waitv(waiters + 1, nr, 0, ts, 1);
125 printf("futex_waitv([");
126 for (unsigned int i = 0; i < FUTEX_WAITV_MAX; ++i) {
127 printf("%s{val=%#x, uaddr=%p, flags=%s}",
128 i ? ", " : "",
129 i + 1, &futexes[i + 1], "FUTEX_32|FUTEX_PRIVATE_FLAG");
130 }
131 printf("], %u, 0, {tv_sec=1, tv_nsec=2}, CLOCK_MONOTONIC) = %s\n",
132 nr, errstr);
133
134 puts("+++ exited with 0 +++");
135 return 0;
136 }