xref: /linux/tools/testing/selftests/futex/functional/futex_requeue.c (revision 59e6295fac26b8e85c1ea859cdd89fa1e47519d7)
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 <limits.h>
9 #include <pthread.h>
10 #include <string.h>
11 
12 #include "futextest.h"
13 #include "futex_thread.h"
14 #include "kselftest_harness.h"
15 
16 struct waiter_args {
17 	struct __test_metadata	*_metadata;
18 	unsigned int		n_threads;
19 };
20 
21 volatile futex_t *f1;
22 
23 static int waiterfn(void *arg)
24 {
25 	struct __test_metadata *_metadata;
26 	struct waiter_args *wargs = arg;
27 	struct timespec to = { };
28 	int res;
29 
30 	_metadata = wargs->_metadata;
31 	to.tv_sec = (wargs->n_threads + 1) * WAIT_FOR_THREAD_SECS;
32 
33 	res = futex_wait(f1, *f1, &to, 0);
34 	if (res) {
35 		EXPECT_EQ(res, 0)
36 			TH_LOG("waiter failed errno %d: %s", errno, strerror(errno));
37 	}
38 
39 	return 0;
40 }
41 
42 TEST(requeue_single)
43 {
44 	struct waiter_args wargs = { ._metadata = _metadata, .n_threads = 1 };
45 	struct futex_thread waiter;
46 	volatile futex_t _f1 = 0;
47 	volatile futex_t f2 = 0;
48 
49 	f1 = &_f1;
50 
51 	/*
52 	 * Requeue a waiter from f1 to f2, and wake f2.
53 	 */
54 	ASSERT_EQ(futex_thread_create(&waiter, waiterfn, &wargs), 0)
55 		TH_LOG("pthread_create failed");
56 
57 	ASSERT_EQ(futex_wait_for_thread(&waiter, _metadata), 0)
58 		TH_LOG("Wait for thread failed");
59 
60 	EXPECT_EQ(futex_cmp_requeue(f1, 0, &f2, 0, 1, 0), 1);
61 	EXPECT_EQ(futex_wake(&f2, 1, 0), 1);
62 
63 	EXPECT_EQ(futex_thread_destroy(&waiter), 0);
64 }
65 
66 TEST(requeue_multiple)
67 {
68 	struct waiter_args wargs = { ._metadata = _metadata, .n_threads = 10 };
69 	struct futex_thread waiter[10];
70 	volatile futex_t _f1 = 0;
71 	volatile futex_t f2 = 0;
72 
73 	f1 = &_f1;
74 
75 	/*
76 	 * Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7.
77 	 * At futex_wake, wake INT_MAX (should be exactly 7).
78 	 */
79 	for (int i = 0; i < 10; i++) {
80 		ASSERT_EQ(futex_thread_create(&waiter[i], waiterfn, &wargs), 0)
81 			TH_LOG("pthread_create failed for waiter %d", i);
82 	}
83 
84 	for (int i = 0; i < 10; i++) {
85 		ASSERT_EQ(futex_wait_for_thread(&waiter[i], _metadata), 0)
86 			TH_LOG("Wait for waiter thread %d failed", i);
87 	}
88 
89 	EXPECT_EQ(futex_cmp_requeue(f1, 0, &f2, 3, 7, 0), 10);
90 	EXPECT_EQ(futex_wake(&f2, INT_MAX, 0), 7);
91 
92 	for (int i = 0; i < 10; i++)
93 		EXPECT_EQ(futex_thread_destroy(&waiter[i]), 0);
94 }
95 
96 TEST_HARNESS_MAIN
97