From: Su Zhidao <[email protected]> Add a test that verifies the sched_ext bypass mechanism does not prevent tasks from running to completion.
The test attaches a minimal global FIFO scheduler, spawns worker processes that complete a fixed computation, detaches the scheduler (which triggers bypass mode while workers are still active), and verifies all workers complete successfully under bypass mode. This exercises the scheduler attach/detach lifecycle and verifies that bypass mode (activated during unregistration to guarantee forward progress) does not stall running tasks. Signed-off-by: Su Zhidao <[email protected]> --- tools/testing/selftests/sched_ext/Makefile | 1 + .../testing/selftests/sched_ext/bypass.bpf.c | 32 ++++++ tools/testing/selftests/sched_ext/bypass.c | 105 ++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 tools/testing/selftests/sched_ext/bypass.bpf.c create mode 100644 tools/testing/selftests/sched_ext/bypass.c diff --git a/tools/testing/selftests/sched_ext/Makefile b/tools/testing/selftests/sched_ext/Makefile index a3bbe2c7911b..5fb6278d3f97 100644 --- a/tools/testing/selftests/sched_ext/Makefile +++ b/tools/testing/selftests/sched_ext/Makefile @@ -162,6 +162,7 @@ endef all_test_bpfprogs := $(foreach prog,$(wildcard *.bpf.c),$(INCLUDE_DIR)/$(patsubst %.c,%.skel.h,$(prog))) auto-test-targets := \ + bypass \ create_dsq \ dequeue \ enq_last_no_enq_fails \ diff --git a/tools/testing/selftests/sched_ext/bypass.bpf.c b/tools/testing/selftests/sched_ext/bypass.bpf.c new file mode 100644 index 000000000000..cb37c8df6834 --- /dev/null +++ b/tools/testing/selftests/sched_ext/bypass.bpf.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * BPF scheduler for bypass mode operational test. + * + * Implements a minimal global FIFO scheduler. The userspace side + * attaches this scheduler, runs worker tasks to completion, and + * verifies that tasks complete successfully. + * + * Copyright (c) 2026 Xiaomi Corporation. + */ +#include <scx/common.bpf.h> + +char _license[] SEC("license") = "GPL"; + +UEI_DEFINE(uei); + +void BPF_STRUCT_OPS(bypass_enqueue, struct task_struct *p, u64 enq_flags) +{ + scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); +} + +void BPF_STRUCT_OPS(bypass_exit, struct scx_exit_info *ei) +{ + UEI_RECORD(uei, ei); +} + +SEC(".struct_ops.link") +struct sched_ext_ops bypass_ops = { + .enqueue = (void *)bypass_enqueue, + .exit = (void *)bypass_exit, + .name = "bypass_test", +}; diff --git a/tools/testing/selftests/sched_ext/bypass.c b/tools/testing/selftests/sched_ext/bypass.c new file mode 100644 index 000000000000..952f09d76bdb --- /dev/null +++ b/tools/testing/selftests/sched_ext/bypass.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Verify the sched_ext bypass mechanism: spawn worker tasks and ensure + * they run to completion while a BPF scheduler is active. + * + * The bypass mechanism (activated on scheduler unregistration) must + * guarantee forward progress. This test verifies that worker tasks + * complete successfully when the scheduler is detached. + * + * Copyright (c) 2026 Xiaomi Corporation. + */ +#define _GNU_SOURCE +#include <unistd.h> +#include <sys/wait.h> +#include <bpf/bpf.h> +#include <scx/common.h> +#include "scx_test.h" +#include "bypass.bpf.skel.h" + +#define NUM_BYPASS_WORKERS 4 + +static void worker_fn(void) +{ + volatile int sum = 0; + int i; + + /* + * Do enough work to still be running when bpf_link__destroy() + * is called, ensuring tasks are active during bypass mode. + */ + for (i = 0; i < 10000000; i++) + sum += i; +} + +static enum scx_test_status setup(void **ctx) +{ + struct bypass *skel; + + skel = bypass__open(); + SCX_FAIL_IF(!skel, "Failed to open bypass skel"); + SCX_ENUM_INIT(skel); + SCX_FAIL_IF(bypass__load(skel), "Failed to load bypass skel"); + + *ctx = skel; + return SCX_TEST_PASS; +} + +static enum scx_test_status run(void *ctx) +{ + struct bypass *skel = ctx; + struct bpf_link *link; + pid_t pids[NUM_BYPASS_WORKERS]; + int i, status; + + link = bpf_map__attach_struct_ops(skel->maps.bypass_ops); + SCX_FAIL_IF(!link, "Failed to attach bypass scheduler"); + + /* + * Spawn worker processes. These must complete successfully + * even as the scheduler is active and then detached (which + * triggers bypass mode). + */ + for (i = 0; i < NUM_BYPASS_WORKERS; i++) { + pids[i] = fork(); + SCX_FAIL_IF(pids[i] < 0, "fork() failed for worker %d", i); + + if (pids[i] == 0) { + worker_fn(); + _exit(0); + } + } + + /* + * Detach the scheduler while workers are still running. This + * triggers bypass mode, which must guarantee forward progress + * for all active tasks. + */ + bpf_link__destroy(link); + + /* Workers must complete successfully under bypass mode */ + for (i = 0; i < NUM_BYPASS_WORKERS; i++) { + SCX_FAIL_IF(waitpid(pids[i], &status, 0) != pids[i], + "waitpid failed for worker %d", i); + SCX_FAIL_IF(!WIFEXITED(status) || WEXITSTATUS(status) != 0, + "Worker %d did not exit cleanly", i); + } + + SCX_EQ(skel->data->uei.kind, EXIT_KIND(SCX_EXIT_UNREG)); + + return SCX_TEST_PASS; +} + +static void cleanup(void *ctx) +{ + bypass__destroy(ctx); +} + +struct scx_test bypass_test = { + .name = "bypass", + .description = "Verify tasks complete during bypass mode", + .setup = setup, + .run = run, + .cleanup = cleanup, +}; +REGISTER_SCX_TEST(&bypass_test) -- 2.43.0

