aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorOlivier Certner <olce@FreeBSD.org>2026-10-09 14:29:06 +0000
committerOlivier Certner <olce@FreeBSD.org>2026-11-03 17:42:22 +0000
commit510331fa376309ae0860b91bd501c9c5a73e86a7 (patch)
tree777a2c3a46b627432b47dd96206aced1d894cf37 /sys
parent28c31242758323499eaf8af1f03fc4ae4a960205 (diff)
sched: Automatically namespace schedulers' implementation functions
This renames back scheduler implementation functions to their old names, i.e., the same name as the interface functions, in the source code, while providing the infrastructure to still produce from them C symbols namespaced by the scheduler implementation, in order to avoid symbol collisions with interface dispatching functions and other scheduler implementations when multiple ones are compiled in. In a nutshell, the implementation consists in re-routing interface names to implementation names via the C preprocessor. The main reasons for this change are that different implementation names: 1. Break navigating code with ctags-like tools like in-tree ctags, Global and Universal Ctags. 2. Spoils inlining opportunities in internal scheduler code if not careful. This alternatively could be regained by changing call points to use scheduler-specific names, but that does not prevent people from inadvertently adding more calls to interface functions. Also, having to namespace calls with the implementation name in the implementation itself can be seen as code clutter. 3. Introduces avoidable cognitive burden, for example in the form of having to ask oneself whether internal scheduler functions should be namespaced or not, and then when calling them which their actual names are. However, C symbol collisions create difficulties with debugging and ELF manipulation tools, including when printing backtraces (which scheduler implementation is in use?). For example, as of this writing, 'disassemble' in GDB will choose one of the existing functions and disassemble it without mentioning the existing others; our ddb(4) will set a breakpoint on one of these functions only (which should be improved); etc. So keeping namespaced symbol names was desirable, which is why symbol re-routing via the C preprocessor was chosen. People wanting to extract information from ELF files will have to use full symbol names instead of source code names. This is certainly a drawback, but we expect that people will spend by far more time on the code rather than trying to disassemble some particular implementation function, so the inconvenience will barely occur in practice. Also, DWARF information matching machine code to source code location stays undisturbed and gdb will continue to display matching source code correctly. ctags-like tool are likely to never implement macro substitution when definitions are in other files, or if they do to never enable it by default, as this would considerably slow down source parsing (Universal Ctags reports a 2x slowdown just by enabling expansions for definitions that are in the *same* file). LSPs have not been tested; we however expect this change will cause nothing but minor annoyances when using them. Writing new calls to scheduler functions should work as usual in terms of help/completion (including in implementations, as corresponding implementation and interface functions have same signature). Even automatically producing implementation function signatures when adding a new definition is expected to work. Please report if not the case. The implementation of the machinery to substitute interface names by implementation names has two parts. First, a new generated per-implementation-specific header has to be included in each implementation ("sched_<NAME>_ns.h"). It contains simple C preprocessor substitutions, such as, taking the example of ULE: #define sched_clock sched_ule_clock #define sched_switch sched_ule_switch allowing to use the interface names in place of the implementation names in the implementation itself. It also checks that an implementation actually defined SCHED_IMPLEMENTATION and to the same value that was used to produce it. These headers are generated from the pattern header 'sys/kern/sched_ns.h' through directives in 'sys/conf/files', via the C preprocessor using the already existing X macros and some light post-processing by the new 'sys/tools/sched_impl_ns.awk' script. Second, <sys/sched.h> declares all implementation functions when included from an implementation, so that out-of-order references within the implementation do not cause problems, as it was before multiple schedulers could coexist. Implementations must define SCHED_IMPLEMENTATION to their name used as the namespacing symbol part (e.g., ule or 4bsd), which used to be the name passed as the first argument to DECLARE_SCHEDULER(). This argument is now redundant and has been removed. That same macro with same value has to be defined in the directives from 'sys/conf/files' for each implementation's namespacing header to be produced properly. For added safety, <sys/sched.h> does not provide interface functions' declarations when SCHED_IMPLEMENTATION is defined anymore, so that implementations can never inadvertently call these functions. Reviewed by: mchoo MFC after: 3 days Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D60644
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files24
-rw-r--r--sys/kern/sched_4bsd.c101
-rw-r--r--sys/kern/sched_ns.h52
-rw-r--r--sys/kern/sched_shim.c1
-rw-r--r--sys/kern/sched_ule.c107
-rw-r--r--sys/sys/sched.h52
-rw-r--r--sys/tools/sched_impl_ns.awk38
7 files changed, 264 insertions, 111 deletions
diff --git a/sys/conf/files b/sys/conf/files
index cd38d5b9b4ae..3bc46035c816 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3993,9 +3993,6 @@ kern/link_elf.c standard
kern/linker_if.m standard
kern/p1003_1b.c standard
kern/posix4_mib.c standard
-kern/sched_4bsd.c optional sched_4bsd
-kern/sched_shim.c standard
-kern/sched_ule.c optional sched_ule
kern/serdev_if.m standard
kern/stack_protector.c standard \
compile-with "${NORMAL_C:N-fstack-protector*}"
@@ -4719,6 +4716,27 @@ nlm/nlm_prot_svc.c optional nfslockd | nfsd
nlm/nlm_prot_xdr.c optional nfslockd | nfsd
nlm/sm_inter_xdr.c optional nfslockd | nfsd
+# Scheduler
+kern/sched_4bsd.c optional sched_4bsd
+sched_4bsd_ns.h optional sched_4bsd \
+ dependency "$S/kern/sched_ns.h $S/sys/sched.h \
+ $S/tools/sched_impl_ns.awk" \
+ compile-with "${CPP} -DSCHED_IMPLEMENTATION=4bsd \
+ $S/kern/sched_ns.h | \
+ ${AWK} -f $S/tools/sched_impl_ns.awk > ${.TARGET}" \
+ no-obj no-implicit-rule before-depend local \
+ clean "sched_4bsd_ns.h"
+kern/sched_ule.c optional sched_ule
+sched_ule_ns.h optional sched_ule \
+ dependency "$S/kern/sched_ns.h $S/sys/sched.h \
+ $S/tools/sched_impl_ns.awk" \
+ compile-with "${CPP} -DSCHED_IMPLEMENTATION=ule \
+ $S/kern/sched_ns.h | \
+ ${AWK} -f $S/tools/sched_impl_ns.awk > ${.TARGET}" \
+ no-obj no-implicit-rule before-depend local \
+ clean "sched_ule_ns.h"
+kern/sched_shim.c standard
+
# Linux Kernel Programming Interface
compat/linuxkpi/common/src/linux_80211.c optional compat_linuxkpi wlan \
compile-with "${LINUXKPI_C}"
diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c
index 84d30b596d37..fc06ad8f5e1b 100644
--- a/sys/kern/sched_4bsd.c
+++ b/sys/kern/sched_4bsd.c
@@ -48,6 +48,7 @@
#include <sys/proc.h>
#include <sys/resourcevar.h>
#include <sys/runq.h>
+#define SCHED_IMPLEMENTATION 4bsd
#include <sys/sched.h>
#include <sys/sdt.h>
#include <sys/smp.h>
@@ -67,6 +68,12 @@
#endif
/*
+ * Namespacing for implementation functions to have same name as interface
+ * functions in the code while retaining namespaced symbols in the kernel ELF.
+ */
+#include "sched_4bsd_ns.h"
+
+/*
* INVERSE_ESTCPU_WEIGHT is only suitable for statclock() frequencies in
* the range 100-256 Hz (approximately).
*/
@@ -161,7 +168,7 @@ static struct kproc_desc sched_kp = {
};
static void
-sched_4bsd_sysinit(void)
+sched_sysinit(void)
{
kproc_start(&sched_kp);
}
@@ -640,7 +647,7 @@ resetpriority_thread(struct thread *td)
}
static void
-sched_4bsd_setup(void)
+sched_setup(void)
{
/*
* Decay 95% of `ts_pctcpu' in 60 seconds; see CCPU_SHIFT
@@ -660,7 +667,7 @@ sched_4bsd_setup(void)
* This routine determines time constants after stathz and hz are setup.
*/
static void
-sched_4bsd_initticks(void)
+sched_initticks(void)
{
realstathz = stathz ? stathz : hz;
@@ -677,7 +684,7 @@ sched_4bsd_initticks(void)
* proc0_init()
*/
static void
-sched_4bsd_init(void)
+sched_init(void)
{
/*
@@ -689,14 +696,14 @@ sched_4bsd_init(void)
}
static void
-sched_4bsd_init_ap(void)
+sched_init_ap(void)
{
/* Nothing needed. */
}
static bool
-sched_4bsd_runnable(void)
+sched_runnable(void)
{
#ifdef SMP
return (runq_not_empty(&runq_global) ||
@@ -707,7 +714,7 @@ sched_4bsd_runnable(void)
}
static int
-sched_4bsd_rr_interval(void)
+sched_rr_interval(void)
{
/* Convert sched_slice from stathz to hz. */
@@ -774,7 +781,7 @@ sched_clock_tick(struct thread *td)
}
static void
-sched_4bsd_clock(struct thread *td, int cnt)
+sched_clock(struct thread *td, int cnt)
{
for ( ; cnt > 0; cnt--)
@@ -785,7 +792,7 @@ sched_4bsd_clock(struct thread *td, int cnt)
* Charge child's scheduling CPU usage to parent.
*/
static void
-sched_4bsd_exit(struct proc *p, struct thread *td)
+sched_exit(struct proc *p, struct thread *td)
{
KTR_STATE1(KTR_SCHED, "thread", sched_tdname(td), "proc exit",
@@ -796,7 +803,7 @@ sched_4bsd_exit(struct proc *p, struct thread *td)
}
static void
-sched_4bsd_exit_thread(struct thread *td, struct thread *child)
+sched_exit_thread(struct thread *td, struct thread *child)
{
KTR_STATE1(KTR_SCHED, "thread", sched_tdname(child), "exit",
@@ -812,13 +819,13 @@ sched_4bsd_exit_thread(struct thread *td, struct thread *child)
}
static void
-sched_4bsd_fork(struct thread *td, struct thread *childtd)
+sched_fork(struct thread *td, struct thread *childtd)
{
sched_fork_thread(td, childtd);
}
static void
-sched_4bsd_fork_thread(struct thread *td, struct thread *childtd)
+sched_fork_thread(struct thread *td, struct thread *childtd)
{
struct td_sched *ts, *tsc;
@@ -837,7 +844,7 @@ sched_4bsd_fork_thread(struct thread *td, struct thread *childtd)
}
static void
-sched_4bsd_nice(struct proc *p, int nice)
+sched_nice(struct proc *p, int nice)
{
struct thread *td;
@@ -852,7 +859,7 @@ sched_4bsd_nice(struct proc *p, int nice)
}
static void
-sched_4bsd_class(struct thread *td, int class)
+sched_class(struct thread *td, int class)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
td->td_pri_class = class;
@@ -891,7 +898,7 @@ sched_priority(struct thread *td, u_char prio)
* priority.
*/
static void
-sched_4bsd_lend_prio(struct thread *td, u_char prio)
+sched_lend_prio(struct thread *td, u_char prio)
{
td->td_flags |= TDF_BORROWING;
@@ -907,7 +914,7 @@ sched_4bsd_lend_prio(struct thread *td, u_char prio)
* of prio.
*/
static void
-sched_4bsd_unlend_prio(struct thread *td, u_char prio)
+sched_unlend_prio(struct thread *td, u_char prio)
{
u_char base_pri;
@@ -924,7 +931,7 @@ sched_4bsd_unlend_prio(struct thread *td, u_char prio)
}
static void
-sched_4bsd_prio(struct thread *td, u_char prio)
+sched_prio(struct thread *td, u_char prio)
{
u_char oldprio;
@@ -951,7 +958,7 @@ sched_4bsd_prio(struct thread *td, u_char prio)
}
static void
-sched_4bsd_ithread_prio(struct thread *td, u_char prio)
+sched_ithread_prio(struct thread *td, u_char prio)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
MPASS(td->td_pri_class == PRI_ITHD);
@@ -960,7 +967,7 @@ sched_4bsd_ithread_prio(struct thread *td, u_char prio)
}
static void
-sched_4bsd_user_prio(struct thread *td, u_char prio)
+sched_user_prio(struct thread *td, u_char prio)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
@@ -971,7 +978,7 @@ sched_4bsd_user_prio(struct thread *td, u_char prio)
}
static void
-sched_4bsd_lend_user_prio(struct thread *td, u_char prio)
+sched_lend_user_prio(struct thread *td, u_char prio)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
@@ -987,7 +994,7 @@ sched_4bsd_lend_user_prio(struct thread *td, u_char prio)
* Like the above but first check if there is anything to do.
*/
static void
-sched_4bsd_lend_user_prio_cond(struct thread *td, u_char prio)
+sched_lend_user_prio_cond(struct thread *td, u_char prio)
{
if (td->td_lend_user_pri == prio)
@@ -999,7 +1006,7 @@ sched_4bsd_lend_user_prio_cond(struct thread *td, u_char prio)
}
static void
-sched_4bsd_sleep(struct thread *td, int pri)
+sched_sleep(struct thread *td, int pri)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
@@ -1010,7 +1017,7 @@ sched_4bsd_sleep(struct thread *td, int pri)
}
static void
-sched_4bsd_switch(struct thread *td, int flags)
+sched_switch(struct thread *td, int flags)
{
struct thread *newtd;
struct mtx *tmtx;
@@ -1143,7 +1150,7 @@ sched_4bsd_switch(struct thread *td, int flags)
}
static void
-sched_4bsd_wakeup(struct thread *td, int srqflags)
+sched_wakeup(struct thread *td, int srqflags)
{
struct td_sched *ts;
@@ -1318,7 +1325,7 @@ sched_pickcpu(struct thread *td)
#endif
static void
-sched_4bsd_add(struct thread *td, int flags)
+sched_add(struct thread *td, int flags)
#ifdef SMP
{
cpuset_t tidlemsk;
@@ -1465,7 +1472,7 @@ sched_4bsd_add(struct thread *td, int flags)
#endif /* SMP */
static void
-sched_4bsd_rem(struct thread *td)
+sched_rem(struct thread *td)
{
struct td_sched *ts;
@@ -1495,7 +1502,7 @@ sched_4bsd_rem(struct thread *td)
* slot.
*/
static struct thread *
-sched_4bsd_choose(void)
+sched_choose(void)
{
struct thread *td;
struct runq *runq;
@@ -1540,7 +1547,7 @@ sched_4bsd_choose(void)
}
static void
-sched_4bsd_preempt(struct thread *td)
+sched_preempt(struct thread *td)
{
int flags;
@@ -1558,7 +1565,7 @@ sched_4bsd_preempt(struct thread *td)
}
static void
-sched_4bsd_userret_slowpath(struct thread *td)
+sched_userret_slowpath(struct thread *td)
{
thread_lock(td);
@@ -1568,7 +1575,7 @@ sched_4bsd_userret_slowpath(struct thread *td)
}
static void
-sched_4bsd_bind(struct thread *td, int cpu)
+sched_bind(struct thread *td, int cpu)
{
#ifdef SMP
struct td_sched *ts = td_get_sched(td);
@@ -1589,7 +1596,7 @@ sched_4bsd_bind(struct thread *td, int cpu)
}
static void
-sched_4bsd_unbind(struct thread* td)
+sched_unbind(struct thread* td)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
KASSERT(td == curthread, ("sched_unbind: can only bind curthread"));
@@ -1597,39 +1604,39 @@ sched_4bsd_unbind(struct thread* td)
}
static int
-sched_4bsd_is_bound(struct thread *td)
+sched_is_bound(struct thread *td)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
return (td->td_flags & TDF_BOUND);
}
static void
-sched_4bsd_relinquish(struct thread *td)
+sched_relinquish(struct thread *td)
{
thread_lock(td);
mi_switch(SW_VOL | SWT_RELINQUISH);
}
static int
-sched_4bsd_load(void)
+sched_load(void)
{
return (sched_tdcnt);
}
static int
-sched_4bsd_sizeof_proc(void)
+sched_sizeof_proc(void)
{
return (sizeof(struct proc));
}
static int
-sched_4bsd_sizeof_thread(void)
+sched_sizeof_thread(void)
{
return (sizeof(struct thread) + sizeof(struct td_sched));
}
static fixpt_t
-sched_4bsd_pctcpu(struct thread *td)
+sched_pctcpu(struct thread *td)
{
struct td_sched *ts;
@@ -1639,7 +1646,7 @@ sched_4bsd_pctcpu(struct thread *td)
}
static u_int
-sched_4bsd_estcpu(struct thread *td)
+sched_estcpu(struct thread *td)
{
return (td_get_sched(td)->ts_estcpu);
@@ -1649,7 +1656,7 @@ sched_4bsd_estcpu(struct thread *td)
* The actual idle process.
*/
static void
-sched_4bsd_idletd(void *dummy)
+sched_idletd(void *dummy)
{
struct pcpuidlestat *stat;
@@ -1691,7 +1698,7 @@ sched_throw_tail(struct thread *td)
* A CPU is entering for the first time.
*/
static void
-sched_4bsd_ap_entry(void)
+sched_ap_entry(void)
{
/*
@@ -1715,7 +1722,7 @@ sched_4bsd_ap_entry(void)
* A thread is exiting.
*/
static void
-sched_4bsd_throw(struct thread *td)
+sched_throw(struct thread *td)
{
MPASS(td != NULL);
@@ -1729,7 +1736,7 @@ sched_4bsd_throw(struct thread *td)
}
static void
-sched_4bsd_fork_exit(struct thread *td)
+sched_fork_exit(struct thread *td)
{
/*
@@ -1748,7 +1755,7 @@ sched_4bsd_fork_exit(struct thread *td)
}
static char *
-sched_4bsd_tdname(struct thread *td)
+sched_tdname(struct thread *td)
{
#ifdef KTR
struct td_sched *ts;
@@ -1764,7 +1771,7 @@ sched_4bsd_tdname(struct thread *td)
}
static void
-sched_4bsd_clear_tdname(struct thread *td)
+sched_clear_tdname(struct thread *td)
{
#ifdef KTR
struct td_sched *ts;
@@ -1775,7 +1782,7 @@ sched_4bsd_clear_tdname(struct thread *td)
}
static void
-sched_4bsd_affinity(struct thread *td)
+sched_affinity(struct thread *td)
{
#ifdef SMP
struct td_sched *ts;
@@ -1838,9 +1845,9 @@ sched_4bsd_affinity(struct thread *td)
}
static int
-sched_4bsd_find_l2_neighbor(int cpu)
+sched_find_l2_neighbor(int cpu)
{
return (-1);
}
-DECLARE_SCHEDULER(4bsd, "4BSD");
+DECLARE_SCHEDULER("4BSD");
diff --git a/sys/kern/sched_ns.h b/sys/kern/sched_ns.h
new file mode 100644
index 000000000000..0c71f4350fbc
--- /dev/null
+++ b/sys/kern/sched_ns.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2026 The FreeBSD Foundation
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * This software was developed by Olivier Certner <olce@FreeBSD.org>
+ * at Kumacom SARL under sponsorship from the FreeBSD Foundation.
+ */
+
+/*
+ * This file serves to generate a namespacing header for scheduler
+ * implementations.
+ *
+ * During build, it is pre-processed with CPP and only the (expanded) lines
+ * between the __START__ and __END__ lines below remain in the
+ * implementation-specific namespacing header.
+ *
+ * Lines produced between __START__ and __END__ below look like:
+ *
+ * # define sched_clock sched_ule_clock __NL__
+ * # define sched_switch sched_ule_switch __NL__
+ *
+ * and the build machinery substitutes __NL__ by newlines so the final result
+ * can be included and its lines recognized as '#define' preprocessing
+ * directives.
+ *
+ * A line between __START__ and __END__ starting with __CHECK_IMPLEMENTATION__
+ * is treated specially and generates code that checks whether
+ * SCHED_IMPLEMENTATION is the same as the value passed as the first argument
+ * (which is that of SCHED_IMPLEMENTATION here).
+ *
+ * See files 'sys/conf/files' and 'sys/tools/sched_impl_ns.awk' for the
+ * machinery.
+ */
+
+#define _KERNEL
+#include <sys/cdefs.h>
+#include <sys/sched.h>
+
+#define _SCHED_IMPL_DEFINE(args, ret_type, fn, ...) \
+ _SCHED_ITF_ARG2 args define SCHED_ITF_FUNCTION_NAME(fn) \
+ SCHED_ITF_IMPL_FUNCTION_NAME(_SCHED_ITF_ARG1 args, fn) \
+ __NL__
+
+#ifndef SCHED_IMPLEMENTATION
+#error SCHED_IMPLEMENTATION must be defined (via sys/conf/files)
+#endif
+
+__START__
+__CHECK_IMPLEMENTATION__ SCHED_IMPLEMENTATION
+SCHED_ITF_NOCOMMON(_SCHED_IMPL_DEFINE, SCHED_IMPLEMENTATION, #)
+__END__
diff --git a/sys/kern/sched_shim.c b/sys/kern/sched_shim.c
index 8fdd12e5f84d..e79221e9f771 100644
--- a/sys/kern/sched_shim.c
+++ b/sys/kern/sched_shim.c
@@ -15,6 +15,7 @@
#include <sys/proc.h>
#include <sys/runq.h>
#include <sys/sbuf.h>
+#define SCHED_SHIM
#include <sys/sched.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c
index 96acd31d6419..44c787b13ece 100644
--- a/sys/kern/sched_ule.c
+++ b/sys/kern/sched_ule.c
@@ -52,6 +52,7 @@
#include <sys/resource.h>
#include <sys/resourcevar.h>
#include <sys/runq.h>
+#define SCHED_IMPLEMENTATION ule
#include <sys/sched.h>
#include <sys/sdt.h>
#include <sys/smp.h>
@@ -75,6 +76,12 @@
#include <machine/cpu.h>
#include <machine/smp.h>
+/*
+ * Namespacing for implementation functions to have same name as interface
+ * functions in the code while retaining namespaced symbols in the kernel ELF.
+ */
+#include "sched_ule_ns.h"
+
#define TS_NAME_LEN (MAXCOMLEN + sizeof(" td ") + sizeof(__XSTRING(UINT_MAX)))
#define TDQ_NAME_LEN (sizeof("sched lock ") + sizeof(__XSTRING(MAXCPU)))
#define TDQ_LOADNAME_LEN (sizeof("CPU ") + sizeof(__XSTRING(MAXCPU)) - 1 + sizeof(" load"))
@@ -1637,7 +1644,7 @@ sched_setup_smp(void)
* information.
*/
static void
-sched_ule_setup(void)
+sched_setup(void)
{
struct tdq *tdq;
@@ -1662,7 +1669,7 @@ sched_ule_setup(void)
*/
/* ARGSUSED */
static void
-sched_ule_initticks(void)
+sched_initticks(void)
{
int incr;
@@ -1886,7 +1893,7 @@ sched_interact_fork(struct thread *td)
* Called from proc0_init() to setup the scheduler fields.
*/
static void
-sched_ule_init(void)
+sched_init(void)
{
struct td_sched *ts0;
@@ -1911,7 +1918,7 @@ sched_ule_init(void)
* after sched_init_ap().
*/
static void
-sched_ule_init_ap(void)
+sched_init_ap(void)
{
#ifdef SMP
@@ -1926,7 +1933,7 @@ sched_ule_init_ap(void)
* at most sched_slice stathz ticks.
*/
static int
-sched_ule_rr_interval(void)
+sched_rr_interval(void)
{
/* Convert sched_slice from stathz to hz. */
@@ -2046,7 +2053,7 @@ sched_thread_priority(struct thread *td, u_char prio)
* priority.
*/
static void
-sched_ule_lend_prio(struct thread *td, u_char prio)
+sched_lend_prio(struct thread *td, u_char prio)
{
td->td_flags |= TDF_BORROWING;
@@ -2062,7 +2069,7 @@ sched_ule_lend_prio(struct thread *td, u_char prio)
* of prio.
*/
static void
-sched_ule_unlend_prio(struct thread *td, u_char prio)
+sched_unlend_prio(struct thread *td, u_char prio)
{
u_char base_pri;
@@ -2082,7 +2089,7 @@ sched_ule_unlend_prio(struct thread *td, u_char prio)
* Standard entry for setting the priority to an absolute value.
*/
static void
-sched_ule_prio(struct thread *td, u_char prio)
+sched_prio(struct thread *td, u_char prio)
{
u_char oldprio;
@@ -2112,7 +2119,7 @@ sched_ule_prio(struct thread *td, u_char prio)
* Set the base interrupt thread priority.
*/
static void
-sched_ule_ithread_prio(struct thread *td, u_char prio)
+sched_ithread_prio(struct thread *td, u_char prio)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
MPASS(td->td_pri_class == PRI_ITHD);
@@ -2124,7 +2131,7 @@ sched_ule_ithread_prio(struct thread *td, u_char prio)
* Set the base user priority, does not effect current running priority.
*/
static void
-sched_ule_user_prio(struct thread *td, u_char prio)
+sched_user_prio(struct thread *td, u_char prio)
{
td->td_base_user_pri = prio;
@@ -2134,7 +2141,7 @@ sched_ule_user_prio(struct thread *td, u_char prio)
}
static void
-sched_ule_lend_user_prio(struct thread *td, u_char prio)
+sched_lend_user_prio(struct thread *td, u_char prio)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
@@ -2150,7 +2157,7 @@ sched_ule_lend_user_prio(struct thread *td, u_char prio)
* Like the above but first check if there is anything to do.
*/
static void
-sched_ule_lend_user_prio_cond(struct thread *td, u_char prio)
+sched_lend_user_prio_cond(struct thread *td, u_char prio)
{
if (td->td_lend_user_pri == prio)
@@ -2322,7 +2329,7 @@ thread_unblock_switch(struct thread *td, struct mtx *mtx)
* be assigned elsewhere via binding.
*/
static void
-sched_ule_switch(struct thread *td, int flags)
+sched_switch(struct thread *td, int flags)
{
struct thread *newtd;
struct tdq *tdq;
@@ -2461,7 +2468,7 @@ sched_ule_switch(struct thread *td, int flags)
* Adjust thread priorities as a result of a nice request.
*/
static void
-sched_ule_nice(struct proc *p, int nice)
+sched_nice(struct proc *p, int nice)
{
struct thread *td;
@@ -2480,7 +2487,7 @@ sched_ule_nice(struct proc *p, int nice)
* Record the sleep time for the interactivity scorer.
*/
static void
-sched_ule_sleep(struct thread *td, int prio)
+sched_sleep(struct thread *td, int prio)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
@@ -2501,7 +2508,7 @@ sched_ule_sleep(struct thread *td, int prio)
* Requires the thread lock on entry, drops on exit.
*/
static void
-sched_ule_wakeup(struct thread *td, int srqflags)
+sched_wakeup(struct thread *td, int srqflags)
{
struct td_sched *ts;
int slptick;
@@ -2541,7 +2548,7 @@ sched_ule_wakeup(struct thread *td, int srqflags)
* priority.
*/
static void
-sched_ule_fork(struct thread *td, struct thread *child)
+sched_fork(struct thread *td, struct thread *child)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
sched_pctcpu_update(td_get_sched(td), 1);
@@ -2560,7 +2567,7 @@ sched_ule_fork(struct thread *td, struct thread *child)
* Fork a new thread, may be within the same process.
*/
static void
-sched_ule_fork_thread(struct thread *td, struct thread *child)
+sched_fork_thread(struct thread *td, struct thread *child)
{
struct td_sched *ts;
struct td_sched *ts2;
@@ -2606,7 +2613,7 @@ sched_ule_fork_thread(struct thread *td, struct thread *child)
* Adjust the priority class of a thread.
*/
static void
-sched_ule_class(struct thread *td, int class)
+sched_class(struct thread *td, int class)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
@@ -2619,7 +2626,7 @@ sched_ule_class(struct thread *td, int class)
* Return some of the child's priority and interactivity to the parent.
*/
static void
-sched_ule_exit(struct proc *p, struct thread *child)
+sched_exit(struct proc *p, struct thread *child)
{
struct thread *td;
@@ -2637,7 +2644,7 @@ sched_ule_exit(struct proc *p, struct thread *child)
* causes new processes spawned by it to receive worse scores immediately.
*/
static void
-sched_ule_exit_thread(struct thread *td, struct thread *child)
+sched_exit_thread(struct thread *td, struct thread *child)
{
KTR_STATE1(KTR_SCHED, "thread", sched_tdname(child), "thread exit",
@@ -2655,7 +2662,7 @@ sched_ule_exit_thread(struct thread *td, struct thread *child)
}
static void
-sched_ule_preempt(struct thread *td)
+sched_preempt(struct thread *td)
{
struct tdq *tdq;
int flags;
@@ -2687,7 +2694,7 @@ sched_ule_preempt(struct thread *td)
* to static priorities in msleep() or similar.
*/
static void
-sched_ule_userret_slowpath(struct thread *td)
+sched_userret_slowpath(struct thread *td)
{
thread_lock(td);
@@ -2714,7 +2721,7 @@ td_slice(struct thread *td, struct tdq *tdq)
* and interrupt threads.
*/
static void
-sched_ule_clock(struct thread *td, int cnt)
+sched_clock(struct thread *td, int cnt)
{
struct tdq *tdq;
struct td_sched *ts;
@@ -2800,7 +2807,7 @@ sched_ule_clock(struct thread *td, int cnt)
}
static u_int
-sched_ule_estcpu(struct thread *td __unused)
+sched_estcpu(struct thread *td __unused)
{
return (0);
@@ -2811,7 +2818,7 @@ sched_ule_estcpu(struct thread *td __unused)
* cooperative idle threads.
*/
static bool
-sched_ule_runnable(void)
+sched_runnable(void)
{
struct tdq *tdq;
@@ -2824,7 +2831,7 @@ sched_ule_runnable(void)
* the run-queue while running however the load remains.
*/
static struct thread *
-sched_ule_choose(void)
+sched_choose(void)
{
struct thread *td;
struct tdq *tdq;
@@ -2901,7 +2908,7 @@ tdq_add(struct tdq *tdq, struct thread *td, int flags)
* Requires the thread lock on entry, drops on exit.
*/
static void
-sched_ule_add(struct thread *td, int flags)
+sched_add(struct thread *td, int flags)
{
struct tdq *tdq;
#ifdef SMP
@@ -2961,7 +2968,7 @@ sched_ule_add(struct thread *td, int flags)
* exit by calling sched_exit_thread() and sched_throw() themselves.
*/
static void
-sched_ule_rem(struct thread *td)
+sched_rem(struct thread *td)
{
struct tdq *tdq;
@@ -2984,7 +2991,7 @@ sched_ule_rem(struct thread *td)
* Fetch cpu utilization information. Updates on demand.
*/
static fixpt_t
-sched_ule_pctcpu(struct thread *td)
+sched_pctcpu(struct thread *td)
{
struct td_sched *ts;
u_int len;
@@ -3006,7 +3013,7 @@ sched_ule_pctcpu(struct thread *td)
* cpumask.
*/
static void
-sched_ule_affinity(struct thread *td)
+sched_affinity(struct thread *td)
{
#ifdef SMP
struct td_sched *const ts = td_get_sched(td);
@@ -3039,7 +3046,7 @@ sched_ule_affinity(struct thread *td)
* Bind a thread to a target cpu.
*/
static void
-sched_ule_bind(struct thread *td, int cpu)
+sched_bind(struct thread *td, int cpu)
{
struct td_sched *ts;
@@ -3063,7 +3070,7 @@ sched_ule_bind(struct thread *td, int cpu)
* Release a bound thread.
*/
static void
-sched_ule_unbind(struct thread *td)
+sched_unbind(struct thread *td)
{
struct td_sched *ts;
@@ -3077,7 +3084,7 @@ sched_ule_unbind(struct thread *td)
}
static int
-sched_ule_is_bound(struct thread *td)
+sched_is_bound(struct thread *td)
{
THREAD_LOCK_ASSERT(td, MA_OWNED);
return (td_get_sched(td)->ts_flags & TSF_BOUND);
@@ -3087,7 +3094,7 @@ sched_ule_is_bound(struct thread *td)
* Basic yield call.
*/
static void
-sched_ule_relinquish(struct thread *td)
+sched_relinquish(struct thread *td)
{
thread_lock(td);
mi_switch(SW_VOL | SWT_RELINQUISH);
@@ -3097,7 +3104,7 @@ sched_ule_relinquish(struct thread *td)
* Return the total system load.
*/
static int
-sched_ule_load(void)
+sched_load(void)
{
#ifdef SMP
int total;
@@ -3113,13 +3120,13 @@ sched_ule_load(void)
}
static int
-sched_ule_sizeof_proc(void)
+sched_sizeof_proc(void)
{
return (sizeof(struct proc));
}
static int
-sched_ule_sizeof_thread(void)
+sched_sizeof_thread(void)
{
return (sizeof(struct thread) + sizeof(struct td_sched));
}
@@ -3135,7 +3142,7 @@ sched_ule_sizeof_thread(void)
* The actual idle process.
*/
static void
-sched_ule_idletd(void *dummy)
+sched_idletd(void *dummy)
{
struct thread *td;
struct tdq *tdq;
@@ -3238,7 +3245,7 @@ sched_throw_grab(struct tdq *tdq)
* A CPU is entering for the first time.
*/
static void
-sched_ule_ap_entry(void)
+sched_ap_entry(void)
{
struct thread *newtd;
struct tdq *tdq;
@@ -3268,7 +3275,7 @@ sched_ule_ap_entry(void)
* A thread is exiting.
*/
static void
-sched_ule_throw(struct thread *td)
+sched_throw(struct thread *td)
{
struct thread *newtd;
struct tdq *tdq;
@@ -3299,7 +3306,7 @@ sched_ule_throw(struct thread *td)
* let fork do the rest of the work.
*/
static void
-sched_ule_fork_exit(struct thread *td)
+sched_fork_exit(struct thread *td)
{
struct tdq *tdq;
int cpuid;
@@ -3325,7 +3332,7 @@ sched_ule_fork_exit(struct thread *td)
* Create on first use to catch odd startup conditions.
*/
static char *
-sched_ule_tdname(struct thread *td)
+sched_tdname(struct thread *td)
{
#ifdef KTR
struct td_sched *ts;
@@ -3341,7 +3348,7 @@ sched_ule_tdname(struct thread *td)
}
static void
-sched_ule_clear_tdname(struct thread *td)
+sched_clear_tdname(struct thread *td)
{
#ifdef KTR
struct td_sched *ts;
@@ -3352,13 +3359,13 @@ sched_ule_clear_tdname(struct thread *td)
}
static void
-sched_ule_sysinit(void)
+sched_sysinit(void)
{
}
#ifdef SMP
static int
-sched_ule_find_child_with_core(int cpu, struct cpu_group *grp)
+sched_find_child_with_core(int cpu, struct cpu_group *grp)
{
int i;
@@ -3375,7 +3382,7 @@ sched_ule_find_child_with_core(int cpu, struct cpu_group *grp)
}
static int
-sched_ule_find_l2_neighbor(int cpu)
+sched_find_l2_neighbor(int cpu)
{
struct cpu_group *grp;
int i;
@@ -3388,7 +3395,7 @@ sched_ule_find_l2_neighbor(int cpu)
* Find the smallest CPU group that contains the given core.
*/
i = 0;
- while ((i = sched_ule_find_child_with_core(cpu, grp)) != -1) {
+ while ((i = sched_find_child_with_core(cpu, grp)) != -1) {
/*
* If the smallest group containing the given CPU has less
* than two members, we conclude the given CPU has no
@@ -3417,7 +3424,7 @@ sched_ule_find_l2_neighbor(int cpu)
}
#else
static int
-sched_ule_find_l2_neighbor(int cpu)
+sched_find_l2_neighbor(int cpu)
{
return (-1);
}
@@ -3505,4 +3512,4 @@ SYSCTL_INT(_kern_sched_ule, OID_AUTO, always_steal, CTLFLAG_RWTUN,
"Always run the stealer from the idle thread");
#endif
-DECLARE_SCHEDULER(ule, "ULE");
+DECLARE_SCHEDULER("ULE");
diff --git a/sys/sys/sched.h b/sys/sys/sched.h
index 75c56a864076..3a88c03d2d60 100644
--- a/sys/sys/sched.h
+++ b/sys/sys/sched.h
@@ -317,6 +317,8 @@
*/
#define _SCHED_ITF_ARG1(a0, ...) \
a0
+#define _SCHED_ITF_ARG2(a0, a1, ...) \
+ a1
#define _SCHED_ITF_ARG9(a0, a1, a2, a3, a4, a5, a6, a7, a8, ...) \
a8
#define _SCHED_ITF_NARGS(...) \
@@ -362,16 +364,18 @@
__CONCAT(fn, _impl)
#define SCHED_ITF_FUNCTION_NAME(fn) \
__CONCAT(sched_, fn)
-#define _SCHED_ITF_IMPL_FUNCTION_NAME(sched_name, fn) \
+#define SCHED_ITF_IMPL_FUNCTION_NAME(sched_name, fn) \
SCHED_ITF_FUNCTION_NAME(__CONCAT(__CONCAT(sched_name, _), \
fn))
-/*
- * C declaration of first part of interface functions.
- */
struct proc;
struct thread;
+#ifndef SCHED_IMPLEMENTATION
+
+/*
+ * C declaration of first part of interface functions.
+ */
/* Eliding argument names to avoid collisions with C++ keywords. */
#define _SCHED_ITF_FUN(args, ret_type, fn, ...) \
ret_type \
@@ -381,10 +385,29 @@ SCHED_ITF_DISPATCH(_SCHED_ITF_FUN, );
SCHED_ITF_WRAP(_SCHED_ITF_FUN, );
#undef _SCHED_ITF_FUN
+#else /* SCHED_IMPLEMENTATION */
+
+/*
+ * C declarations for implementation functions.
+ *
+ * SCHED_IMPLEMENTATION must be defined to the scheduler name as used in
+ * variable names (i.e., lower case, such as 4bsd or ule).
+ */
+#define _SCHED_ITF_FUN(args, ret_type, fn, ...) \
+ static ret_type \
+ SCHED_ITF_IMPL_FUNCTION_NAME(_SCHED_ITF_ARG1 args, fn) \
+ (SCHED_ITF_ARGS_PROTO_NAME(__VA_ARGS__));
+SCHED_ITF_NOCOMMON(_SCHED_ITF_FUN, SCHED_IMPLEMENTATION)
+#undef _SCHED_ITF_FUN
+
+#endif /* !SCHED_IMPLEMENTATION */
+
/*
* Common functions.
*/
+#ifndef SCHED_IMPLEMENTATION
+
static inline void
sched_userret(struct thread *td)
{
@@ -404,6 +427,8 @@ sched_userret(struct thread *td)
sched_userret_slowpath(td);
}
+#endif /* SCHED_IMPLEMENTATION */
+
static __inline void
sched_pin(void)
{
@@ -475,6 +500,7 @@ extern int dtrace_vtime_active;
extern dtrace_vtime_switch_func_t dtrace_vtime_switch_func;
#endif
+#if defined(SCHED_IMPLEMENTATION) || defined(SCHED_SHIM)
/*
* Scheduler instance structure.
*/
@@ -495,22 +521,26 @@ struct sched_selection {
};
#define _SCHED_DECLARE_FIELD_FUN(args, ret_type, fn, ...) \
- .SCHED_ITF_FIELD_NAME(fn) = &_SCHED_ITF_IMPL_FUNCTION_NAME( \
+ .SCHED_ITF_FIELD_NAME(fn) = &SCHED_ITF_IMPL_FUNCTION_NAME( \
_SCHED_ITF_ARG1 args, fn),
+#endif /* SCHED_IMPLEMENTATION || SCHED_SHIM */
-#define DECLARE_SCHEDULER(var_name, string_name) \
+#ifdef SCHED_IMPLEMENTATION
+#define DECLARE_SCHEDULER(string_name) \
static const struct sched_instance \
- __CONCAT(_sched_instance_, var_name) = { \
+ __CONCAT(_sched_instance_, SCHED_IMPLEMENTATION) = { \
SCHED_ITF_NOCOMMON(_SCHED_DECLARE_FIELD_FUN, \
- var_name) \
+ SCHED_IMPLEMENTATION) \
}; \
static const struct sched_selection \
- __CONCAT(_sched_selector_, var_name) = { \
+ __CONCAT(_sched_selector_, SCHED_IMPLEMENTATION) = { \
.name = string_name, \
- .instance = &__CONCAT(_sched_instance_, var_name), \
+ .instance = &__CONCAT(_sched_instance_, \
+ SCHED_IMPLEMENTATION), \
}; \
DATA_SET(sched_instance_set, \
- __CONCAT(_sched_selector_, var_name));
+ __CONCAT(_sched_selector_, SCHED_IMPLEMENTATION));
+#endif /* SCHED_IMPLEMENTATION */
void sched_instance_select(void);
diff --git a/sys/tools/sched_impl_ns.awk b/sys/tools/sched_impl_ns.awk
new file mode 100644
index 000000000000..7c515ac0ec4f
--- /dev/null
+++ b/sys/tools/sched_impl_ns.awk
@@ -0,0 +1,38 @@
+#!/usr/bin/awk -f
+
+# Copyright (c) 2026 The FreeBSD Foundation
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# This software was developed by Olivier Certner <olce.freebsd@certner.fr>
+# at Kumacom SARL under sponsorship from the FreeBSD Foundation.
+
+/^__END__$/ {
+ keep = 0;
+}
+
+keep != 0 && $1 == "__CHECK_IMPLEMENTATION__" {
+ # Check that SCHED_IMPLEMENTATION is defined
+ print "#if !defined(SCHED_IMPLEMENTATION)";
+ print "#error SCHED_IMPLEMENTATION not defined"
+ print "#endif"
+ # Check that it is consistent with that used to generate the header
+ printf("#define _SCHED_IMPL_CHECK_FAILED_%s\n", $2)
+ printf("/* Check that SCHED_IMPLEMENTATION is '%s'. */\n", $2);
+ print "__CONCAT(_SCHED_IMPL_CHECK_FAILED_, SCHED_IMPLEMENTATION)"
+ printf("#undef _SCHED_IMPL_CHECK_FAILED_%s\n", $2)
+ no_print = 1;
+}
+
+keep != 0 && no_print == 0 {
+ gsub("__NL__", "\n");
+ print;
+}
+
+{
+ no_print = 0;
+}
+
+/^__START__$/ {
+ keep = 1;
+}