1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright Collabora Ltd., 2021 4 * 5 * futex cmp requeue test by André Almeida <andrealmeid@collabora.com> 6 */ 7 8 #include <pthread.h> 9 #include <sys/shm.h> 10 #include <sys/mman.h> 11 #include <fcntl.h> 12 #include "logging.h" 13 #include "futextest.h" 14 15 #define TEST_NAME "futex-wait" 16 #define timeout_ns 30000000 17 #define WAKE_WAIT_US 10000 18 #define SHM_PATH "futex_shm_file" 19 20 void *futex; 21 22 void usage(char *prog) 23 { 24 printf("Usage: %s\n", prog); 25 printf(" -c Use color\n"); 26 printf(" -h Display this help message\n"); 27 printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 28 VQUIET, VCRITICAL, VINFO); 29 } 30 31 static void *waiterfn(void *arg) 32 { 33 struct timespec to; 34 unsigned int flags = 0; 35 36 if (arg) 37 flags = *((unsigned int *) arg); 38 39 to.tv_sec = 0; 40 to.tv_nsec = timeout_ns; 41 42 if (futex_wait(futex, 0, &to, flags)) 43 printf("waiter failed errno %d\n", errno); 44 45 return NULL; 46 } 47 48 int main(int argc, char *argv[]) 49 { 50 int res, ret = RET_PASS, fd, c, shm_id; 51 u_int32_t f_private = 0, *shared_data; 52 unsigned int flags = FUTEX_PRIVATE_FLAG; 53 pthread_t waiter; 54 void *shm; 55 56 futex = &f_private; 57 58 while ((c = getopt(argc, argv, "cht:v:")) != -1) { 59 switch (c) { 60 case 'c': 61 log_color(1); 62 break; 63 case 'h': 64 usage(basename(argv[0])); 65 exit(0); 66 case 'v': 67 log_verbosity(atoi(optarg)); 68 break; 69 default: 70 usage(basename(argv[0])); 71 exit(1); 72 } 73 } 74 75 ksft_print_header(); 76 ksft_set_plan(3); 77 ksft_print_msg("%s: Test futex_wait\n", basename(argv[0])); 78 79 /* Testing a private futex */ 80 info("Calling private futex_wait on futex: %p\n", futex); 81 if (pthread_create(&waiter, NULL, waiterfn, (void *) &flags)) 82 error("pthread_create failed\n", errno); 83 84 usleep(WAKE_WAIT_US); 85 86 info("Calling private futex_wake on futex: %p\n", futex); 87 res = futex_wake(futex, 1, FUTEX_PRIVATE_FLAG); 88 if (res != 1) { 89 ksft_test_result_fail("futex_wake private returned: %d %s\n", 90 errno, strerror(errno)); 91 ret = RET_FAIL; 92 } else { 93 ksft_test_result_pass("futex_wake private succeeds\n"); 94 } 95 96 /* Testing an anon page shared memory */ 97 shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); 98 if (shm_id < 0) { 99 perror("shmget"); 100 exit(1); 101 } 102 103 shared_data = shmat(shm_id, NULL, 0); 104 105 *shared_data = 0; 106 futex = shared_data; 107 108 info("Calling shared (page anon) futex_wait on futex: %p\n", futex); 109 if (pthread_create(&waiter, NULL, waiterfn, NULL)) 110 error("pthread_create failed\n", errno); 111 112 usleep(WAKE_WAIT_US); 113 114 info("Calling shared (page anon) futex_wake on futex: %p\n", futex); 115 res = futex_wake(futex, 1, 0); 116 if (res != 1) { 117 ksft_test_result_fail("futex_wake shared (page anon) returned: %d %s\n", 118 errno, strerror(errno)); 119 ret = RET_FAIL; 120 } else { 121 ksft_test_result_pass("futex_wake shared (page anon) succeeds\n"); 122 } 123 124 125 /* Testing a file backed shared memory */ 126 fd = open(SHM_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 127 if (fd < 0) { 128 perror("open"); 129 exit(1); 130 } 131 132 if (ftruncate(fd, sizeof(f_private))) { 133 perror("ftruncate"); 134 exit(1); 135 } 136 137 shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 138 if (shm == MAP_FAILED) { 139 perror("mmap"); 140 exit(1); 141 } 142 143 memcpy(shm, &f_private, sizeof(f_private)); 144 145 futex = shm; 146 147 info("Calling shared (file backed) futex_wait on futex: %p\n", futex); 148 if (pthread_create(&waiter, NULL, waiterfn, NULL)) 149 error("pthread_create failed\n", errno); 150 151 usleep(WAKE_WAIT_US); 152 153 info("Calling shared (file backed) futex_wake on futex: %p\n", futex); 154 res = futex_wake(shm, 1, 0); 155 if (res != 1) { 156 ksft_test_result_fail("futex_wake shared (file backed) returned: %d %s\n", 157 errno, strerror(errno)); 158 ret = RET_FAIL; 159 } else { 160 ksft_test_result_pass("futex_wake shared (file backed) succeeds\n"); 161 } 162 163 /* Freeing resources */ 164 shmdt(shared_data); 165 munmap(shm, sizeof(f_private)); 166 remove(SHM_PATH); 167 close(fd); 168 169 ksft_print_cnts(); 170 return ret; 171 } 172