From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B65363806CE for ; Mon, 1 Jun 2026 06:51:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780296710; cv=none; b=rig71RmZUo1u3McREanepytLu2I2+2JDiqY1HyLlkPBg8XKeos7FXT4CYZF6DXd7kQ9OHiluDf6KYPOyL/34bH5CWBnS7w/JLhU/IBjkYUeOByb2L69fbDWtJZtgC6BU5zlUltYpNh3ckBu5Um6ZkbBP+x4LlTzXMwI1FJjO38w= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780296710; c=relaxed/simple; bh=gwxob2EZvulYK9ds/Mqv1DMR+vDx8ag+CcujK4k5Wow=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Pkv5oe6wwEqnD8lk69YVY2UMilX4zt5DYjsJEZTCNQ72Ljpv7s4C9ub3MM6OrfeSD9JC870Qj2z6WZb7+S3gMvzHoHAHuuXgaKVBs0ztwC1vvoNViBz5KsdTblJbK53kg3/OMNXYHJZHxTv/ww+0RuqZ7zQ6v0feZoGJEaZsKzs= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--wakel.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=p6LXqWc9; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--wakel.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="p6LXqWc9" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-c85a2cde332so525166a12.3 for ; Sun, 31 May 2026 23:51:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1780296704; x=1780901504; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=gj/zqebitZEjvXoiM48+KkCnu32ZUykHthRZNwA4NOU=; b=p6LXqWc9lIAN+CrneIYmW/Ngqx9E/VqUWU2wSbX6s/z1FUSCQZzuozgWBKWdZqq2Jh BUG8VLJ2wWIItgTWlx/5/Hzms4iHaxuUPOU8UV8wm5gmletfloM3URKg6qtouyUmwRgh F2uoKCpJw/MNHRr/4SD450gkPhEQM7HpuQMHPYTB29M7J23AxuqUrssI8rLoeQUbHfYp vEK0BaYuMI1Bu9lHVGJCS7UHONrztqguX4zMIG4TNmmZj/0b7YrGqFRFxUtZGXvA083T 2/jUjboICqvOrxaO6CpmUnmnVsyo5WI5CrrPYdU04OHfqH2C9diTdI3twk/8EcRPH2z9 4Hzg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780296704; x=1780901504; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=gj/zqebitZEjvXoiM48+KkCnu32ZUykHthRZNwA4NOU=; b=X/Is5JxwisabT5K2sErFVRFuUk+UYT1YiOsA0LCwLY0KzJlCHjeHT9T7gAW8D9sOXx UlnLJOS6mezeTOafaMER1atlw2x4m/rsMWlFwXD3ZLTDjdeHxo8sk1lz7OiXK/lBDsiM OqUgs1qEv86olbt7eE5ABhqxBmy4cyugKmFxKamJB+8SivDILm2eiW+eVqLl2jH04wF2 FhyyDRSkDO5EVag8p/5bQOMOJzD61LBOcFV2svXvz1Bjdl9DCERRq+IgfbARKJBFpij+ 47ompYa2Behw7veuDITMxNmsIKsJWc/D0bvKlXlZiXRcwR3HOBhuq9bqFvXAfNknl5f2 8/tg== X-Forwarded-Encrypted: i=1; AFNElJ+x8ndL+MDGBt2BA61Q+D2QqS7zooQEHGfMkTpVV6r6jjF/5mam80l5jDPx4Lcpo17ahSdmf2FEgnXHOb0=@vger.kernel.org X-Gm-Message-State: AOJu0YwkapppAGm20zLQgKC8GzS1MRryy+jWkOq/MOoloJ8elXKoS5xP xYbGM209kH733UfGiexCrETd2cSdhTdUn8oBBpGazAJ5pZ/k9wGXvzYUfPGkIEg3ipEGuECuDCE uxw== X-Received: from pgc24.prod.google.com ([2002:a05:6a02:2f98:b0:c85:121a:8a22]) (user=wakel job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:b08d:b0:3b2:a86f:d38e with SMTP id adf61e73a8af0-3b427f5a847mr9719886637.36.1780296703565; Sun, 31 May 2026 23:51:43 -0700 (PDT) Date: Mon, 1 Jun 2026 06:51:26 +0000 In-Reply-To: <20260601065126.3623867-1-wakel@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260601065126.3623867-1-wakel@google.com> X-Mailer: git-send-email 2.54.0.823.g6e5bcc1fc9-goog Message-ID: <20260601065126.3623867-8-wakel@google.com> Subject: [PATCH 7/7] selftests/futex: Migrate robust_list to harness From: Wake Liu To: Thomas Gleixner , Ingo Molnar , Shuah Khan , linux-kselftest@vger.kernel.org Cc: Peter Zijlstra , Darren Hart , Davidlohr Bueso , "=?UTF-8?q?Andr=C3=A9=20Almeida?=" , Carlos Llamas , linux-kernel@vger.kernel.org, wakel@google.com Content-Type: text/plain; charset="UTF-8" Migrate robust_list test to the kselftest harness framework, removing mixed legacy ksft_* API usages and passing test metadata to cloned child functions via child_args struct. Also, fix an out-of-bounds waitpid bug during multithreaded tests. Signed-off-by: Wake Liu --- .../selftests/futex/functional/robust_list.c | 166 +++++++++--------- 1 file changed, 85 insertions(+), 81 deletions(-) diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c index e7d1254e18ca..d0b461962586 100644 --- a/tools/testing/selftests/futex/functional/robust_list.c +++ b/tools/testing/selftests/futex/functional/robust_list.c @@ -25,7 +25,7 @@ #define _GNU_SOURCE #include "futextest.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #include #include @@ -35,11 +35,11 @@ #include #include #include +#include +#include #define STACK_SIZE (1024 * 1024) - #define FUTEX_TIMEOUT 3 - #define SLEEP_US 100 static pthread_barrier_t barrier, barrier2; @@ -58,30 +58,46 @@ static int get_robust_list(int pid, struct robust_list_head **head, size_t *len_ * Basic lock struct, contains just the futex word and the robust list element * Real implementations have also a *prev to easily walk in the list */ +typedef _Atomic(unsigned int) atomic_futex_t; + struct lock_struct { - _Atomic(unsigned int) futex; + atomic_futex_t futex; struct robust_list list; }; +struct child_args { + struct __test_metadata *_metadata; + void *arg; +}; + /* * Helper function to spawn a child thread. Returns -1 on error, pid on success */ -static int create_child(int (*fn)(void *arg), void *arg) +static int create_child(struct __test_metadata *_metadata, int (*fn)(void *arg), void *arg) { char *stack; pid_t pid; + struct child_args *cargs = malloc(sizeof(*cargs)); + + if (!cargs) + return -1; + cargs->_metadata = _metadata; + cargs->arg = arg; stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); - if (stack == MAP_FAILED) + if (stack == MAP_FAILED) { + free(cargs); return -1; + } stack += STACK_SIZE; - pid = clone(fn, stack, CLONE_VM | SIGCHLD, arg); - - if (pid == -1) + pid = clone(fn, stack, CLONE_VM | SIGCHLD, cargs); + if (pid == -1) { + free(cargs); return -1; + } return pid; } @@ -110,7 +126,7 @@ static int set_list(struct robust_list_head *head) */ static int mutex_lock(struct lock_struct *lock, struct robust_list_head *head, bool error_inject) { - _Atomic(unsigned int) *futex = &lock->futex; + atomic_futex_t *futex = &lock->futex; unsigned int zero = 0; pid_t tid = gettid(); int ret = -1; @@ -170,21 +186,19 @@ static int mutex_lock(struct lock_struct *lock, struct robust_list_head *head, b */ static int child_fn_lock(void *arg) { - struct lock_struct *lock = arg; + struct child_args *cargs = arg; + struct __test_metadata *_metadata = cargs->_metadata; + struct lock_struct *lock = cargs->arg; struct robust_list_head head; int ret; + free(cargs); + ret = set_list(&head); - if (ret) { - ksft_test_result_fail("set_robust_list error\n"); - return ret; - } + ASSERT_EQ(ret, 0) TH_LOG("set_robust_list error"); ret = mutex_lock(lock, &head, false); - if (ret) { - ksft_test_result_fail("mutex_lock error\n"); - return ret; - } + ASSERT_EQ(ret, 0) TH_LOG("mutex_lock error"); pthread_barrier_wait(&barrier); @@ -207,7 +221,7 @@ static int child_fn_lock(void *arg) TEST(test_robustness) { struct lock_struct lock = { .futex = 0 }; - _Atomic(unsigned int) *futex = &lock.futex; + atomic_futex_t *futex = &lock.futex; struct robust_list_head head; int ret, pid, wstatus; @@ -221,7 +235,7 @@ TEST(test_robustness) ret = pthread_barrier_init(&barrier, NULL, 2); ASSERT_EQ(ret, 0); - pid = create_child(&child_fn_lock, &lock); + pid = create_child(_metadata, &child_fn_lock, &lock); ASSERT_NE(pid, -1); pthread_barrier_wait(&barrier); @@ -238,9 +252,7 @@ TEST(test_robustness) wait(&wstatus); pthread_barrier_destroy(&barrier); - /* Pass only if the child hasn't return error */ - if (!WEXITSTATUS(wstatus)) - ksft_test_result_pass("%s\n", __func__); + EXPECT_EQ(WEXITSTATUS(wstatus), 0) TH_LOG("child failed"); } /* @@ -266,8 +278,6 @@ TEST(test_set_robust_list_invalid_size) ret = set_robust_list(&head, 0); ASSERT_EQ(ret, -1); ASSERT_EQ(errno, EINVAL); - - ksft_test_result_pass("%s\n", __func__); } /* @@ -294,20 +304,19 @@ TEST(test_get_robust_list_self) ASSERT_EQ(ret, 0); ASSERT_EQ(get_head, &head2); ASSERT_EQ(head_size, len_ptr); - - ksft_test_result_pass("%s\n", __func__); } static int child_list(void *arg) { - struct robust_list_head *head = arg; + struct child_args *cargs = arg; + struct __test_metadata *_metadata = cargs->_metadata; + struct robust_list_head *head = cargs->arg; int ret; + free(cargs); + ret = set_robust_list(head, sizeof(*head)); - if (ret) { - ksft_test_result_fail("set_robust_list error\n"); - return -1; - } + ASSERT_EQ(ret, 0) TH_LOG("set_robust_list error"); /* * After setting the list head, wait until the main thread can call @@ -337,7 +346,7 @@ TEST(test_get_robust_list_child) ret = pthread_barrier_init(&barrier2, NULL, 2); ASSERT_EQ(ret, 0); - tid = create_child(&child_list, &head); + tid = create_child(_metadata, &child_list, &head); ASSERT_NE(tid, -1); pthread_barrier_wait(&barrier); @@ -352,28 +361,24 @@ TEST(test_get_robust_list_child) pthread_barrier_destroy(&barrier); pthread_barrier_destroy(&barrier2); - /* Pass only if the child hasn't return error */ - if (!WEXITSTATUS(wstatus)) - ksft_test_result_pass("%s\n", __func__); + EXPECT_EQ(WEXITSTATUS(wstatus), 0) TH_LOG("child failed"); } static int child_fn_lock_with_error(void *arg) { - struct lock_struct *lock = arg; + struct child_args *cargs = arg; + struct __test_metadata *_metadata = cargs->_metadata; + struct lock_struct *lock = cargs->arg; struct robust_list_head head; int ret; + free(cargs); + ret = set_list(&head); - if (ret) { - ksft_test_result_fail("set_robust_list error\n"); - return -1; - } + ASSERT_EQ(ret, 0) TH_LOG("set_robust_list error"); ret = mutex_lock(lock, &head, true); - if (ret) { - ksft_test_result_fail("mutex_lock error\n"); - return -1; - } + ASSERT_EQ(ret, 0) TH_LOG("mutex_lock error"); pthread_barrier_wait(&barrier); @@ -391,7 +396,7 @@ static int child_fn_lock_with_error(void *arg) TEST(test_set_list_op_pending) { struct lock_struct lock = { .futex = 0 }; - _Atomic(unsigned int) *futex = &lock.futex; + atomic_futex_t *futex = &lock.futex; struct robust_list_head head; int ret, wstatus; @@ -401,7 +406,7 @@ TEST(test_set_list_op_pending) ret = pthread_barrier_init(&barrier, NULL, 2); ASSERT_EQ(ret, 0); - ret = create_child(&child_fn_lock_with_error, &lock); + ret = create_child(_metadata, &child_fn_lock_with_error, &lock); ASSERT_NE(ret, -1); pthread_barrier_wait(&barrier); @@ -414,21 +419,21 @@ TEST(test_set_list_op_pending) wait(&wstatus); pthread_barrier_destroy(&barrier); - /* Pass only if the child hasn't return error */ - if (!WEXITSTATUS(wstatus)) - ksft_test_result_pass("%s\n", __func__); - else - ksft_test_result_fail("%s\n", __func__); + EXPECT_EQ(WEXITSTATUS(wstatus), 0) TH_LOG("child failed"); } #define CHILD_NR 10 static int child_lock_holder(void *arg) { - struct lock_struct *locks = arg; + struct child_args *cargs = arg; + struct __test_metadata *_metadata = cargs->_metadata; + struct lock_struct *locks = cargs->arg; struct robust_list_head head; int i; + free(cargs); + set_list(&head); for (i = 0; i < CHILD_NR; i++) { @@ -447,22 +452,20 @@ static int child_lock_holder(void *arg) static int child_wait_lock(void *arg) { - struct lock_struct *lock = arg; + struct child_args *cargs = arg; + struct __test_metadata *_metadata = cargs->_metadata; + struct lock_struct *lock = cargs->arg; struct robust_list_head head; int ret; + free(cargs); + pthread_barrier_wait(&barrier2); ret = mutex_lock(lock, &head, false); + ASSERT_EQ(ret, 0) TH_LOG("mutex_lock error"); - if (ret) { - ksft_test_result_fail("mutex_lock error\n"); - return -1; - } - - if (!(lock->futex & FUTEX_OWNER_DIED)) { - ksft_test_result_fail("futex not marked with FUTEX_OWNER_DIED\n"); - return -1; - } + ASSERT_TRUE(lock->futex & FUTEX_OWNER_DIED) + TH_LOG("futex not marked with FUTEX_OWNER_DIED"); return 0; } @@ -482,18 +485,20 @@ TEST(test_robust_list_multiple_elements) ret = pthread_barrier_init(&barrier2, NULL, CHILD_NR + 1); ASSERT_EQ(ret, 0); - pids[0] = create_child(&child_lock_holder, &locks); + pids[0] = create_child(_metadata, &child_lock_holder, &locks); + ASSERT_NE(pids[0], -1); /* Wait until the locker thread takes the look */ pthread_barrier_wait(&barrier); - for (i = 0; i < CHILD_NR; i++) - pids[i+1] = create_child(&child_wait_lock, &locks[i]); + for (i = 0; i < CHILD_NR; i++) { + pids[i+1] = create_child(_metadata, &child_wait_lock, &locks[i]); + ASSERT_NE(pids[i+1], -1); + } - /* Wait for all children to return */ + /* Wait for all children to return (holder + all waiters) */ ret = 0; - - for (i = 0; i < CHILD_NR; i++) { + for (i = 0; i < CHILD_NR + 1; i++) { waitpid(pids[i], &wstatus, 0); if (WEXITSTATUS(wstatus)) ret = -1; @@ -502,22 +507,21 @@ TEST(test_robust_list_multiple_elements) pthread_barrier_destroy(&barrier); pthread_barrier_destroy(&barrier2); - /* Pass only if the child hasn't return error */ - if (!ret) - ksft_test_result_pass("%s\n", __func__); + EXPECT_EQ(ret, 0) TH_LOG("One or more children failed"); } static int child_circular_list(void *arg) { + struct child_args *cargs = arg; + struct __test_metadata *_metadata = cargs->_metadata; static struct robust_list_head head; struct lock_struct a, b, c; int ret; + free(cargs); + ret = set_list(&head); - if (ret) { - ksft_test_result_fail("set_list error\n"); - return -1; - } + ASSERT_EQ(ret, 0) TH_LOG("set_list error"); head.list.next = &a.list; @@ -539,14 +543,14 @@ static int child_circular_list(void *arg) TEST(test_circular_list) { int wstatus; + pid_t pid; - create_child(child_circular_list, NULL); + pid = create_child(_metadata, child_circular_list, NULL); + ASSERT_NE(pid, -1); wait(&wstatus); - /* Pass only if the child hasn't return error */ - if (!WEXITSTATUS(wstatus)) - ksft_test_result_pass("%s\n", __func__); + EXPECT_EQ(WEXITSTATUS(wstatus), 0) TH_LOG("child failed"); } TEST_HARNESS_MAIN -- 2.54.0.823.g6e5bcc1fc9-goog