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 #include "futextest.h" 19 #include "futex2test.h" 20 #include "logging.h" 21 22 #define TEST_NAME "futex-wait" 23 #define WAKE_WAIT_US 10000 24 #define NR_FUTEXES 30 25 static struct futex_waitv waitv[NR_FUTEXES]; 26 u_int32_t futexes[NR_FUTEXES] = {0}; 27 28 void usage(char *prog) 29 { 30 printf("Usage: %s\n", prog); 31 printf(" -c Use color\n"); 32 printf(" -h Display this help message\n"); 33 printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 34 VQUIET, VCRITICAL, VINFO); 35 } 36 37 void *waiterfn(void *arg) 38 { 39 struct timespec to; 40 int res; 41 42 /* setting absolute timeout for futex2 */ 43 if (clock_gettime(CLOCK_MONOTONIC, &to)) 44 error("gettime64 failed\n", errno); 45 46 to.tv_sec++; 47 48 res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC); 49 if (res < 0) { 50 ksft_test_result_fail("futex_waitv returned: %d %s\n", 51 errno, strerror(errno)); 52 } else if (res != NR_FUTEXES - 1) { 53 ksft_test_result_fail("futex_waitv returned: %d, expecting %d\n", 54 res, NR_FUTEXES - 1); 55 } 56 57 return NULL; 58 } 59 60 int main(int argc, char *argv[]) 61 { 62 pthread_t waiter; 63 int res, ret = RET_PASS; 64 struct timespec to; 65 int c, i; 66 67 while ((c = getopt(argc, argv, "cht:v:")) != -1) { 68 switch (c) { 69 case 'c': 70 log_color(1); 71 break; 72 case 'h': 73 usage(basename(argv[0])); 74 exit(0); 75 case 'v': 76 log_verbosity(atoi(optarg)); 77 break; 78 default: 79 usage(basename(argv[0])); 80 exit(1); 81 } 82 } 83 84 ksft_print_header(); 85 ksft_set_plan(7); 86 ksft_print_msg("%s: Test FUTEX_WAITV\n", 87 basename(argv[0])); 88 89 for (i = 0; i < NR_FUTEXES; i++) { 90 waitv[i].uaddr = (uintptr_t)&futexes[i]; 91 waitv[i].flags = FUTEX_32 | FUTEX_PRIVATE_FLAG; 92 waitv[i].val = 0; 93 waitv[i].__reserved = 0; 94 } 95 96 /* Private waitv */ 97 if (pthread_create(&waiter, NULL, waiterfn, NULL)) 98 error("pthread_create failed\n", errno); 99 100 usleep(WAKE_WAIT_US); 101 102 res = futex_wake(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), 1, FUTEX_PRIVATE_FLAG); 103 if (res != 1) { 104 ksft_test_result_fail("futex_wake private returned: %d %s\n", 105 res ? errno : res, 106 res ? strerror(errno) : ""); 107 ret = RET_FAIL; 108 } else { 109 ksft_test_result_pass("futex_waitv private\n"); 110 } 111 112 /* Shared waitv */ 113 for (i = 0; i < NR_FUTEXES; i++) { 114 int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); 115 116 if (shm_id < 0) { 117 perror("shmget"); 118 exit(1); 119 } 120 121 unsigned int *shared_data = shmat(shm_id, NULL, 0); 122 123 *shared_data = 0; 124 waitv[i].uaddr = (uintptr_t)shared_data; 125 waitv[i].flags = FUTEX_32; 126 waitv[i].val = 0; 127 waitv[i].__reserved = 0; 128 } 129 130 if (pthread_create(&waiter, NULL, waiterfn, NULL)) 131 error("pthread_create failed\n", errno); 132 133 usleep(WAKE_WAIT_US); 134 135 res = futex_wake(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), 1, 0); 136 if (res != 1) { 137 ksft_test_result_fail("futex_wake shared returned: %d %s\n", 138 res ? errno : res, 139 res ? strerror(errno) : ""); 140 ret = RET_FAIL; 141 } else { 142 ksft_test_result_pass("futex_waitv shared\n"); 143 } 144 145 for (i = 0; i < NR_FUTEXES; i++) 146 shmdt(u64_to_ptr(waitv[i].uaddr)); 147 148 /* Testing a waiter without FUTEX_32 flag */ 149 waitv[0].flags = FUTEX_PRIVATE_FLAG; 150 151 if (clock_gettime(CLOCK_MONOTONIC, &to)) 152 error("gettime64 failed\n", errno); 153 154 to.tv_sec++; 155 156 res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC); 157 if (res == EINVAL) { 158 ksft_test_result_fail("futex_waitv private returned: %d %s\n", 159 res ? errno : res, 160 res ? strerror(errno) : ""); 161 ret = RET_FAIL; 162 } else { 163 ksft_test_result_pass("futex_waitv without FUTEX_32\n"); 164 } 165 166 /* Testing a waiter with an unaligned address */ 167 waitv[0].flags = FUTEX_PRIVATE_FLAG | FUTEX_32; 168 waitv[0].uaddr = 1; 169 170 if (clock_gettime(CLOCK_MONOTONIC, &to)) 171 error("gettime64 failed\n", errno); 172 173 to.tv_sec++; 174 175 res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC); 176 if (res == EINVAL) { 177 ksft_test_result_fail("futex_wake private returned: %d %s\n", 178 res ? errno : res, 179 res ? strerror(errno) : ""); 180 ret = RET_FAIL; 181 } else { 182 ksft_test_result_pass("futex_waitv with an unaligned address\n"); 183 } 184 185 /* Testing a NULL address for waiters.uaddr */ 186 waitv[0].uaddr = 0x00000000; 187 188 if (clock_gettime(CLOCK_MONOTONIC, &to)) 189 error("gettime64 failed\n", errno); 190 191 to.tv_sec++; 192 193 res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC); 194 if (res == EINVAL) { 195 ksft_test_result_fail("futex_waitv private returned: %d %s\n", 196 res ? errno : res, 197 res ? strerror(errno) : ""); 198 ret = RET_FAIL; 199 } else { 200 ksft_test_result_pass("futex_waitv NULL address in waitv.uaddr\n"); 201 } 202 203 /* Testing a NULL address for *waiters */ 204 if (clock_gettime(CLOCK_MONOTONIC, &to)) 205 error("gettime64 failed\n", errno); 206 207 to.tv_sec++; 208 209 res = futex_waitv(NULL, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC); 210 if (res == EINVAL) { 211 ksft_test_result_fail("futex_waitv private returned: %d %s\n", 212 res ? errno : res, 213 res ? strerror(errno) : ""); 214 ret = RET_FAIL; 215 } else { 216 ksft_test_result_pass("futex_waitv NULL address in *waiters\n"); 217 } 218 219 /* Testing an invalid clockid */ 220 if (clock_gettime(CLOCK_MONOTONIC, &to)) 221 error("gettime64 failed\n", errno); 222 223 to.tv_sec++; 224 225 res = futex_waitv(NULL, NR_FUTEXES, 0, &to, CLOCK_TAI); 226 if (res == EINVAL) { 227 ksft_test_result_fail("futex_waitv private returned: %d %s\n", 228 res ? errno : res, 229 res ? strerror(errno) : ""); 230 ret = RET_FAIL; 231 } else { 232 ksft_test_result_pass("futex_waitv invalid clockid\n"); 233 } 234 235 ksft_print_cnts(); 236 return ret; 237 } 238