162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright Collabora Ltd., 2021 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * futex cmp requeue test by André Almeida <andrealmeid@collabora.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <pthread.h> 962306a36Sopenharmony_ci#include <sys/shm.h> 1062306a36Sopenharmony_ci#include <sys/mman.h> 1162306a36Sopenharmony_ci#include <fcntl.h> 1262306a36Sopenharmony_ci#include "logging.h" 1362306a36Sopenharmony_ci#include "futextest.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define TEST_NAME "futex-wait" 1662306a36Sopenharmony_ci#define timeout_ns 30000000 1762306a36Sopenharmony_ci#define WAKE_WAIT_US 10000 1862306a36Sopenharmony_ci#define SHM_PATH "futex_shm_file" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_civoid *futex; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_civoid usage(char *prog) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci printf("Usage: %s\n", prog); 2562306a36Sopenharmony_ci printf(" -c Use color\n"); 2662306a36Sopenharmony_ci printf(" -h Display this help message\n"); 2762306a36Sopenharmony_ci printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 2862306a36Sopenharmony_ci VQUIET, VCRITICAL, VINFO); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void *waiterfn(void *arg) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct timespec to; 3462306a36Sopenharmony_ci unsigned int flags = 0; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (arg) 3762306a36Sopenharmony_ci flags = *((unsigned int *) arg); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci to.tv_sec = 0; 4062306a36Sopenharmony_ci to.tv_nsec = timeout_ns; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (futex_wait(futex, 0, &to, flags)) 4362306a36Sopenharmony_ci printf("waiter failed errno %d\n", errno); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci return NULL; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ciint main(int argc, char *argv[]) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci int res, ret = RET_PASS, fd, c, shm_id; 5162306a36Sopenharmony_ci u_int32_t f_private = 0, *shared_data; 5262306a36Sopenharmony_ci unsigned int flags = FUTEX_PRIVATE_FLAG; 5362306a36Sopenharmony_ci pthread_t waiter; 5462306a36Sopenharmony_ci void *shm; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci futex = &f_private; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci while ((c = getopt(argc, argv, "cht:v:")) != -1) { 5962306a36Sopenharmony_ci switch (c) { 6062306a36Sopenharmony_ci case 'c': 6162306a36Sopenharmony_ci log_color(1); 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci case 'h': 6462306a36Sopenharmony_ci usage(basename(argv[0])); 6562306a36Sopenharmony_ci exit(0); 6662306a36Sopenharmony_ci case 'v': 6762306a36Sopenharmony_ci log_verbosity(atoi(optarg)); 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci default: 7062306a36Sopenharmony_ci usage(basename(argv[0])); 7162306a36Sopenharmony_ci exit(1); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci ksft_print_header(); 7662306a36Sopenharmony_ci ksft_set_plan(3); 7762306a36Sopenharmony_ci ksft_print_msg("%s: Test futex_wait\n", basename(argv[0])); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* Testing a private futex */ 8062306a36Sopenharmony_ci info("Calling private futex_wait on futex: %p\n", futex); 8162306a36Sopenharmony_ci if (pthread_create(&waiter, NULL, waiterfn, (void *) &flags)) 8262306a36Sopenharmony_ci error("pthread_create failed\n", errno); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci usleep(WAKE_WAIT_US); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci info("Calling private futex_wake on futex: %p\n", futex); 8762306a36Sopenharmony_ci res = futex_wake(futex, 1, FUTEX_PRIVATE_FLAG); 8862306a36Sopenharmony_ci if (res != 1) { 8962306a36Sopenharmony_ci ksft_test_result_fail("futex_wake private returned: %d %s\n", 9062306a36Sopenharmony_ci errno, strerror(errno)); 9162306a36Sopenharmony_ci ret = RET_FAIL; 9262306a36Sopenharmony_ci } else { 9362306a36Sopenharmony_ci ksft_test_result_pass("futex_wake private succeeds\n"); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* Testing an anon page shared memory */ 9762306a36Sopenharmony_ci shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); 9862306a36Sopenharmony_ci if (shm_id < 0) { 9962306a36Sopenharmony_ci perror("shmget"); 10062306a36Sopenharmony_ci exit(1); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci shared_data = shmat(shm_id, NULL, 0); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci *shared_data = 0; 10662306a36Sopenharmony_ci futex = shared_data; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci info("Calling shared (page anon) futex_wait on futex: %p\n", futex); 10962306a36Sopenharmony_ci if (pthread_create(&waiter, NULL, waiterfn, NULL)) 11062306a36Sopenharmony_ci error("pthread_create failed\n", errno); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci usleep(WAKE_WAIT_US); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci info("Calling shared (page anon) futex_wake on futex: %p\n", futex); 11562306a36Sopenharmony_ci res = futex_wake(futex, 1, 0); 11662306a36Sopenharmony_ci if (res != 1) { 11762306a36Sopenharmony_ci ksft_test_result_fail("futex_wake shared (page anon) returned: %d %s\n", 11862306a36Sopenharmony_ci errno, strerror(errno)); 11962306a36Sopenharmony_ci ret = RET_FAIL; 12062306a36Sopenharmony_ci } else { 12162306a36Sopenharmony_ci ksft_test_result_pass("futex_wake shared (page anon) succeeds\n"); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Testing a file backed shared memory */ 12662306a36Sopenharmony_ci fd = open(SHM_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 12762306a36Sopenharmony_ci if (fd < 0) { 12862306a36Sopenharmony_ci perror("open"); 12962306a36Sopenharmony_ci exit(1); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (ftruncate(fd, sizeof(f_private))) { 13362306a36Sopenharmony_ci perror("ftruncate"); 13462306a36Sopenharmony_ci exit(1); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 13862306a36Sopenharmony_ci if (shm == MAP_FAILED) { 13962306a36Sopenharmony_ci perror("mmap"); 14062306a36Sopenharmony_ci exit(1); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci memcpy(shm, &f_private, sizeof(f_private)); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci futex = shm; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci info("Calling shared (file backed) futex_wait on futex: %p\n", futex); 14862306a36Sopenharmony_ci if (pthread_create(&waiter, NULL, waiterfn, NULL)) 14962306a36Sopenharmony_ci error("pthread_create failed\n", errno); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci usleep(WAKE_WAIT_US); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci info("Calling shared (file backed) futex_wake on futex: %p\n", futex); 15462306a36Sopenharmony_ci res = futex_wake(shm, 1, 0); 15562306a36Sopenharmony_ci if (res != 1) { 15662306a36Sopenharmony_ci ksft_test_result_fail("futex_wake shared (file backed) returned: %d %s\n", 15762306a36Sopenharmony_ci errno, strerror(errno)); 15862306a36Sopenharmony_ci ret = RET_FAIL; 15962306a36Sopenharmony_ci } else { 16062306a36Sopenharmony_ci ksft_test_result_pass("futex_wake shared (file backed) succeeds\n"); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* Freeing resources */ 16462306a36Sopenharmony_ci shmdt(shared_data); 16562306a36Sopenharmony_ci munmap(shm, sizeof(f_private)); 16662306a36Sopenharmony_ci remove(SHM_PATH); 16762306a36Sopenharmony_ci close(fd); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci ksft_print_cnts(); 17062306a36Sopenharmony_ci return ret; 17162306a36Sopenharmony_ci} 172