[PATCH v6 8/9] selftests/futex: Expand for get_robust_list2()

André Almeida
2025-11-22T05:51:36Z

Reuse the same selftest for the original set_robust_list() syscall for
the new set_robust_list2() syscall. Use kselftest variants feature to
run the relevant tests for both interfaces. Create a new test case to
get different lists from the same task.

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
.../selftests/futex/functional/robust_list.c | 95 ++++++++++++++++++----
1 file changed, 81 insertions(+), 14 deletions(-)

diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c
index bf47e9ab2951..e6b26d7b9502 100644
--- a/tools/testing/selftests/futex/functional/robust_list.c
+++ b/tools/testing/selftests/futex/functional/robust_list.c
@@ -44,6 +44,7 @@

#ifndef SYS_set_robust_list2
# define SYS_set_robust_list2 470
+# define SYS_get_robust_list2 471

enum robust_list_cmd {
FUTEX_ROBUST_LIST_CMD_SET_64,
@@ -81,6 +82,12 @@ static int set_robust_list2(struct robust_list_head *head, int index,
return syscall(SYS_set_robust_list2, head, index, cmd, flags);
}

+static int get_robust_list2(int pid, struct robust_list_head **head,
+ unsigned int index, unsigned int flags)
+{
+ return syscall(SYS_get_robust_list2, pid, head, index, flags);
+}
+
static bool robust_list2_support(void)
{
int ret = set_robust_list2(0, 0, FUTEX_ROBUST_LIST_CMD_LIST_LIMIT, 0);
@@ -181,6 +188,23 @@ static int set_list(struct robust_list_head *head, bool robust2, int index)
return set_robust_list2(head, index, get_cmd_set(), 0);
}

+static int get_list(pid_t pid, struct robust_list_head **head, bool robust2, int index)
+{
+ int ret;
+
+ if (!robust2) {
+ size_t len_ptr;
+
+ ret = get_robust_list(pid, head, &len_ptr);
+ if (sizeof(**head) != len_ptr)
+ return -EINVAL;
+
+ return ret;
+ }
+
+ return get_robust_list2(pid, head, index, 0);
+}
+
/*
* A basic (and incomplete) mutex lock function with robustness
*/
@@ -391,37 +415,44 @@ TEST(test_set_robust_list2_inval)
/*
* Test get_robust_list with pid = 0, getting the list of the running thread
*/
-TEST(test_get_robust_list_self)
+TEST_F(robust_api, test_get_robust_list_self)
{
struct robust_list_head head, head2, *get_head;
- size_t head_size = sizeof(head), len_ptr;
+ bool robust2 = variant->robust2;
int ret;

- ret = set_robust_list(&head, head_size);
+ ret = set_list(&head, robust2, 0);
ASSERT_EQ(ret, 0);

- ret = get_robust_list(0, &get_head, &len_ptr);
+ ret = get_list(0, &get_head, robust2, 0);
ASSERT_EQ(ret, 0);
ASSERT_EQ(get_head, &head);
- ASSERT_EQ(head_size, len_ptr);

- ret = set_robust_list(&head2, head_size);
+ ret = set_list(&head2, robust2, 0);
ASSERT_EQ(ret, 0);

- ret = get_robust_list(0, &get_head, &len_ptr);
+ ret = get_list(0, &get_head, robust2, 0);
ASSERT_EQ(ret, 0);
ASSERT_EQ(get_head, &head2);
- ASSERT_EQ(head_size, len_ptr);

ksft_test_result_pass("%s\n", __func__);
}

+struct child_arg_struct {
+ struct robust_list_head *head;
+ bool robust2;
+};
+
static int child_list(void *arg)
{
- struct robust_list_head *head = arg;
+ struct child_arg_struct *child = arg;
+ struct robust_list_head *head;
+ bool robust2 = child->robust2;
int ret;

- ret = set_robust_list(head, sizeof(*head));
+ head = child->head;
+
+ ret = set_list(head, robust2, 0);
if (ret) {
ksft_test_result_fail("set_robust_list error\n");
return -1;
@@ -444,23 +475,26 @@ static int child_list(void *arg)
* parent
* 2) the child thread still alive when we try to get the list from it
*/
-TEST(test_get_robust_list_child)
+TEST_F(robust_api, test_get_robust_list_child)
{
struct robust_list_head head, *get_head;
+ bool robust2 = variant->robust2;
+ struct child_arg_struct child =
+ {.robust2 = robust2, .head = &head};
int ret, wstatus;
- size_t len_ptr;
pid_t tid;

+
ret = pthread_barrier_init(&barrier, NULL, 2);
ret = pthread_barrier_init(&barrier2, NULL, 2);
ASSERT_EQ(ret, 0);

- tid = create_child(&child_list, &head);
+ tid = create_child(&child_list, &child);
ASSERT_NE(tid, -1);

pthread_barrier_wait(&barrier);

- ret = get_robust_list(tid, &get_head, &len_ptr);
+ ret = get_list(tid, &get_head, robust2, 0);
ASSERT_EQ(ret, 0);
ASSERT_EQ(&head, get_head);

@@ -914,4 +948,37 @@ TEST(test_32bit_lists)
munmap(locks, sizeof(*locks) * CHILD_NR);
}

+/*
+ * Test setting and getting mutiples head lists
+ */
+TEST(set_and_get_robust2)
+{
+ struct robust_list_head *head = NULL, *heads;
+ int i, list_limit, ret;
+
+ if (!robust_list2_support()) {
+ ksft_test_result_skip("robust_list2 not supported\n");
+ return;
+ }
+
+ list_limit = set_robust_list2(NULL, 0, FUTEX_ROBUST_LIST_CMD_LIST_LIMIT, 0);
+
+ heads = malloc(list_limit * sizeof(*heads));
+ ASSERT_NE(heads, NULL);
+
+ for (i = 0; i < list_limit; i++) {
+ ret = set_list(&heads[i], true, i);
+ ASSERT_EQ(ret, 0);
+ }
+
+ for (i = 0; i < list_limit; i++) {
+ ret = get_list(0, &head, true, i);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(head, &heads[i]);
+ }
+
+ free(heads);
+ ksft_test_result_pass("%s\n", __func__);
+}
+
TEST_HARNESS_MAIN

--
2.52.0