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 <fcntl.h> 9 #include <pthread.h> 10 #include <stdlib.h> 11 #include <sys/shm.h> 12 #include <sys/mman.h> 13 14 #include "futextest.h" 15 #include "kselftest_harness.h" 16 17 #define timeout_ns 30000000 18 #define WAKE_WAIT_US 10000 19 #define SHM_PATH "futex_shm_file" 20 21 void *futex; 22 23 struct waiter_args { 24 struct __test_metadata *_metadata; 25 unsigned int flags; 26 }; 27 28 static void *waiterfn(void *arg) 29 { 30 struct waiter_args *args = (struct waiter_args *)arg; 31 struct __test_metadata *_metadata = args->_metadata; 32 struct timespec to; 33 int res; 34 35 to.tv_sec = 0; 36 to.tv_nsec = timeout_ns; 37 38 res = futex_wait(futex, 0, &to, args->flags); 39 if (res) { 40 EXPECT_EQ(res, 0) 41 TH_LOG("waiter failed errno %d: %s", errno, strerror(errno)); 42 } 43 44 free(args); 45 return NULL; 46 } 47 48 TEST(private_futex) 49 { 50 struct waiter_args *args = malloc(sizeof(*args)); 51 u_int32_t f_private = 0; 52 pthread_t waiter; 53 int res; 54 55 args->_metadata = _metadata; 56 args->flags = FUTEX_PRIVATE_FLAG; 57 futex = &f_private; 58 59 /* Testing a private futex */ 60 TH_LOG("Calling private futex_wait on futex: %p", futex); 61 ASSERT_EQ(pthread_create(&waiter, NULL, waiterfn, args), 0) 62 TH_LOG("pthread_create failed"); 63 64 usleep(WAKE_WAIT_US); 65 66 TH_LOG("Calling private futex_wake on futex: %p", futex); 67 res = futex_wake(futex, 1, FUTEX_PRIVATE_FLAG); 68 EXPECT_EQ(res, 1) 69 TH_LOG("futex_wake private returned: %d %s", res, res < 0 ? strerror(errno) : ""); 70 71 pthread_join(waiter, NULL); 72 } 73 74 TEST(anon_page) 75 { 76 struct waiter_args *args = malloc(sizeof(*args)); 77 u_int32_t *shared_data; 78 pthread_t waiter; 79 int res, shm_id; 80 81 args->_metadata = _metadata; 82 args->flags = 0; 83 84 /* Testing an anon page shared memory */ 85 shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); 86 if (shm_id < 0) { 87 if (errno == ENOSYS) { 88 free(args); 89 SKIP(return, "shmget syscall not supported"); 90 } 91 ASSERT_GE(shm_id, 0) 92 TH_LOG("shmget failed: %s", strerror(errno)); 93 } 94 95 shared_data = shmat(shm_id, NULL, 0); 96 if (shared_data == (void *)-1) { 97 free(args); 98 ASSERT_NE(shared_data, (void *)-1) 99 TH_LOG("shmat failed: %s", strerror(errno)); 100 } 101 102 *shared_data = 0; 103 futex = shared_data; 104 105 TH_LOG("Calling shared (page anon) futex_wait on futex: %p", futex); 106 ASSERT_EQ(pthread_create(&waiter, NULL, waiterfn, args), 0) 107 TH_LOG("pthread_create failed"); 108 109 usleep(WAKE_WAIT_US); 110 111 TH_LOG("Calling shared (page anon) futex_wake on futex: %p", futex); 112 res = futex_wake(futex, 1, 0); 113 EXPECT_EQ(res, 1) { 114 TH_LOG("futex_wake shared (page anon) returned: %d %s", 115 res, res < 0 ? strerror(errno) : ""); 116 } 117 118 pthread_join(waiter, NULL); 119 shmdt(shared_data); 120 } 121 122 TEST(file_backed) 123 { 124 struct waiter_args *args = malloc(sizeof(*args)); 125 u_int32_t f_private = 0; 126 pthread_t waiter; 127 int res, fd; 128 void *shm; 129 130 args->_metadata = _metadata; 131 args->flags = 0; 132 133 /* Testing a file backed shared memory */ 134 fd = open(SHM_PATH, O_RDWR | O_CREAT, 0600); 135 if (fd < 0) { 136 free(args); 137 ASSERT_GE(fd, 0) 138 TH_LOG("open failed: %s", strerror(errno)); 139 } 140 141 if (ftruncate(fd, sizeof(f_private))) { 142 free(args); 143 close(fd); 144 ASSERT_TRUE(0) 145 TH_LOG("ftruncate failed: %s", strerror(errno)); 146 } 147 148 shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 149 if (shm == MAP_FAILED) { 150 free(args); 151 close(fd); 152 ASSERT_NE(shm, MAP_FAILED) 153 TH_LOG("mmap failed: %s", strerror(errno)); 154 } 155 156 memcpy(shm, &f_private, sizeof(f_private)); 157 158 futex = shm; 159 160 TH_LOG("Calling shared (file backed) futex_wait on futex: %p", futex); 161 ASSERT_EQ(pthread_create(&waiter, NULL, waiterfn, args), 0) 162 TH_LOG("pthread_create failed"); 163 164 usleep(WAKE_WAIT_US); 165 166 TH_LOG("Calling shared (file backed) futex_wake on futex: %p", futex); 167 res = futex_wake(shm, 1, 0); 168 EXPECT_EQ(res, 1) { 169 TH_LOG("futex_wake shared (file backed) returned: %d %s", 170 res, res < 0 ? strerror(errno) : ""); 171 } 172 173 pthread_join(waiter, NULL); 174 munmap(shm, sizeof(f_private)); 175 remove(SHM_PATH); 176 close(fd); 177 } 178 179 TEST_HARNESS_MAIN 180