Path: blob/master/tools/testing/selftests/futex/functional/futex_wait_timeout.c
29271 views
// SPDX-License-Identifier: GPL-2.0-or-later1/******************************************************************************2*3* Copyright © International Business Machines Corp., 20094*5* DESCRIPTION6* Block on a futex and wait for timeout.7*8* AUTHOR9* Darren Hart <[email protected]>10*11* HISTORY12* 2009-Nov-6: Initial version by Darren Hart <[email protected]>13* 2021-Apr-26: More test cases by André Almeida <[email protected]>14*15*****************************************************************************/1617#include <pthread.h>1819#include "futextest.h"20#include "futex2test.h"21#include "../../kselftest_harness.h"2223static long timeout_ns = 100000; /* 100us default timeout */24static futex_t futex_pi;25static pthread_barrier_t barrier;2627/*28* Get a PI lock and hold it forever, so the main thread lock_pi will block29* and we can test the timeout30*/31void *get_pi_lock(void *arg)32{33int ret;34volatile futex_t lock = 0;3536ret = futex_lock_pi(&futex_pi, NULL, 0, 0);37if (ret != 0)38ksft_exit_fail_msg("futex_lock_pi failed\n");3940pthread_barrier_wait(&barrier);4142/* Blocks forever */43ret = futex_wait(&lock, 0, NULL, 0);44ksft_exit_fail_msg("futex_wait failed\n");4546return NULL;47}4849/*50* Check if the function returned the expected error51*/52static void test_timeout(int res, char *test_name, int err)53{54if (!res || errno != err) {55ksft_test_result_fail("%s returned %d\n", test_name,56res < 0 ? errno : res);57} else {58ksft_test_result_pass("%s succeeds\n", test_name);59}60}6162/*63* Calculate absolute timeout and correct overflow64*/65static int futex_get_abs_timeout(clockid_t clockid, struct timespec *to,66long timeout_ns)67{68if (clock_gettime(clockid, to))69ksft_exit_fail_msg("clock_gettime failed\n");7071to->tv_nsec += timeout_ns;7273if (to->tv_nsec >= 1000000000) {74to->tv_sec++;75to->tv_nsec -= 1000000000;76}7778return 0;79}8081TEST(wait_bitset)82{83futex_t f1 = FUTEX_INITIALIZER;84struct timespec to;85int res;8687/* initialize relative timeout */88to.tv_sec = 0;89to.tv_nsec = timeout_ns;9091res = futex_wait(&f1, f1, &to, 0);92test_timeout(res, "futex_wait relative", ETIMEDOUT);9394/* FUTEX_WAIT_BITSET with CLOCK_REALTIME */95if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))96ksft_test_result_error("get_time error");97res = futex_wait_bitset(&f1, f1, &to, 1, FUTEX_CLOCK_REALTIME);98test_timeout(res, "futex_wait_bitset realtime", ETIMEDOUT);99100/* FUTEX_WAIT_BITSET with CLOCK_MONOTONIC */101if (futex_get_abs_timeout(CLOCK_MONOTONIC, &to, timeout_ns))102ksft_test_result_error("get_time error");103res = futex_wait_bitset(&f1, f1, &to, 1, 0);104test_timeout(res, "futex_wait_bitset monotonic", ETIMEDOUT);105}106107TEST(requeue_pi)108{109futex_t f1 = FUTEX_INITIALIZER;110struct timespec to;111int res;112113/* FUTEX_WAIT_REQUEUE_PI with CLOCK_REALTIME */114if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))115ksft_test_result_error("get_time error");116res = futex_wait_requeue_pi(&f1, f1, &futex_pi, &to, FUTEX_CLOCK_REALTIME);117test_timeout(res, "futex_wait_requeue_pi realtime", ETIMEDOUT);118119/* FUTEX_WAIT_REQUEUE_PI with CLOCK_MONOTONIC */120if (futex_get_abs_timeout(CLOCK_MONOTONIC, &to, timeout_ns))121ksft_test_result_error("get_time error");122res = futex_wait_requeue_pi(&f1, f1, &futex_pi, &to, 0);123test_timeout(res, "futex_wait_requeue_pi monotonic", ETIMEDOUT);124125}126127TEST(lock_pi)128{129struct timespec to;130pthread_t thread;131int res;132133/* Create a thread that will lock forever so any waiter will timeout */134pthread_barrier_init(&barrier, NULL, 2);135pthread_create(&thread, NULL, get_pi_lock, NULL);136137/* Wait until the other thread calls futex_lock_pi() */138pthread_barrier_wait(&barrier);139pthread_barrier_destroy(&barrier);140141/*142* FUTEX_LOCK_PI with CLOCK_REALTIME143* Due to historical reasons, FUTEX_LOCK_PI supports only realtime144* clock, but requires the caller to not set CLOCK_REALTIME flag.145*146* If you call FUTEX_LOCK_PI with a monotonic clock, it'll be147* interpreted as a realtime clock, and (unless you mess your machine's148* time or your time machine) the monotonic clock value is always149* smaller than realtime and the syscall will timeout immediately.150*/151if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))152ksft_test_result_error("get_time error");153res = futex_lock_pi(&futex_pi, &to, 0, 0);154test_timeout(res, "futex_lock_pi realtime", ETIMEDOUT);155156/* Test operations that don't support FUTEX_CLOCK_REALTIME */157res = futex_lock_pi(&futex_pi, NULL, 0, FUTEX_CLOCK_REALTIME);158test_timeout(res, "futex_lock_pi invalid timeout flag", ENOSYS);159}160161TEST(waitv)162{163futex_t f1 = FUTEX_INITIALIZER;164struct futex_waitv waitv = {165.uaddr = (uintptr_t)&f1,166.val = f1,167.flags = FUTEX_32,168.__reserved = 0,169};170struct timespec to;171int res;172173/* futex_waitv with CLOCK_MONOTONIC */174if (futex_get_abs_timeout(CLOCK_MONOTONIC, &to, timeout_ns))175ksft_test_result_error("get_time error");176res = futex_waitv(&waitv, 1, 0, &to, CLOCK_MONOTONIC);177test_timeout(res, "futex_waitv monotonic", ETIMEDOUT);178179/* futex_waitv with CLOCK_REALTIME */180if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))181ksft_test_result_error("get_time error");182res = futex_waitv(&waitv, 1, 0, &to, CLOCK_REALTIME);183test_timeout(res, "futex_waitv realtime", ETIMEDOUT);184}185186TEST_HARNESS_MAIN187188189