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 13 #include "futextest.h" 14 #include "kselftest_harness.h" 15 16 #define timeout_ns 30000000 17 #define WAKE_WAIT_US 10000 18 #define SHM_PATH "futex_shm_file" 19 20 void *futex; 21 22 static void *waiterfn(void *arg) 23 { 24 struct timespec to; 25 unsigned int flags = 0; 26 27 if (arg) 28 flags = *((unsigned int *) arg); 29 30 to.tv_sec = 0; 31 to.tv_nsec = timeout_ns; 32 33 if (futex_wait(futex, 0, &to, flags)) 34 printf("waiter failed errno %d\n", errno); 35 36 return NULL; 37 } 38 39 TEST(private_futex) 40 { 41 unsigned int flags = FUTEX_PRIVATE_FLAG; 42 u_int32_t f_private = 0; 43 pthread_t waiter; 44 int res; 45 46 futex = &f_private; 47 48 /* Testing a private futex */ 49 ksft_print_dbg_msg("Calling private futex_wait on futex: %p\n", futex); 50 if (pthread_create(&waiter, NULL, waiterfn, (void *) &flags)) 51 ksft_exit_fail_msg("pthread_create failed\n"); 52 53 usleep(WAKE_WAIT_US); 54 55 ksft_print_dbg_msg("Calling private futex_wake on futex: %p\n", futex); 56 res = futex_wake(futex, 1, FUTEX_PRIVATE_FLAG); 57 if (res != 1) { 58 ksft_test_result_fail("futex_wake private returned: %d %s\n", 59 errno, strerror(errno)); 60 } else { 61 ksft_test_result_pass("futex_wake private succeeds\n"); 62 } 63 } 64 65 TEST(anon_page) 66 { 67 u_int32_t *shared_data; 68 pthread_t waiter; 69 int res, shm_id; 70 71 /* Testing an anon page shared memory */ 72 shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); 73 if (shm_id < 0) { 74 if (errno == ENOSYS) 75 ksft_exit_skip("shmget syscall not supported\n"); 76 perror("shmget"); 77 exit(1); 78 } 79 80 shared_data = shmat(shm_id, NULL, 0); 81 82 *shared_data = 0; 83 futex = shared_data; 84 85 ksft_print_dbg_msg("Calling shared (page anon) futex_wait on futex: %p\n", futex); 86 if (pthread_create(&waiter, NULL, waiterfn, NULL)) 87 ksft_exit_fail_msg("pthread_create failed\n"); 88 89 usleep(WAKE_WAIT_US); 90 91 ksft_print_dbg_msg("Calling shared (page anon) futex_wake on futex: %p\n", futex); 92 res = futex_wake(futex, 1, 0); 93 if (res != 1) { 94 ksft_test_result_fail("futex_wake shared (page anon) returned: %d %s\n", 95 errno, strerror(errno)); 96 } else { 97 ksft_test_result_pass("futex_wake shared (page anon) succeeds\n"); 98 } 99 100 shmdt(shared_data); 101 } 102 103 TEST(file_backed) 104 { 105 u_int32_t f_private = 0; 106 pthread_t waiter; 107 int res, fd; 108 void *shm; 109 110 /* Testing a file backed shared memory */ 111 fd = open(SHM_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 112 if (fd < 0) 113 ksft_exit_fail_msg("open\n"); 114 115 if (ftruncate(fd, sizeof(f_private))) 116 ksft_exit_fail_msg("ftruncate\n"); 117 118 shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 119 if (shm == MAP_FAILED) 120 ksft_exit_fail_msg("mmap\n"); 121 122 memcpy(shm, &f_private, sizeof(f_private)); 123 124 futex = shm; 125 126 ksft_print_dbg_msg("Calling shared (file backed) futex_wait on futex: %p\n", futex); 127 if (pthread_create(&waiter, NULL, waiterfn, NULL)) 128 ksft_exit_fail_msg("pthread_create failed\n"); 129 130 usleep(WAKE_WAIT_US); 131 132 ksft_print_dbg_msg("Calling shared (file backed) futex_wake on futex: %p\n", futex); 133 res = futex_wake(shm, 1, 0); 134 if (res != 1) { 135 ksft_test_result_fail("futex_wake shared (file backed) returned: %d %s\n", 136 errno, strerror(errno)); 137 } else { 138 ksft_test_result_pass("futex_wake shared (file backed) succeeds\n"); 139 } 140 141 munmap(shm, sizeof(f_private)); 142 remove(SHM_PATH); 143 close(fd); 144 } 145 146 TEST_HARNESS_MAIN 147