Lunatik

scxModule

Linux Extensible Scheduler (sched_ext) integration.

This library allows Lua scripts to interact with the kernel’s sched_ext subsystem. It enables sched_ext/eBPF programs to call Lua functions for task scheduling, providing a flexible way to implement custom scheduling logic in Lua.

The primary mechanism involves an sched_ext program calling the bpf_luascx_run kfunc, which in turn invokes a Lua callback function previously registered using scx.attach().

The callback runs inside the sched_ext operation that calls the kfunc, and ops.enqueue runs with the runqueue lock of its CPU held, so a callback must not call print, a completion’s complete or a mailbox’s send: each can wake a task, and the wakeup takes that lock again on a CPU that already holds it. An allocation the callback’s Lua makes under memory pressure, which can wake kswapd, and the log of an error the callback raises can wake a task the same way.

Needs 6.12 and later, with CONFIG_SCHED_CLASS_EXT; without it the module loads and offers attach, which raises EOPNOTSUPP, and detach, which does nothing. The kfunc needs the module’s BTF: run sudo make btf_install before make, or the kernel logs missing module BTF, cannot register kfuncs and an eBPF program that calls bpf_luascx_run does not load. The eBPF side is a sched_ext struct_ops scheduler; tests/scx/scx_pass.bpf.c with tests/scx/pass.lua is a worked pair.

Class scx_ctx

scx_ctx:task () Returns the object for the current task.

scx

attach (callback) Registers a Lua callback function to be invoked by a sched_ext eBPF program.
detach () Unregisters the Lua callback function associated with the current Lunatik runtime.

Class scx_ctx in detail

sched_ext callback context, valid only while the callback runs. It is handed to the callback registered with scx.attach; its methods raise once the callback returns.
scx_ctx:task ()
Returns the object for the current task. The same task object is reused for every callback: it is valid only during the callback that returned it, and later it raises or reads the task of the callback then running.

Returns

    task

scx in detail

attach (callback)
Registers a Lua callback function to be invoked by a sched_ext eBPF program. When a sched_ext program calls the bpf_luascx_run kfunc, Lunatik will execute the registered Lua callback associated with the current Lunatik runtime. The runtime must be a hardirq one (lunatik run -c hardirq <script>). Calling it again replaces the previous callback.

The eBPF program declares the kfunc as:

 extern int bpf_luascx_run(char *key, size_t key__sz,
     struct task_struct *task, struct luascx_task_class *cls) __ksym;
  • key: the name of the Lunatik runtime, the script as given to lunatik run without .lua (e.g. “sched/policy”; a path keeps its directory). It is looked up in Lunatik’s table of active runtimes.
  • key__sz: sizeof the key array, the NUL terminator included.
  • the task pointer: the task being scheduled.
  • cls: where the decision is written, a struct of two u64, the dispatch queue and then the slice.

It returns 0 once the callback decided and cls is filled, and -1, leaving cls as it was, when cls is NULL or no callback decided.

Parameters

  • callback function Lua function to call. It receives one argument:

    ctx: An scx_ctx context object used to inspect the task.

    It returns the decision, the dispatch queue and then the slice in nanoseconds, which bpf_luascx_run writes to cls; a nil one takes SCX_DSQ_GLOBAL or SCX_SLICE_DFL. When it returns neither, or raises, bpf_luascx_run returns -1 and the decision is left to the eBPF program; a value that is not a number is logged as invalid task class and answered the same way.

Returns

    nil

Raises

EOPNOTSUPP on a kernel without sched_ext; runtime context mismatch unless the runtime is hardirq; not allowed while the runtime closes from a finalizer that runs at its close; or on allocation failure.

See also

Usage

-- sched/policy.lua, run with lunatik run -c hardirq sched/policy
local scx = require("scx")
local ext = require("linux.scx")

local function my_scheduler(ctx)
  local task = ctx:task()
  if task:comm() == "bash" then
    return ext.dsq.LOCAL, ext.slice.DFL
  end
end
scx.attach(my_scheduler)

-- In eBPF C code, to call the above Lua function:
-- char rt_key[] = "sched/policy"; // the script, without .lua
-- int ret = bpf_luascx_run(rt_key, sizeof(rt_key), p, cls);
detach ()
Unregisters the Lua callback function associated with the current Lunatik runtime. After calling this, bpf_luascx_run calls targeting this runtime invoke no Lua function: they log no callback attached, return -1 and leave the decision to the eBPF program.

Returns

    nil

Usage

scx.detach()