Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/futex/functional/futex_wait_timeout.c
29271 views
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 <[email protected]>
11
*
12
* HISTORY
13
* 2009-Nov-6: Initial version by Darren Hart <[email protected]>
14
* 2021-Apr-26: More test cases by André Almeida <[email protected]>
15
*
16
*****************************************************************************/
17
18
#include <pthread.h>
19
20
#include "futextest.h"
21
#include "futex2test.h"
22
#include "../../kselftest_harness.h"
23
24
static long timeout_ns = 100000; /* 100us default timeout */
25
static futex_t futex_pi;
26
static 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
*/
32
void *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
*/
53
static 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
*/
66
static 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
82
TEST(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
108
TEST(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
128
TEST(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
162
TEST(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
187
TEST_HARNESS_MAIN
188
189