summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2026-10-14 08:18:11 -1000
committerTejun Heo <tj@kernel.org>2026-10-14 08:18:11 -1000
commitcf5bc5805b23fa88413110fefca4d5c699d596ec (patch)
treed725b1014af0393bd983da442a7075422a7b6cdb
parent070b82a8012249bd8bb83c68b67683c707eb8ca0 (diff)
parent6052353d2f32fd876ac0846b089f292dd5793141 (diff)
downloadlinux-next-cf5bc5805b23fa88413110fefca4d5c699d596ec.tar.gz
linux-next-cf5bc5805b23fa88413110fefca4d5c699d596ec.zip
Merge branch 'for-7.4' into for-next
-rw-r--r--tools/sched_ext/include/scx/user_exit_info.h1
-rw-r--r--tools/testing/selftests/sched_ext/allowed_cpus.c2
-rw-r--r--tools/testing/selftests/sched_ext/cgroup_nr_cpus.c2
-rw-r--r--tools/testing/selftests/sched_ext/create_dsq.bpf.c8
-rw-r--r--tools/testing/selftests/sched_ext/create_dsq.c2
-rw-r--r--tools/testing/selftests/sched_ext/cyclic_kick_wait.c2
-rw-r--r--tools/testing/selftests/sched_ext/enq_blocked.c2
-rw-r--r--tools/testing/selftests/sched_ext/exit.c8
-rw-r--r--tools/testing/selftests/sched_ext/hotplug.c12
-rw-r--r--tools/testing/selftests/sched_ext/init_enable_count.bpf.c8
-rw-r--r--tools/testing/selftests/sched_ext/init_enable_count.c13
-rw-r--r--tools/testing/selftests/sched_ext/kick.c8
-rw-r--r--tools/testing/selftests/sched_ext/maximal.bpf.c6
-rw-r--r--tools/testing/selftests/sched_ext/maximal.c2
-rw-r--r--tools/testing/selftests/sched_ext/nohz_tick.c6
-rw-r--r--tools/testing/selftests/sched_ext/prog_run.c7
-rw-r--r--tools/testing/selftests/sched_ext/reload_loop.c49
-rw-r--r--tools/testing/selftests/sched_ext/scx_test.h57
18 files changed, 162 insertions, 33 deletions
diff --git a/tools/sched_ext/include/scx/user_exit_info.h b/tools/sched_ext/include/scx/user_exit_info.h
index 56a02b549aef..cf27ac2447ef 100644
--- a/tools/sched_ext/include/scx/user_exit_info.h
+++ b/tools/sched_ext/include/scx/user_exit_info.h
@@ -52,6 +52,7 @@
enum scx_exit_code {
/* Reasons */
SCX_ECODE_RSN_HOTPLUG = 1LLU << 32,
+ SCX_ECODE_RSN_CGROUP_OFFLINE = 2LLU << 32,
/* Actions */
SCX_ECODE_ACT_RESTART = 1LLU << 48,
diff --git a/tools/testing/selftests/sched_ext/allowed_cpus.c b/tools/testing/selftests/sched_ext/allowed_cpus.c
index 773699d120ea..76311728a6b1 100644
--- a/tools/testing/selftests/sched_ext/allowed_cpus.c
+++ b/tools/testing/selftests/sched_ext/allowed_cpus.c
@@ -149,7 +149,7 @@ static enum scx_test_status run(void *ctx)
/* Just sleeping is fine, plenty of scheduling events happening. */
sleep(1);
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly");
goto out;
}
diff --git a/tools/testing/selftests/sched_ext/cgroup_nr_cpus.c b/tools/testing/selftests/sched_ext/cgroup_nr_cpus.c
index 4973f7080353..1475a8b3f05f 100644
--- a/tools/testing/selftests/sched_ext/cgroup_nr_cpus.c
+++ b/tools/testing/selftests/sched_ext/cgroup_nr_cpus.c
@@ -400,7 +400,7 @@ static enum scx_test_status run(void *arg)
!wait_nr_cpus(&ctx, ctx.leaf, nr_child, "leaf after cpuset disable"))
goto out;
- if (ctx.skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(ctx.skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly");
goto out;
}
diff --git a/tools/testing/selftests/sched_ext/create_dsq.bpf.c b/tools/testing/selftests/sched_ext/create_dsq.bpf.c
index 680cc4b6d8c7..24dacd1aab0c 100644
--- a/tools/testing/selftests/sched_ext/create_dsq.bpf.c
+++ b/tools/testing/selftests/sched_ext/create_dsq.bpf.c
@@ -12,6 +12,8 @@ char _license[] SEC("license") = "GPL";
u32 nr_lifecycle_tests;
+UEI_DEFINE(uei);
+
void BPF_STRUCT_OPS(create_dsq_exit_task, struct task_struct *p,
struct scx_exit_task_args *args)
{
@@ -84,10 +86,16 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(create_dsq_init)
return 0;
}
+void BPF_STRUCT_OPS(create_dsq_exit, struct scx_exit_info *ei)
+{
+ UEI_RECORD(uei, ei);
+}
+
SEC(".struct_ops.link")
struct sched_ext_ops create_dsq_ops = {
.init_task = (void *) create_dsq_init_task,
.exit_task = (void *) create_dsq_exit_task,
.init = (void *) create_dsq_init,
+ .exit = (void *) create_dsq_exit,
.name = "create_dsq",
};
diff --git a/tools/testing/selftests/sched_ext/create_dsq.c b/tools/testing/selftests/sched_ext/create_dsq.c
index 422e6532ee71..84143d5710f4 100644
--- a/tools/testing/selftests/sched_ext/create_dsq.c
+++ b/tools/testing/selftests/sched_ext/create_dsq.c
@@ -35,6 +35,8 @@ static enum scx_test_status run(void *ctx)
return SCX_TEST_FAIL;
}
+ SCX_ASSERT_ALIVE(skel, uei);
+
bpf_link__destroy(link);
SCX_EQ(skel->bss->nr_lifecycle_tests, 1024);
diff --git a/tools/testing/selftests/sched_ext/cyclic_kick_wait.c b/tools/testing/selftests/sched_ext/cyclic_kick_wait.c
index c2e5aa9de715..178d1d75f332 100644
--- a/tools/testing/selftests/sched_ext/cyclic_kick_wait.c
+++ b/tools/testing/selftests/sched_ext/cyclic_kick_wait.c
@@ -152,7 +152,7 @@ static enum scx_test_status run(void *ctx)
sleep(5);
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly (kind=%llu code=%lld)",
(unsigned long long)skel->data->uei.kind,
(long long)skel->data->uei.exit_code);
diff --git a/tools/testing/selftests/sched_ext/enq_blocked.c b/tools/testing/selftests/sched_ext/enq_blocked.c
index 26204548bbf0..1d5e090b54bc 100644
--- a/tools/testing/selftests/sched_ext/enq_blocked.c
+++ b/tools/testing/selftests/sched_ext/enq_blocked.c
@@ -844,7 +844,7 @@ out:
}
}
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly (kind=%llu code=%lld)",
(unsigned long long)skel->data->uei.kind,
(long long)skel->data->uei.exit_code);
diff --git a/tools/testing/selftests/sched_ext/exit.c b/tools/testing/selftests/sched_ext/exit.c
index 01b17092d5c8..fd6f1c9ab2db 100644
--- a/tools/testing/selftests/sched_ext/exit.c
+++ b/tools/testing/selftests/sched_ext/exit.c
@@ -43,8 +43,12 @@ static enum scx_test_status run(void *ctx)
}
/* Assumes uei.kind is written last */
- while (skel->data->uei.kind == EXIT_KIND(SCX_EXIT_NONE))
- sched_yield();
+ if (!SCX_TIMED_WAIT_UEI(skel, uei, 10000)) {
+ SCX_ERR("Timed out waiting for scheduler to exit");
+ bpf_link__destroy(link);
+ exit__destroy(skel);
+ return SCX_TEST_FAIL;
+ }
SCX_EQ(skel->data->uei.kind, EXIT_KIND(SCX_EXIT_UNREG_BPF));
SCX_EQ(skel->data->uei.exit_code, tc);
diff --git a/tools/testing/selftests/sched_ext/hotplug.c b/tools/testing/selftests/sched_ext/hotplug.c
index 10b8d42bd89b..3c07686a93c8 100644
--- a/tools/testing/selftests/sched_ext/hotplug.c
+++ b/tools/testing/selftests/sched_ext/hotplug.c
@@ -85,8 +85,10 @@ static enum scx_test_status test_hotplug(bool onlining, bool cbs_defined)
if (toggle_online_status(onlining ? 1 : 0))
goto out_destroy_link;
- while (!UEI_EXITED(skel, uei))
- sched_yield();
+ if (!SCX_TIMED_WAIT_UEI(skel, uei, 10000)) {
+ SCX_ERR("Timed out waiting for scheduler to exit");
+ goto out_destroy_link;
+ }
SCX_EQ(skel->data->uei.kind, kind);
SCX_EQ(UEI_REPORT(skel, uei), code);
@@ -130,8 +132,10 @@ static enum scx_test_status test_hotplug_attach(void)
goto out_destroy_link;
SCX_ASSERT(link);
- while (!UEI_EXITED(skel, uei))
- sched_yield();
+ if (!SCX_TIMED_WAIT_UEI(skel, uei, 10000)) {
+ SCX_ERR("Timed out waiting for scheduler to exit");
+ goto out_destroy_link;
+ }
kind = SCX_KIND_VAL(SCX_EXIT_UNREG_KERN);
code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) |
diff --git a/tools/testing/selftests/sched_ext/init_enable_count.bpf.c b/tools/testing/selftests/sched_ext/init_enable_count.bpf.c
index 5eb9edb1837d..c0a5dd8fe183 100644
--- a/tools/testing/selftests/sched_ext/init_enable_count.bpf.c
+++ b/tools/testing/selftests/sched_ext/init_enable_count.bpf.c
@@ -15,6 +15,8 @@ char _license[] SEC("license") = "GPL";
u64 init_task_cnt, exit_task_cnt, enable_cnt, disable_cnt;
u64 init_fork_cnt, init_transition_cnt;
+UEI_DEFINE(uei);
+
s32 BPF_STRUCT_OPS_SLEEPABLE(cnt_init_task, struct task_struct *p,
struct scx_init_task_args *args)
{
@@ -43,11 +45,17 @@ void BPF_STRUCT_OPS(cnt_disable, struct task_struct *p)
__sync_fetch_and_add(&disable_cnt, 1);
}
+void BPF_STRUCT_OPS(cnt_exit, struct scx_exit_info *ei)
+{
+ UEI_RECORD(uei, ei);
+}
+
SEC(".struct_ops.link")
struct sched_ext_ops init_enable_count_ops = {
.init_task = (void *) cnt_init_task,
.exit_task = (void *) cnt_exit_task,
.enable = (void *) cnt_enable,
.disable = (void *) cnt_disable,
+ .exit = (void *) cnt_exit,
.name = "init_enable_count",
};
diff --git a/tools/testing/selftests/sched_ext/init_enable_count.c b/tools/testing/selftests/sched_ext/init_enable_count.c
index 44577e30e764..c4a57038a1d6 100644
--- a/tools/testing/selftests/sched_ext/init_enable_count.c
+++ b/tools/testing/selftests/sched_ext/init_enable_count.c
@@ -5,6 +5,7 @@
* Copyright (c) 2023 Tejun Heo <tj@kernel.org>
*/
#include <signal.h>
+#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
@@ -72,7 +73,17 @@ static enum scx_test_status run_test(bool global)
close(pipe_fds[1]);
signal(SIGCHLD, SIG_DFL);
+ SCX_ASSERT_ALIVE(skel, uei);
+
bpf_link__destroy(link);
+
+ /*
+ * The clean unregister above is recorded in uei and would
+ * otherwise trip the liveness check of the second cycle, which
+ * reuses this skeleton.
+ */
+ memset(&skel->data->uei, 0, sizeof(skel->data->uei));
+
SCX_GE(skel->bss->init_task_cnt, num_pre_forks);
SCX_GE(skel->bss->exit_task_cnt, num_pre_forks);
@@ -124,6 +135,8 @@ static enum scx_test_status run_test(bool global)
status);
}
+ SCX_ASSERT_ALIVE(skel, uei);
+
bpf_link__destroy(link);
SCX_GE(skel->bss->init_task_cnt, 2 * num_children);
diff --git a/tools/testing/selftests/sched_ext/kick.c b/tools/testing/selftests/sched_ext/kick.c
index 7f01602c75b2..40c91d54c1eb 100644
--- a/tools/testing/selftests/sched_ext/kick.c
+++ b/tools/testing/selftests/sched_ext/kick.c
@@ -97,7 +97,7 @@ static bool wait_for_state(struct kick *skel, u32 wanted)
for (i = 0; i < WAIT_LOOPS; i++) {
if (__atomic_load_n(&skel->bss->state, __ATOMIC_ACQUIRE) == wanted)
return true;
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE))
+ if (UEI_EXITED(skel, uei))
return false;
usleep(1000);
}
@@ -111,7 +111,7 @@ static bool wait_for_counter(struct kick *skel, const u64 *counter, u64 wanted)
for (i = 0; i < WAIT_LOOPS; i++) {
if (__atomic_load_n(counter, __ATOMIC_ACQUIRE) >= wanted)
return true;
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE))
+ if (UEI_EXITED(skel, uei))
return false;
usleep(1000);
}
@@ -421,7 +421,9 @@ static enum scx_test_status invalid_one(struct kick_ctx *ctx, u32 scenario)
enum scx_test_status ret = SCX_TEST_FAIL;
int cpu = ctx->target_cpu;
int i;
+ u64 error_kind;
+ error_kind = EXIT_KIND(SCX_EXIT_ERROR);
victim = scx_test_spawn_gated_worker(cpu, false);
if (victim.pid < 0)
return SCX_TEST_FAIL;
@@ -440,7 +442,7 @@ static enum scx_test_status invalid_one(struct kick_ctx *ctx, u32 scenario)
goto out;
for (i = 0; i < WAIT_LOOPS; i++) {
- if (skel->data->uei.kind == EXIT_KIND(SCX_EXIT_ERROR)) {
+ if (UEI_EXITED(skel, uei) == error_kind) {
ret = SCX_TEST_PASS;
break;
}
diff --git a/tools/testing/selftests/sched_ext/maximal.bpf.c b/tools/testing/selftests/sched_ext/maximal.bpf.c
index 04a369078aac..9ea664e2ff70 100644
--- a/tools/testing/selftests/sched_ext/maximal.bpf.c
+++ b/tools/testing/selftests/sched_ext/maximal.bpf.c
@@ -14,6 +14,8 @@ char _license[] SEC("license") = "GPL";
#define DSQ_ID 0
+UEI_DEFINE(uei);
+
s32 BPF_STRUCT_OPS(maximal_select_cpu, struct task_struct *p, s32 prev_cpu,
u64 wake_flags)
{
@@ -132,7 +134,9 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(maximal_init)
}
void BPF_STRUCT_OPS(maximal_exit, struct scx_exit_info *info)
-{}
+{
+ UEI_RECORD(uei, info);
+}
SEC(".struct_ops.link")
struct sched_ext_ops maximal_ops = {
diff --git a/tools/testing/selftests/sched_ext/maximal.c b/tools/testing/selftests/sched_ext/maximal.c
index 1dc369224670..6c6b80e0446e 100644
--- a/tools/testing/selftests/sched_ext/maximal.c
+++ b/tools/testing/selftests/sched_ext/maximal.c
@@ -35,6 +35,8 @@ static enum scx_test_status run(void *ctx)
link = bpf_map__attach_struct_ops(skel->maps.maximal_ops);
SCX_FAIL_IF(!link, "Failed to attach scheduler");
+ SCX_ASSERT_ALIVE(skel, uei);
+
bpf_link__destroy(link);
return SCX_TEST_PASS;
diff --git a/tools/testing/selftests/sched_ext/nohz_tick.c b/tools/testing/selftests/sched_ext/nohz_tick.c
index df40976b9166..e19a97034b7f 100644
--- a/tools/testing/selftests/sched_ext/nohz_tick.c
+++ b/tools/testing/selftests/sched_ext/nohz_tick.c
@@ -165,7 +165,7 @@ static bool wait_for_counter(struct nohz_tick *skel, const u64 *counter, u64 val
for (elapsed = 0; elapsed < timeout_ms; elapsed++) {
if (__atomic_load_n(counter, __ATOMIC_RELAXED) >= value)
return true;
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE))
+ if (UEI_EXITED(skel, uei))
return false;
usleep(1000);
}
@@ -182,7 +182,7 @@ static bool wait_for_tick_stop(struct nohz_tick *skel, const u64 *counter, int t
u64 curr;
usleep(1000);
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE))
+ if (UEI_EXITED(skel, uei))
return false;
curr = __atomic_load_n(counter, __ATOMIC_RELAXED);
if (curr == prev) {
@@ -461,7 +461,7 @@ static enum scx_test_status run(void *ctx_ptr)
scx_test_stop_gated_worker(&challenger);
check_exit:
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly (kind=%llu code=%lld)",
(unsigned long long)skel->data->uei.kind,
(long long)skel->data->uei.exit_code);
diff --git a/tools/testing/selftests/sched_ext/prog_run.c b/tools/testing/selftests/sched_ext/prog_run.c
index 1129ec2aaddc..369c744ac06e 100644
--- a/tools/testing/selftests/sched_ext/prog_run.c
+++ b/tools/testing/selftests/sched_ext/prog_run.c
@@ -55,8 +55,11 @@ static enum scx_test_status run(void *ctx)
}
/* Assumes uei.kind is written last */
- while (skel->data->uei.kind == EXIT_KIND(SCX_EXIT_NONE))
- sched_yield();
+ if (!SCX_TIMED_WAIT_UEI(skel, uei, 10000)) {
+ SCX_ERR("Timed out waiting for scheduler to exit");
+ status = SCX_TEST_FAIL;
+ goto out;
+ }
if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_UNREG_BPF)) {
SCX_ERR("Unexpected exit kind: %llu",
diff --git a/tools/testing/selftests/sched_ext/reload_loop.c b/tools/testing/selftests/sched_ext/reload_loop.c
index 49297b83d748..7d8880fa1a03 100644
--- a/tools/testing/selftests/sched_ext/reload_loop.c
+++ b/tools/testing/selftests/sched_ext/reload_loop.c
@@ -4,6 +4,7 @@
* Copyright (c) 2024 David Vernet <dvernet@meta.com>
*/
#include <bpf/bpf.h>
+#include <errno.h>
#include <pthread.h>
#include <scx/common.h>
#include <sys/wait.h>
@@ -11,8 +12,14 @@
#include "maximal.bpf.skel.h"
#include "scx_test.h"
+enum {
+ RELOAD_ITERS = 1024,
+ RELOAD_THREADS = 2,
+};
+
static struct maximal *skel;
-static pthread_t threads[2];
+static pthread_t threads[RELOAD_THREADS];
+static int unexpected_errno;
bool force_exit = false;
@@ -31,32 +38,58 @@ static enum scx_test_status setup(void **ctx)
static void *do_reload_loop(void *arg)
{
- u32 i;
+ u32 i, failures = 0;
- for (i = 0; i < 1024 && !force_exit; i++) {
+ for (i = 0; i < RELOAD_ITERS && !force_exit; i++) {
struct bpf_link *link;
+ errno = 0;
link = bpf_map__attach_struct_ops(skel->maps.maximal_ops);
- if (link)
- bpf_link__destroy(link);
+ if (!link) {
+ int e = errno;
+
+ if (e != EBUSY)
+ __atomic_store_n(&unexpected_errno, e,
+ __ATOMIC_RELAXED);
+ failures++;
+ continue;
+ }
+
+ bpf_link__destroy(link);
}
- return NULL;
+ return (void *)(unsigned long)failures;
}
static enum scx_test_status run(void *ctx)
{
- int err;
+ unsigned long failures[RELOAD_THREADS] = {};
+ int err, i;
void *ret;
err = pthread_create(&threads[0], NULL, do_reload_loop, NULL);
SCX_FAIL_IF(err, "Failed to create thread 0");
err = pthread_create(&threads[1], NULL, do_reload_loop, NULL);
- SCX_FAIL_IF(err, "Failed to create thread 1");
+ if (err) {
+ force_exit = true;
+ pthread_join(threads[0], NULL);
+ SCX_FAIL("Failed to create thread 1");
+ }
SCX_FAIL_IF(pthread_join(threads[0], &ret), "thread 0 failed");
+ failures[0] = (unsigned long)ret;
+
SCX_FAIL_IF(pthread_join(threads[1], &ret), "thread 1 failed");
+ failures[1] = (unsigned long)ret;
+
+ SCX_FAIL_IF(unexpected_errno, "unexpected attach errno %d",
+ unexpected_errno);
+
+ for (i = 0; i < RELOAD_THREADS; i++)
+ SCX_FAIL_IF(failures[i] == RELOAD_ITERS,
+ "thread %d: every attach failed (%lu EBUSY)",
+ i, failures[i]);
return SCX_TEST_PASS;
}
diff --git a/tools/testing/selftests/sched_ext/scx_test.h b/tools/testing/selftests/sched_ext/scx_test.h
index 90b8d6915bb7..8490b01fff74 100644
--- a/tools/testing/selftests/sched_ext/scx_test.h
+++ b/tools/testing/selftests/sched_ext/scx_test.h
@@ -18,8 +18,6 @@ enum scx_test_status {
SCX_TEST_FAIL,
};
-#define EXIT_KIND(__ent) __COMPAT_ENUM_OR_ZERO("scx_exit_kind", #__ent)
-
struct scx_test {
/**
* name - The name of the testcase.
@@ -110,6 +108,41 @@ void scx_test_register(struct scx_test *test);
#define SCX_ASSERT(_x) SCX_FAIL_IF(!(_x), "Expected %s to be true (%lu)", \
#_x, (u64)(_x))
+/*
+ * SCX_ASSERT_ALIVE - Fail the test if the scheduler under test exited
+ * on its own between attach and this check, e.g. from a runtime error.
+ * A scheduler that dies mid-test freezes whatever state the test is
+ * about to assert on, which can make the assertions pass vacuously.
+ * uei.msg carries the actual error text, so print it alongside the
+ * recorded kind and exit code.
+ */
+#define SCX_ASSERT_ALIVE(__skel, __uei) \
+ do { \
+ if (UEI_EXITED(__skel, __uei)) \
+ SCX_FAIL("Scheduler exited unexpectedly" \
+ " (kind=%llu code=%lld msg='%s')", \
+ (unsigned long long)(__skel)->data->__uei.kind, \
+ (long long)(__skel)->data->__uei.exit_code, \
+ (__skel)->data->__uei.msg); \
+ } while (0)
+
+/*
+ * SCX_TIMED_WAIT_UEI - Wait for the scheduler under test to exit, i.e.
+ * its uei to be filled in, for up to @__ms iterations at ~1ms each.
+ * Returns true if the scheduler exited and false on timeout, so a
+ * scheduler that never exits fails the test instead of hanging it.
+ * The bound is iteration-based rather than wall-clock and stretches
+ * on a loaded system instead of failing early.
+ */
+#define SCX_TIMED_WAIT_UEI(__skel, __uei, __ms) \
+ ({ \
+ s64 __left = (__ms); \
+ \
+ while (__left-- > 0 && !UEI_EXITED(__skel, __uei)) \
+ usleep(1000); \
+ UEI_EXITED(__skel, __uei) != 0; \
+ })
+
#define SCX_ECODE_VAL(__ecode) ({ \
u64 __val = 0; \
bool __found = false; \
@@ -119,13 +152,25 @@ void scx_test_register(struct scx_test *test);
(s64)__val; \
})
+/*
+ * SCX_KIND_VAL - Resolve an scx_exit_kind enumerator from kernel BTF.
+ *
+ * Unlike __COMPAT_ENUM_OR_ZERO(), a missing enumerator fails the test
+ * loudly instead of silently resolving to 0 (== SCX_EXIT_NONE), which
+ * would make the comparison vacuous.
+ */
#define SCX_KIND_VAL(__kind) ({ \
- u64 __val = 0; \
- bool __found = false; \
+ u64 __val = 0; \
\
- __found = __COMPAT_read_enum("scx_exit_kind", #__kind, &__val); \
- SCX_ASSERT(__found); \
+ if (!__COMPAT_read_enum("scx_exit_kind", #__kind, &__val)) \
+ SCX_FAIL("scx_exit_kind.%s not found in kernel BTF", #__kind); \
__val; \
})
+/*
+ * EXIT_KIND - Alias of SCX_KIND_VAL() for resolving scx_exit_kind
+ * enumerator values, kept for readability at the EXIT_KIND() call sites.
+ */
+#define EXIT_KIND(__ent) SCX_KIND_VAL(__ent)
+
#endif // # __SCX_TEST_H__