238 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 1000024#define NR_FUTEXES 3025static struct futex_waitv waitv[NR_FUTEXES];26u_int32_t futexes[NR_FUTEXES] = {0};27 28void 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 37void *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 60int 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