Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * futex_waitv() test by André Almeida <andrealmeid@collabora.com>
4 *
5 * Copyright 2021 Collabora Ltd.
6 */
7
8#include <errno.h>
9#include <error.h>
10#include <getopt.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <time.h>
15#include <pthread.h>
16#include <stdint.h>
17#include <sys/shm.h>
18
19#include "futextest.h"
20#include "futex2test.h"
21#include "kselftest_harness.h"
22
23#define WAKE_WAIT_US 10000
24#define NR_FUTEXES 30
25static struct futex_waitv waitv[NR_FUTEXES];
26u_int32_t futexes[NR_FUTEXES] = {0};
27
28void *waiterfn(void *arg)
29{
30 struct timespec to;
31 int res;
32
33 /* setting absolute timeout for futex2 */
34 if (clock_gettime(CLOCK_MONOTONIC, &to))
35 ksft_exit_fail_msg("gettime64 failed\n");
36
37 to.tv_sec++;
38
39 res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
40 if (res < 0) {
41 ksft_test_result_fail("futex_waitv returned: %d %s\n",
42 errno, strerror(errno));
43 } else if (res != NR_FUTEXES - 1) {
44 ksft_test_result_fail("futex_waitv returned: %d, expecting %d\n",
45 res, NR_FUTEXES - 1);
46 }
47
48 return NULL;
49}
50
51TEST(private_waitv)
52{
53 pthread_t waiter;
54 int res, i;
55
56 for (i = 0; i < NR_FUTEXES; i++) {
57 waitv[i].uaddr = (uintptr_t)&futexes[i];
58 waitv[i].flags = FUTEX_32 | FUTEX_PRIVATE_FLAG;
59 waitv[i].val = 0;
60 waitv[i].__reserved = 0;
61 }
62
63 /* Private waitv */
64 if (pthread_create(&waiter, NULL, waiterfn, NULL))
65 ksft_exit_fail_msg("pthread_create failed\n");
66
67 usleep(WAKE_WAIT_US);
68
69 res = futex_wake(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), 1, FUTEX_PRIVATE_FLAG);
70 if (res != 1) {
71 ksft_test_result_fail("futex_wake private returned: %d %s\n",
72 res ? errno : res,
73 res ? strerror(errno) : "");
74 } else {
75 ksft_test_result_pass("futex_waitv private\n");
76 }
77}
78
79TEST(shared_waitv)
80{
81 pthread_t waiter;
82 int res, i;
83
84 /* Shared waitv */
85 for (i = 0; i < NR_FUTEXES; i++) {
86 int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
87
88 if (shm_id < 0) {
89 if (errno == ENOSYS)
90 ksft_exit_skip("shmget syscall not supported\n");
91 perror("shmget");
92 exit(1);
93 }
94
95 unsigned int *shared_data = shmat(shm_id, NULL, 0);
96
97 *shared_data = 0;
98 waitv[i].uaddr = (uintptr_t)shared_data;
99 waitv[i].flags = FUTEX_32;
100 waitv[i].val = 0;
101 waitv[i].__reserved = 0;
102 }
103
104 if (pthread_create(&waiter, NULL, waiterfn, NULL))
105 ksft_exit_fail_msg("pthread_create failed\n");
106
107 usleep(WAKE_WAIT_US);
108
109 res = futex_wake(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), 1, 0);
110 if (res != 1) {
111 ksft_test_result_fail("futex_wake shared returned: %d %s\n",
112 res ? errno : res,
113 res ? strerror(errno) : "");
114 } else {
115 ksft_test_result_pass("futex_waitv shared\n");
116 }
117
118 for (i = 0; i < NR_FUTEXES; i++)
119 shmdt(u64_to_ptr(waitv[i].uaddr));
120}
121
122TEST(invalid_flag)
123{
124 struct timespec to;
125 int res;
126
127 /* Testing a waiter without FUTEX_32 flag */
128 waitv[0].flags = FUTEX_PRIVATE_FLAG;
129
130 if (clock_gettime(CLOCK_MONOTONIC, &to))
131 ksft_exit_fail_msg("gettime64 failed\n");
132
133 to.tv_sec++;
134
135 res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
136 if (res == EINVAL) {
137 ksft_test_result_fail("futex_waitv private returned: %d %s\n",
138 res ? errno : res,
139 res ? strerror(errno) : "");
140 } else {
141 ksft_test_result_pass("futex_waitv without FUTEX_32\n");
142 }
143}
144
145TEST(unaligned_address)
146{
147 struct timespec to;
148 int res;
149
150 /* Testing a waiter with an unaligned address */
151 waitv[0].flags = FUTEX_PRIVATE_FLAG | FUTEX_32;
152 waitv[0].uaddr = 1;
153
154 if (clock_gettime(CLOCK_MONOTONIC, &to))
155 ksft_exit_fail_msg("gettime64 failed\n");
156
157 to.tv_sec++;
158
159 res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
160 if (res == EINVAL) {
161 ksft_test_result_fail("futex_wake private returned: %d %s\n",
162 res ? errno : res,
163 res ? strerror(errno) : "");
164 } else {
165 ksft_test_result_pass("futex_waitv with an unaligned address\n");
166 }
167}
168
169TEST(null_address)
170{
171 struct timespec to;
172 int res;
173
174 /* Testing a NULL address for waiters.uaddr */
175 waitv[0].uaddr = 0x00000000;
176
177 if (clock_gettime(CLOCK_MONOTONIC, &to))
178 ksft_exit_fail_msg("gettime64 failed\n");
179
180 to.tv_sec++;
181
182 res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
183 if (res == EINVAL) {
184 ksft_test_result_fail("futex_waitv private returned: %d %s\n",
185 res ? errno : res,
186 res ? strerror(errno) : "");
187 } else {
188 ksft_test_result_pass("futex_waitv NULL address in waitv.uaddr\n");
189 }
190
191 /* Testing a NULL address for *waiters */
192 if (clock_gettime(CLOCK_MONOTONIC, &to))
193 ksft_exit_fail_msg("gettime64 failed\n");
194
195 to.tv_sec++;
196
197 res = futex_waitv(NULL, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
198 if (res == EINVAL) {
199 ksft_test_result_fail("futex_waitv private returned: %d %s\n",
200 res ? errno : res,
201 res ? strerror(errno) : "");
202 } else {
203 ksft_test_result_pass("futex_waitv NULL address in *waiters\n");
204 }
205}
206
207TEST(invalid_clockid)
208{
209 struct timespec to;
210 int res;
211
212 /* Testing an invalid clockid */
213 if (clock_gettime(CLOCK_MONOTONIC, &to))
214 ksft_exit_fail_msg("gettime64 failed\n");
215
216 to.tv_sec++;
217
218 res = futex_waitv(NULL, NR_FUTEXES, 0, &to, CLOCK_TAI);
219 if (res == EINVAL) {
220 ksft_test_result_fail("futex_waitv private returned: %d %s\n",
221 res ? errno : res,
222 res ? strerror(errno) : "");
223 } else {
224 ksft_test_result_pass("futex_waitv invalid clockid\n");
225 }
226}
227
228TEST_HARNESS_MAIN