File Index
Files and directories
Sign in
FILE

futex_wait_timeout.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/futex/functional/futex_wait_timeout.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/******************************************************************************
  3 *
  4 *   Copyright © International Business Machines  Corp., 2009
  5 *
  6 * DESCRIPTION
  7 *      Block on a futex and wait for timeout.
  8 *
  9 * AUTHOR
 10 *      Darren Hart <dvhart@linux.intel.com>
 11 *
 12 * HISTORY
 13 *      2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
 14 *      2021-Apr-26: More test cases by André Almeida <andrealmeid@collabora.com>
 15 *
 16 *****************************************************************************/
 17
 18#include <pthread.h>
 19
 20#include "futextest.h"
 21#include "futex2test.h"
 22#include "kselftest_harness.h"
 23
 24static long timeout_ns = 100000;	/* 100us default timeout */
 25static futex_t futex_pi;
 26static pthread_barrier_t barrier;
 27
 28/*
 29 * Get a PI lock and hold it forever, so the main thread lock_pi will block
 30 * and we can test the timeout
 31 */
 32void *get_pi_lock(void *arg)
 33{
 34	int ret;
 35	volatile futex_t lock = 0;
 36
 37	ret = futex_lock_pi(&futex_pi, NULL, 0, 0);
 38	if (ret != 0)
 39		ksft_exit_fail_msg("futex_lock_pi failed\n");
 40
 41	pthread_barrier_wait(&barrier);
 42
 43	/* Blocks forever */
 44	ret = futex_wait(&lock, 0, NULL, 0);
 45	ksft_exit_fail_msg("futex_wait failed\n");
 46
 47	return NULL;
 48}
 49
 50/*
 51 * Check if the function returned the expected error
 52 */
 53static void test_timeout(int res, char *test_name, int err)
 54{
 55	if (!res || errno != err) {
 56		ksft_test_result_fail("%s returned %d\n", test_name,
 57				      res < 0 ? errno : res);
 58	} else {
 59		ksft_test_result_pass("%s succeeds\n", test_name);
 60	}
 61}
 62
 63/*
 64 * Calculate absolute timeout and correct overflow
 65 */
 66static int futex_get_abs_timeout(clockid_t clockid, struct timespec *to,
 67				 long timeout_ns)
 68{
 69	if (clock_gettime(clockid, to))
 70		ksft_exit_fail_msg("clock_gettime failed\n");
 71
 72	to->tv_nsec += timeout_ns;
 73
 74	if (to->tv_nsec >= 1000000000) {
 75		to->tv_sec++;
 76		to->tv_nsec -= 1000000000;
 77	}
 78
 79	return 0;
 80}
 81
 82TEST(wait_bitset)
 83{
 84	futex_t f1 = FUTEX_INITIALIZER;
 85	struct timespec to;
 86	int res;
 87
 88	/* initialize relative timeout */
 89	to.tv_sec = 0;
 90	to.tv_nsec = timeout_ns;
 91
 92	res = futex_wait(&f1, f1, &to, 0);
 93	test_timeout(res, "futex_wait relative", ETIMEDOUT);
 94
 95	/* FUTEX_WAIT_BITSET with CLOCK_REALTIME */
 96	if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))
 97		ksft_test_result_error("get_time error");
 98	res = futex_wait_bitset(&f1, f1, &to, 1, FUTEX_CLOCK_REALTIME);
 99	test_timeout(res, "futex_wait_bitset realtime", ETIMEDOUT);
100
101	/* FUTEX_WAIT_BITSET with CLOCK_MONOTONIC */
102	if (futex_get_abs_timeout(CLOCK_MONOTONIC, &to, timeout_ns))
103		ksft_test_result_error("get_time error");
104	res = futex_wait_bitset(&f1, f1, &to, 1, 0);
105	test_timeout(res, "futex_wait_bitset monotonic", ETIMEDOUT);
106}
107
108TEST(requeue_pi)
109{
110	futex_t f1 = FUTEX_INITIALIZER;
111	struct timespec to;
112	int res;
113
114	/* FUTEX_WAIT_REQUEUE_PI with CLOCK_REALTIME */
115	if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))
116		ksft_test_result_error("get_time error");
117	res = futex_wait_requeue_pi(&f1, f1, &futex_pi, &to, FUTEX_CLOCK_REALTIME);
118	test_timeout(res, "futex_wait_requeue_pi realtime", ETIMEDOUT);
119
120	/* FUTEX_WAIT_REQUEUE_PI with CLOCK_MONOTONIC */
121	if (futex_get_abs_timeout(CLOCK_MONOTONIC, &to, timeout_ns))
122		ksft_test_result_error("get_time error");
123	res = futex_wait_requeue_pi(&f1, f1, &futex_pi, &to, 0);
124	test_timeout(res, "futex_wait_requeue_pi monotonic", ETIMEDOUT);
125
126}
127
128TEST(lock_pi)
129{
130	struct timespec to;
131	pthread_t thread;
132	int res;
133
134	/* Create a thread that will lock forever so any waiter will timeout */
135	pthread_barrier_init(&barrier, NULL, 2);
136	pthread_create(&thread, NULL, get_pi_lock, NULL);
137
138	/* Wait until the other thread calls futex_lock_pi() */
139	pthread_barrier_wait(&barrier);
140	pthread_barrier_destroy(&barrier);
141
142	/*
143	 * FUTEX_LOCK_PI with CLOCK_REALTIME
144	 * Due to historical reasons, FUTEX_LOCK_PI supports only realtime
145	 * clock, but requires the caller to not set CLOCK_REALTIME flag.
146	 *
147	 * If you call FUTEX_LOCK_PI with a monotonic clock, it'll be
148	 * interpreted as a realtime clock, and (unless you mess your machine's
149	 * time or your time machine) the monotonic clock value is always
150	 * smaller than realtime and the syscall will timeout immediately.
151	 */
152	if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))
153		ksft_test_result_error("get_time error");
154	res = futex_lock_pi(&futex_pi, &to, 0, 0);
155	test_timeout(res, "futex_lock_pi realtime", ETIMEDOUT);
156
157	/* Test operations that don't support FUTEX_CLOCK_REALTIME */
158	res = futex_lock_pi(&futex_pi, NULL, 0, FUTEX_CLOCK_REALTIME);
159	test_timeout(res, "futex_lock_pi invalid timeout flag", ENOSYS);
160}
161
162TEST(waitv)
163{
164	futex_t f1 = FUTEX_INITIALIZER;
165	struct futex_waitv waitv = {
166		.uaddr		= (uintptr_t)&f1,
167		.val		= f1,
168		.flags		= FUTEX_32,
169		.__reserved	= 0,
170	};
171	struct timespec to;
172	int res;
173
174	/* futex_waitv with CLOCK_MONOTONIC */
175	if (futex_get_abs_timeout(CLOCK_MONOTONIC, &to, timeout_ns))
176		ksft_test_result_error("get_time error");
177	res = futex_waitv(&waitv, 1, 0, &to, CLOCK_MONOTONIC);
178	test_timeout(res, "futex_waitv monotonic", ETIMEDOUT);
179
180	/* futex_waitv with CLOCK_REALTIME */
181	if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))
182		ksft_test_result_error("get_time error");
183	res = futex_waitv(&waitv, 1, 0, &to, CLOCK_REALTIME);
184	test_timeout(res, "futex_waitv realtime", ETIMEDOUT);
185}
186
187TEST_HARNESS_MAIN
~/ Read-only file preview.