Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: futex: Add futex wait test

There are three different strategies to uniquely identify a futex in the
kernel:

- Private futexes: uses the pointer to mm_struct and the page address

- Shared futexes: checks if the page containing the address is a PageAnon:
- If it is, uses the same data as a private futexes
- If it isn't, uses an inode sequence number from struct inode and
the page's index

Create a selftest to check those three paths and basic wait/wake
mechanism.

Signed-off-by: André Almeida <andrealmeid@collabora.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Davidlohr Bueso <dbueso@suse.de>
Link: https://lore.kernel.org/r/20210531165036.41468-2-andrealmeid@collabora.com

authored by

André Almeida and committed by
Thomas Gleixner
c3d12858 149876d9

+177 -1
+1
tools/testing/selftests/futex/functional/.gitignore
··· 6 6 futex_wait_timeout 7 7 futex_wait_uninitialized_heap 8 8 futex_wait_wouldblock 9 + futex_wait
+2 -1
tools/testing/selftests/futex/functional/Makefile
··· 15 15 futex_requeue_pi_signal_restart \ 16 16 futex_requeue_pi_mismatched_ops \ 17 17 futex_wait_uninitialized_heap \ 18 - futex_wait_private_mapped_file 18 + futex_wait_private_mapped_file \ 19 + futex_wait 19 20 20 21 TEST_PROGS := run.sh 21 22
+171
tools/testing/selftests/futex/functional/futex_wait.c
··· 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 + }
+3
tools/testing/selftests/futex/functional/run.sh
··· 73 73 echo 74 74 ./futex_wait_uninitialized_heap $COLOR 75 75 ./futex_wait_private_mapped_file $COLOR 76 + 77 + echo 78 + ./futex_wait $COLOR