aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arm/arm/mp_machdep.c2
-rw-r--r--sys/arm64/arm64/mp_machdep.c2
-rw-r--r--sys/kern/init_main.c2
-rw-r--r--sys/kern/sched_4bsd.c54
-rw-r--r--sys/kern/sched_shim.c96
-rw-r--r--sys/kern/sched_ule.c62
-rw-r--r--sys/powerpc/aim/mp_cpudep.c2
-rw-r--r--sys/powerpc/booke/mp_cpudep.c2
-rw-r--r--sys/riscv/riscv/mp_machdep.c2
-rw-r--r--sys/sys/sched.h507
-rw-r--r--sys/x86/x86/mp_x86.c2
11 files changed, 379 insertions, 354 deletions
diff --git a/sys/arm/arm/mp_machdep.c b/sys/arm/arm/mp_machdep.c
index 9a4dc4e503e1..a745adef20bc 100644
--- a/sys/arm/arm/mp_machdep.c
+++ b/sys/arm/arm/mp_machdep.c
@@ -177,7 +177,7 @@ init_secondary(int cpu)
pc->pc_curthread = pc->pc_idlethread;
pc->pc_curpcb = pc->pc_idlethread->td_pcb;
set_curthread(pc->pc_idlethread);
- schedinit_ap();
+ sched_init_ap();
#ifdef VFP
vfp_init();
#endif
diff --git a/sys/arm64/arm64/mp_machdep.c b/sys/arm64/arm64/mp_machdep.c
index 30f4b30e64a7..2883e7dc74bf 100644
--- a/sys/arm64/arm64/mp_machdep.c
+++ b/sys/arm64/arm64/mp_machdep.c
@@ -280,7 +280,7 @@ init_secondary(uint64_t cpu)
/* Initialize curthread */
KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
pcpup->pc_curthread = pcpup->pc_idlethread;
- schedinit_ap();
+ sched_init_ap();
/* Initialize curpmap to match TTBR0's current setting. */
pmap0 = vmspace_pmap(&vmspace0);
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index cfca5d9d1296..829583cb687c 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -493,7 +493,7 @@ proc0_init(void *dummy __unused)
* Initialise scheduler resources.
* Add scheduler specific parts to proc, thread as needed.
*/
- schedinit(); /* scheduler gets its house in order */
+ sched_init(); /* scheduler gets its house in order */
/*
* Create process 0.
diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c
index 5f0246323dea..431957c048eb 100644
--- a/sys/kern/sched_4bsd.c
+++ b/sys/kern/sched_4bsd.c
@@ -1010,7 +1010,7 @@ sched_4bsd_sleep(struct thread *td, int pri)
}
static void
-sched_4bsd_sswitch(struct thread *td, int flags)
+sched_4bsd_switch(struct thread *td, int flags)
{
struct thread *newtd;
struct mtx *tmtx;
@@ -1842,54 +1842,4 @@ sched_4bsd_find_l2_neighbor(int cpu)
return (-1);
}
-struct sched_instance sched_4bsd_instance = {
-#define SLOT(name) .name = sched_4bsd_##name
- SLOT(load),
- SLOT(rr_interval),
- SLOT(runnable),
- SLOT(exit),
- SLOT(fork),
- SLOT(fork_exit),
- SLOT(class),
- SLOT(nice),
- SLOT(ap_entry),
- SLOT(exit_thread),
- SLOT(estcpu),
- SLOT(fork_thread),
- SLOT(ithread_prio),
- SLOT(lend_prio),
- SLOT(lend_user_prio),
- SLOT(lend_user_prio_cond),
- SLOT(pctcpu),
- SLOT(prio),
- SLOT(sleep),
- SLOT(sswitch),
- SLOT(throw),
- SLOT(unlend_prio),
- SLOT(user_prio),
- SLOT(userret_slowpath),
- SLOT(add),
- SLOT(choose),
- SLOT(clock),
- SLOT(idletd),
- SLOT(preempt),
- SLOT(relinquish),
- SLOT(rem),
- SLOT(wakeup),
- SLOT(bind),
- SLOT(unbind),
- SLOT(is_bound),
- SLOT(affinity),
- SLOT(sizeof_proc),
- SLOT(sizeof_thread),
- SLOT(tdname),
- SLOT(clear_tdname),
- SLOT(find_l2_neighbor),
- SLOT(init),
- SLOT(init_ap),
- SLOT(setup),
- SLOT(initticks),
- SLOT(sysinit),
-#undef SLOT
-};
-DECLARE_SCHEDULER(fourbsd_sched_selector, "4BSD", &sched_4bsd_instance);
+DECLARE_SCHEDULER(4bsd, "4BSD");
diff --git a/sys/kern/sched_shim.c b/sys/kern/sched_shim.c
index 9935c4e40aa8..8fdd12e5f84d 100644
--- a/sys/kern/sched_shim.c
+++ b/sys/kern/sched_shim.c
@@ -18,76 +18,10 @@
#include <sys/sched.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
-#include <machine/ifunc.h>
-
-const struct sched_instance *active_sched;
-#define __DEFINE_SHIM(__m, __r, __n, __p, __a) \
- DEFINE_IFUNC(, __r, __n, __p) \
- { \
- return (active_sched->__m); \
- }
-#define DEFINE_SHIM0(__m, __r, __n) \
- __DEFINE_SHIM(__m, __r, __n, (void), ())
-#define DEFINE_SHIM1(__m, __r, __n, __t1, __a1) \
- __DEFINE_SHIM(__m, __r, __n, (__t1 __a1), (__a1))
-#define DEFINE_SHIM2(__m, __r, __n, __t1, __a1, __t2, __a2) \
- __DEFINE_SHIM(__m, __r, __n, (__t1 __a1, __t2 __a2), (__a1, __a2))
-
-DEFINE_SHIM0(load, int, sched_load)
-DEFINE_SHIM0(rr_interval, int, sched_rr_interval)
-DEFINE_SHIM0(runnable, bool, sched_runnable)
-DEFINE_SHIM2(exit, void, sched_exit, struct proc *, p,
- struct thread *, childtd)
-DEFINE_SHIM2(fork, void, sched_fork, struct thread *, td,
- struct thread *, childtd)
-DEFINE_SHIM1(fork_exit, void, sched_fork_exit, struct thread *, td)
-DEFINE_SHIM2(class, void, sched_class, struct thread *, td, int, class)
-DEFINE_SHIM2(nice, void, sched_nice, struct proc *, p, int, nice)
-DEFINE_SHIM0(ap_entry, void, sched_ap_entry)
-DEFINE_SHIM2(exit_thread, void, sched_exit_thread, struct thread *, td,
- struct thread *, child)
-DEFINE_SHIM1(estcpu, u_int, sched_estcpu, struct thread *, td)
-DEFINE_SHIM2(fork_thread, void, sched_fork_thread, struct thread *, td,
- struct thread *, child)
-DEFINE_SHIM2(ithread_prio, void, sched_ithread_prio, struct thread *, td,
- u_char, prio)
-DEFINE_SHIM2(lend_prio, void, sched_lend_prio, struct thread *, td,
- u_char, prio)
-DEFINE_SHIM2(lend_user_prio, void, sched_lend_user_prio, struct thread *, td,
- u_char, pri)
-DEFINE_SHIM2(lend_user_prio_cond, void, sched_lend_user_prio_cond,
- struct thread *, td, u_char, pri)
-DEFINE_SHIM1(pctcpu, fixpt_t, sched_pctcpu, struct thread *, td)
-DEFINE_SHIM2(prio, void, sched_prio, struct thread *, td, u_char, prio)
-DEFINE_SHIM2(sleep, void, sched_sleep, struct thread *, td, int, prio)
-DEFINE_SHIM2(sswitch, void, sched_switch, struct thread *, td, int, flags)
-DEFINE_SHIM1(throw, void, sched_throw, struct thread *, td)
-DEFINE_SHIM2(unlend_prio, void, sched_unlend_prio, struct thread *, td,
- u_char, prio)
-DEFINE_SHIM2(user_prio, void, sched_user_prio, struct thread *, td,
- u_char, prio)
-DEFINE_SHIM1(userret_slowpath, void, sched_userret_slowpath,
- struct thread *, td)
-DEFINE_SHIM2(add, void, sched_add, struct thread *, td, int, flags)
-DEFINE_SHIM0(choose, struct thread *, sched_choose)
-DEFINE_SHIM2(clock, void, sched_clock, struct thread *, td, int, cnt)
-DEFINE_SHIM1(idletd, void, sched_idletd, void *, dummy)
-DEFINE_SHIM1(preempt, void, sched_preempt, struct thread *, td)
-DEFINE_SHIM1(relinquish, void, sched_relinquish, struct thread *, td)
-DEFINE_SHIM1(rem, void, sched_rem, struct thread *, td)
-DEFINE_SHIM2(wakeup, void, sched_wakeup, struct thread *, td, int, srqflags)
-DEFINE_SHIM2(bind, void, sched_bind, struct thread *, td, int, cpu)
-DEFINE_SHIM1(unbind, void, sched_unbind, struct thread *, td)
-DEFINE_SHIM1(is_bound, int, sched_is_bound, struct thread *, td)
-DEFINE_SHIM1(affinity, void, sched_affinity, struct thread *, td)
-DEFINE_SHIM0(sizeof_proc, int, sched_sizeof_proc)
-DEFINE_SHIM0(sizeof_thread, int, sched_sizeof_thread)
-DEFINE_SHIM1(tdname, char *, sched_tdname, struct thread *, td)
-DEFINE_SHIM1(clear_tdname, void, sched_clear_tdname, struct thread *, td)
-DEFINE_SHIM1(find_l2_neighbor, int, sched_find_l2_neighbor, int, cpu)
-DEFINE_SHIM0(init_ap, void, schedinit_ap)
+#include <machine/ifunc.h>
+static const struct sched_instance *active_sched;
SCHED_STAT_DEFINE(ithread_demotions, "Interrupt thread priority demotions");
SCHED_STAT_DEFINE(ithread_preemptions,
@@ -117,6 +51,18 @@ int __read_mostly dtrace_vtime_active;
dtrace_vtime_switch_func_t dtrace_vtime_switch_func;
#endif
+/*
+ * Define dispatchers for all functions described by SCHED_ITF_DISPATCH().
+ */
+#define DEFINE_SHIM(args, ret_type, fn, ...) \
+ DEFINE_IFUNC(, ret_type, SCHED_ITF_FUNCTION_NAME(fn), \
+ (SCHED_ITF_ARGS_PROTO_NAME(__VA_ARGS__))) \
+ { \
+ return (active_sched->SCHED_ITF_FIELD_NAME(fn)); \
+ }
+SCHED_ITF_DISPATCH(DEFINE_SHIM, );
+#undef DEFINE_SHIM
+
static char sched_name[32] = "ULE";
SET_DECLARE(sched_instance_set, struct sched_selection);
@@ -155,27 +101,27 @@ sched_instance_select(void)
}
void
-schedinit(void)
+sched_init(void)
{
if (active_sched == NULL)
panic("Cannot find scheduler %s", sched_name);
- active_sched->init();
+ active_sched->SCHED_ITF_FIELD_NAME(init)();
}
struct cpu_group __read_mostly *cpu_top; /* CPU topology */
static void
-sched_setup(void *dummy)
+sched_setup(void)
{
cpu_top = smp_topo();
- active_sched->setup();
+ active_sched->SCHED_ITF_FIELD_NAME(setup)();
}
SYSINIT(sched_setup, SI_SUB_RUN_QUEUE, SI_ORDER_FIRST, sched_setup, NULL);
static void
-sched_initticks(void *dummy)
+sched_initticks(void)
{
- active_sched->initticks();
+ active_sched->SCHED_ITF_FIELD_NAME(initticks)();
}
SYSINIT(sched_initticks, SI_SUB_CLOCKS, SI_ORDER_THIRD, sched_initticks,
NULL);
@@ -183,7 +129,7 @@ SYSINIT(sched_initticks, SI_SUB_CLOCKS, SI_ORDER_THIRD, sched_initticks,
static void
sched_sysinit(void)
{
- active_sched->sysinit();
+ active_sched->SCHED_ITF_FIELD_NAME(sysinit)();
}
SYSINIT(sched_sysinit, SI_SUB_LAST, SI_ORDER_FIRST, sched_sysinit, NULL);
diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c
index ea5f63311387..453e3958faf9 100644
--- a/sys/kern/sched_ule.c
+++ b/sys/kern/sched_ule.c
@@ -1899,14 +1899,14 @@ sched_ule_init(void)
}
/*
- * schedinit_ap() is needed prior to calling sched_throw(NULL) to ensure that
+ * sched_init_ap() is needed prior to calling sched_throw(NULL) to ensure that
* the pcpu requirements are met for any calls in the period between curthread
* initialization and sched_throw(). One can safely add threads to the queue
* before sched_throw(), for instance, as long as the thread lock is setup
* correctly.
*
* TDQ_SELF() relies on the below sched pcpu setting; it may be used only
- * after schedinit_ap().
+ * after sched_init_ap().
*/
static void
sched_ule_init_ap(void)
@@ -2320,7 +2320,7 @@ thread_unblock_switch(struct thread *td, struct mtx *mtx)
* be assigned elsewhere via binding.
*/
static void
-sched_ule_sswitch(struct thread *td, int flags)
+sched_ule_switch(struct thread *td, int flags)
{
struct thread *newtd;
struct tdq *tdq;
@@ -3240,7 +3240,7 @@ sched_ule_ap_entry(void)
tdq = TDQ_SELF();
- /* This should have been setup in schedinit_ap(). */
+ /* This should have been setup in sched_init_ap(). */
THREAD_LOCKPTR_ASSERT(curthread, TDQ_LOCKPTR(tdq));
TDQ_LOCK(tdq);
@@ -3418,58 +3418,6 @@ sched_ule_find_l2_neighbor(int cpu)
}
#endif
-struct sched_instance sched_ule_instance = {
-#define SLOT(name) .name = sched_ule_##name
- SLOT(load),
- SLOT(rr_interval),
- SLOT(runnable),
- SLOT(exit),
- SLOT(fork),
- SLOT(fork_exit),
- SLOT(class),
- SLOT(nice),
- SLOT(ap_entry),
- SLOT(exit_thread),
- SLOT(estcpu),
- SLOT(fork_thread),
- SLOT(ithread_prio),
- SLOT(lend_prio),
- SLOT(lend_user_prio),
- SLOT(lend_user_prio_cond),
- SLOT(pctcpu),
- SLOT(prio),
- SLOT(sleep),
- SLOT(sswitch),
- SLOT(throw),
- SLOT(unlend_prio),
- SLOT(user_prio),
- SLOT(userret_slowpath),
- SLOT(add),
- SLOT(choose),
- SLOT(clock),
- SLOT(idletd),
- SLOT(preempt),
- SLOT(relinquish),
- SLOT(rem),
- SLOT(wakeup),
- SLOT(bind),
- SLOT(unbind),
- SLOT(is_bound),
- SLOT(affinity),
- SLOT(sizeof_proc),
- SLOT(sizeof_thread),
- SLOT(tdname),
- SLOT(clear_tdname),
- SLOT(find_l2_neighbor),
- SLOT(init),
- SLOT(init_ap),
- SLOT(setup),
- SLOT(initticks),
- SLOT(sysinit),
-#undef SLOT
-};
-DECLARE_SCHEDULER(ule_sched_selector, "ULE", &sched_ule_instance);
-
static int
sysctl_kern_quantum(SYSCTL_HANDLER_ARGS)
{
@@ -3551,3 +3499,5 @@ SYSCTL_INT(_kern_sched_ule, OID_AUTO, always_steal, CTLFLAG_RWTUN,
&always_steal, 0,
"Always run the stealer from the idle thread");
#endif
+
+DECLARE_SCHEDULER(ule, "ULE");
diff --git a/sys/powerpc/aim/mp_cpudep.c b/sys/powerpc/aim/mp_cpudep.c
index 98acfc1a5c37..6bfec392f166 100644
--- a/sys/powerpc/aim/mp_cpudep.c
+++ b/sys/powerpc/aim/mp_cpudep.c
@@ -132,7 +132,7 @@ cpudep_ap_bootstrap(void)
#endif
pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
sp = pcpup->pc_curpcb->pcb_sp;
- schedinit_ap();
+ sched_init_ap();
return (sp);
}
diff --git a/sys/powerpc/booke/mp_cpudep.c b/sys/powerpc/booke/mp_cpudep.c
index a57c80102045..e38ce1bded99 100644
--- a/sys/powerpc/booke/mp_cpudep.c
+++ b/sys/powerpc/booke/mp_cpudep.c
@@ -83,7 +83,7 @@ cpudep_ap_bootstrap(void)
#endif
pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
sp = pcpup->pc_curpcb->pcb_sp;
- schedinit_ap();
+ sched_init_ap();
/* XXX shouldn't the pcb_sp be checked/forced for alignment here?? */
diff --git a/sys/riscv/riscv/mp_machdep.c b/sys/riscv/riscv/mp_machdep.c
index 9c81d9ee1043..5402c6d388ed 100644
--- a/sys/riscv/riscv/mp_machdep.c
+++ b/sys/riscv/riscv/mp_machdep.c
@@ -180,7 +180,7 @@ init_secondary(uint64_t hart)
/* Initialize curthread */
KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
pcpup->pc_curthread = pcpup->pc_idlethread;
- schedinit_ap();
+ sched_init_ap();
/* Setup and enable interrupts */
intr_pic_init_secondary();
diff --git a/sys/sys/sched.h b/sys/sys/sched.h
index e4cf848cf641..9d8524ee6464 100644
--- a/sys/sys/sched.h
+++ b/sys/sys/sched.h
@@ -36,6 +36,11 @@
/*-
* Copyright (c) 2002-2008, Jeffrey Roberson <jeff@freebsd.org>
* All rights reserved.
+ * Copyright (c) 2026 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Olivier Certner
+ * <olce@FreeBSD.org> at Kumacom SARL under sponsorship from the FreeBSD
+ * Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -71,51 +76,316 @@
#include <sys/linker_set.h>
#include <sys/sdt.h>
-struct proc;
-struct thread;
+/*
+ * Scheduler interface.
+ *
+ * The scheduler interface is the list of functions that external users can
+ * call. It consists of two parts: Functions that must be provided directly by
+ * a scheduler implementation (called an "instance"), and functions with
+ * a common implementation (which may indirectly call instance functions).
+ *
+ * The former are declared in an abstract manner with some of the SCHED_ITF_*()
+ * macros (SCHED_ITF_INTERNAL() being a notable exception), described in detail
+ * below. A fUN() line declares a function, and the final interface function
+ * name is the symbol in the third argument prefixed by 'sched_'. E.g., such
+ * lines:
+ *
+ * FUN((__VA_ARGS__), int, load)
+ * FUN((__VA_ARGS__), void, switch, struct thread *, td, int, flags)
+ *
+ * lead to the C declarations (among others):
+ *
+ * int sched_load(void);
+ * void sched_switch(struct thread *, int);
+ *
+ * and each implementation (instance) must implement corresponding functions,
+ * e.g., for ULE:
+ *
+ * int sched_ule_load(void);
+ * void sched_ule_switch(struct thread *td, int flags);
+ *
+ * Such interface functions are grouped and commented in the SCHED_ITF*()
+ * macros listing them.
+ *
+ * Functions with a common implementation are declared under "Common functions"
+ * below as commented plain C declarations.
+ */
/*
- * General scheduling info.
+ * Macros SCHED_ITF_*() define functions that must be provided by an instance.
+ * Please see their herald comments for details about their differences. They
+ * are X macros to avoid repetitions in function signatures, slot names,
+ * dispatch code, and scheduler instance declaration. They take as an argument
+ * the FUN() macro, which is expanded on each interface's function descriptor.
*
- * sched_load:
- * Total runnable non-ithread threads in the system.
+ * The arguments passed to FUN() are:
+ * - The variable arguments to the X macro, as the first argument.
+ * - The function descriptor, consisting of:
+ * - Field name in 'struct sched_instance'.
+ * - Return type.
+ * - Function name; prefixed by 'sched_' for the publicly visible functions,
+ * and by 'sched_<instance_name>_' for instance's implementation.
+ * - Function arguments, each being represented as a pair of successive macro
+ * parameters, the first being the argument's type and the second its name.
+ * Note that FUN() is passed a variable number of arguments for flexibility.
*
- * sched_runnable:
- * Runnable threads for this processor.
+ * In SCHED_ITF_*() macros, please keep the function's parameters on a separate
+ * line for clarity, even if everything would fit on a single line.
*/
-int sched_load(void);
-int sched_rr_interval(void);
-bool sched_runnable(void);
-/*
- * Proc related scheduling hooks.
+/* sched_add() arguments. */
+#define SRQ_BORING 0x0000 /* No special circumstances. */
+#define SRQ_YIELDING 0x0001 /* We are yielding (from mi_switch). */
+#define SRQ_OURSELF 0x0002 /* It is ourself (from mi_switch). */
+#define SRQ_INTR 0x0004 /* It is probably urgent. */
+#define SRQ_PREEMPTED 0x0008 /* has been preempted.. be kind */
+#define SRQ_BORROWING 0x0010 /* Priority updated due to prio_lend */
+#define SRQ_HOLD 0x0020 /* Return holding original td lock */
+#define SRQ_HOLDTD 0x0040 /* Return holding td lock */
+
+/*
+ * Functions to be directly dispatched to the active scheduler instance.
+ *
+ * These are implemented using ifuncs for zero-cost dispatch.
*/
-void sched_exit(struct proc *p, struct thread *childtd);
-void sched_fork(struct thread *td, struct thread *childtd);
-void sched_fork_exit(struct thread *td);
-void sched_class(struct thread *td, int class);
-void sched_nice(struct proc *p, int nice);
+#define SCHED_ITF_DISPATCH(FUN, ...) \
+ /* \
+ * General scheduling info. \
+ * \
+ * sched_load: \
+ * Total runnable non-ithread threads in the system. \
+ * \
+ * sched_runnable: \
+ * Runnable threads for this processor. \
+ */ \
+ FUN((__VA_ARGS__), int, load) \
+ FUN((__VA_ARGS__), int, rr_interval) \
+ FUN((__VA_ARGS__), bool, runnable) \
+ \
+ /* \
+ * Proc related scheduling hooks. \
+ */ \
+ FUN((__VA_ARGS__), void, exit, \
+ struct proc *, p, struct thread *, child) \
+ FUN((__VA_ARGS__), void, fork, \
+ struct thread *, td, struct thread *, child) \
+ FUN((__VA_ARGS__), void, fork_exit, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), void, class, \
+ struct thread *, td, int, class) \
+ FUN((__VA_ARGS__), void, nice, \
+ struct proc *, p, int, nice) \
+ \
+ /* \
+ * Threads are switched in and out, block on resources, \
+ * have temporary priorities inherited from their procs, \
+ * and use up cpu time. \
+ */ \
+ FUN((__VA_ARGS__), void, ap_entry) \
+ FUN((__VA_ARGS__), void, exit_thread, \
+ struct thread *, td, struct thread *, child) \
+ FUN((__VA_ARGS__), u_int, estcpu, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), void, fork_thread, \
+ struct thread *, td, struct thread *, child) \
+ FUN((__VA_ARGS__), void, ithread_prio, \
+ struct thread *, td, u_char, prio) \
+ FUN((__VA_ARGS__), void, lend_prio, \
+ struct thread *, td, u_char, prio) \
+ FUN((__VA_ARGS__), void, lend_user_prio, \
+ struct thread *, td, u_char, pri) \
+ FUN((__VA_ARGS__), void, lend_user_prio_cond, \
+ struct thread *, td, u_char, pri) \
+ FUN((__VA_ARGS__), fixpt_t, pctcpu, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), void, prio, \
+ struct thread *, td, u_char, prio) \
+ FUN((__VA_ARGS__), void, sleep, \
+ struct thread *, td, int, prio) \
+ FUN((__VA_ARGS__), void, switch, \
+ struct thread *, td, int, flags) \
+ FUN((__VA_ARGS__), void, throw, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), void, unlend_prio, \
+ struct thread *, td, u_char, prio) \
+ FUN((__VA_ARGS__), void, user_prio, \
+ struct thread *, td, u_char, prio) \
+ FUN((__VA_ARGS__), void, userret_slowpath, \
+ struct thread *, td) \
+ \
+ /* \
+ * Threads are moved on and off of run queues \
+ */ \
+ FUN((__VA_ARGS__), void, add, \
+ struct thread *, td, int, flags) \
+ FUN((__VA_ARGS__), struct thread *, choose) \
+ FUN((__VA_ARGS__), void, clock, \
+ struct thread *, td, int, cnt) \
+ FUN((__VA_ARGS__), void, idletd, \
+ void *, dummy) \
+ FUN((__VA_ARGS__), void, preempt, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), void, relinquish, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), void, rem, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), void, wakeup, \
+ struct thread *, td, int, srqflags) \
+ \
+ /* \
+ * Binding makes cpu affinity permanent while pinning is used \
+ * to temporarily hold a thread on a particular CPU. \
+ */ \
+ FUN((__VA_ARGS__), void, bind, \
+ struct thread *, td, int, cpu) \
+ FUN((__VA_ARGS__), void, unbind, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), int, is_bound, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), void, affinity, \
+ struct thread *, td) \
+ \
+ /* \
+ * These procedures tell the process data structure allocation \
+ * code how many bytes to actually allocate. \
+ */ \
+ FUN((__VA_ARGS__), int, sizeof_proc) \
+ FUN((__VA_ARGS__), int, sizeof_thread) \
+ \
+ /* \
+ * This routine provides a consistent thread name for use with \
+ * KTR graphing FUNctions. \
+ */ \
+ FUN((__VA_ARGS__), char *, tdname, \
+ struct thread *, td) \
+ FUN((__VA_ARGS__), void, clear_tdname, \
+ struct thread *, td) \
+ \
+ /* \
+ * Find an L2 neighbor of the given CPU or return -1 if none \
+ * found. This does not distinguish among multiple L2 \
+ * if the given CPU has more than one (it will always return \
+ * the same result in that case). \
+ */ \
+ FUN((__VA_ARGS__), int, find_l2_neighbor, \
+ int, cpu) \
+ \
+ /* \
+ * Fixup scheduler state for secondary APs \
+ */ \
+ FUN((__VA_ARGS__), void, init_ap)
/*
- * Threads are switched in and out, block on resources, have temporary
- * priorities inherited from their procs, and use up cpu time.
+ * Instance functions to be specifically wrapped.
+ *
+ * An explicit common implementation must be provided for these, and it is
+ * expected to call the instance's implementation.
+ */
+#define SCHED_ITF_WRAP(FUN, ...) \
+ /* \
+ * Initialize scheduler state for proc0 and thread0. \
+ */ \
+ FUN((__VA_ARGS__), void, init)
+
+/*
+ * Instance functions used internally.
+ *
+ * Functions here are not made available for external callers.
+ */
+#define SCHED_ITF_INTERNAL(FUN, ...) \
+ /* \
+ * Setup run queues ('cpu_top' filled by the shim machinery). \
+ */ \
+ FUN((__VA_ARGS__), void, setup) \
+ \
+ /* \
+ * Determines time constants after stathz and hz are setup. \
+ */ \
+ FUN((__VA_ARGS__), void, initticks) \
+ \
+ /* \
+ * Final steps after all the rest has been initialized. \
+ */ \
+ FUN((__VA_ARGS__), void, sysinit)
+
+/* All parts at once, but common functions. */
+#define SCHED_ITF_NOCOMMON(FUN, ...) \
+ SCHED_ITF_DISPATCH(FUN, __VA_ARGS__) \
+ SCHED_ITF_WRAP(FUN, __VA_ARGS__) \
+ SCHED_ITF_INTERNAL(FUN, __VA_ARGS__)
+
+/*
+ * Machinery to help define FUN() macros.
+ */
+#define _SCHED_ITF_ARG1(a0, ...) \
+ a0
+#define _SCHED_ITF_ARG9(a0, a1, a2, a3, a4, a5, a6, a7, a8, ...) \
+ a8
+#define _SCHED_ITF_NARGS(...) \
+ _SCHED_ITF_ARG9(__VA_ARGS__ __VA_OPT__(,) 4, ERR, 3, ERR, 2, \
+ ERR, 1, ERR, 0)
+#define _SCHED_ITF_NARGS_DISP(PREFIX, disp_args, full_args) \
+ __CONCAT(__CONCAT(PREFIX, _), _SCHED_ITF_NARGS disp_args) \
+ full_args
+#define _SCHED_ITF_ARGS_PAIR_ERR \
+ "Two macro arguments per interface function argument expected."
+#define _SCHED_ITF_ARGS_PROTO_NAME_0() \
+ void
+#define _SCHED_ITF_ARGS_PROTO_NAME_1(t1, a1) \
+ t1 a1
+#define _SCHED_ITF_ARGS_PROTO_NAME_2(t1, a1, t2, a2) \
+ t1 a1, t2 a2
+#define _SCHED_ITF_ARGS_PROTO_NAME_3(t1, a1, t2, a2, t3, a3) \
+ t1 a1, t2 a2, t3 a3
+#define _SCHED_ITF_ARGS_PROTO_NAME_4(t1, a1, t2, a2, t3, a3, t4, a4) \
+ t1 a1, t2 a2, t3 a3, t4 a4
+#define _SCHED_ITF_ARGS_PROTO_NAME_ERR(...) \
+ _SCHED_ITF_ARGS_PAIR_ERR
+#define SCHED_ITF_ARGS_PROTO_NAME(...) \
+ _SCHED_ITF_NARGS_DISP(_SCHED_ITF_ARGS_PROTO_NAME, \
+ (__VA_ARGS__), (__VA_ARGS__))
+#define _SCHED_ITF_ARGS_PROTO_NONAME_0() \
+ void
+#define _SCHED_ITF_ARGS_PROTO_NONAME_1(t1, a1) \
+ t1
+#define _SCHED_ITF_ARGS_PROTO_NONAME_2(t1, a1, t2, a2) \
+ t1, t2
+#define _SCHED_ITF_ARGS_PROTO_NONAME_3(t1, a1, t2, a2, t3, a3) \
+ t1, t2, t3
+#define _SCHED_ITF_ARGS_PROTO_NONAME_4(t1, a1, t2, a2, t3, a3, t4, a4) \
+ t1, t2, t3, t4
+#define _SCHED_ITF_ARGS_PROTO_NONAME_ERR(...) \
+ _SCHED_ITF_ARGS_PAIR_ERR
+#define SCHED_ITF_ARGS_PROTO_NONAME(...) \
+ _SCHED_ITF_NARGS_DISP(_SCHED_ITF_ARGS_PROTO_NONAME, \
+ (__VA_ARGS__), (__VA_ARGS__))
+
+#define SCHED_ITF_FIELD_NAME(fn) \
+ __CONCAT(fn, _impl)
+#define SCHED_ITF_FUNCTION_NAME(fn) \
+ __CONCAT(sched_, 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;
+
+/* Eliding argument names to avoid collisions with C++ keywords. */
+#define _SCHED_ITF_FUN(args, ret_type, fn, ...) \
+ ret_type \
+ SCHED_ITF_FUNCTION_NAME(fn) \
+ (SCHED_ITF_ARGS_PROTO_NONAME(__VA_ARGS__));
+SCHED_ITF_DISPATCH(_SCHED_ITF_FUN, );
+SCHED_ITF_WRAP(_SCHED_ITF_FUN, );
+#undef _SCHED_ITF_FUN
+
+/*
+ * Common functions.
*/
-void sched_ap_entry(void);
-void sched_exit_thread(struct thread *td, struct thread *child);
-u_int sched_estcpu(struct thread *td);
-void sched_fork_thread(struct thread *td, struct thread *child);
-void sched_ithread_prio(struct thread *td, u_char prio);
-void sched_lend_prio(struct thread *td, u_char prio);
-void sched_lend_user_prio(struct thread *td, u_char pri);
-void sched_lend_user_prio_cond(struct thread *td, u_char pri);
-fixpt_t sched_pctcpu(struct thread *td);
-void sched_prio(struct thread *td, u_char prio);
-void sched_sleep(struct thread *td, int prio);
-void sched_switch(struct thread *td, int flags);
-void sched_throw(struct thread *td);
-void sched_unlend_prio(struct thread *td, u_char prio);
-void sched_user_prio(struct thread *td, u_char prio);
-void sched_userret_slowpath(struct thread *td);
static inline void
sched_userret(struct thread *td)
@@ -136,43 +406,6 @@ sched_userret(struct thread *td)
sched_userret_slowpath(td);
}
-/*
- * Threads are moved on and off of run queues
- */
-void sched_add(struct thread *td, int flags);
-struct thread *sched_choose(void);
-void sched_clock(struct thread *td, int cnt);
-void sched_idletd(void *);
-void sched_preempt(struct thread *td);
-void sched_relinquish(struct thread *td);
-void sched_rem(struct thread *td);
-void sched_wakeup(struct thread *td, int srqflags);
-
-/*
- * Binding makes cpu affinity permanent while pinning is used to temporarily
- * hold a thread on a particular CPU.
- */
-void sched_bind(struct thread *td, int cpu);
-static __inline void sched_pin(void);
-void sched_unbind(struct thread *td);
-static __inline void sched_unpin(void);
-int sched_is_bound(struct thread *td);
-void sched_affinity(struct thread *td);
-
-/*
- * These procedures tell the process data structure allocation code how
- * many bytes to actually allocate.
- */
-int sched_sizeof_proc(void);
-int sched_sizeof_thread(void);
-
-/*
- * This routine provides a consistent thread name for use with KTR graphing
- * functions.
- */
-char *sched_tdname(struct thread *td);
-void sched_clear_tdname(struct thread *td);
-
static __inline void
sched_pin(void)
{
@@ -188,19 +421,9 @@ sched_unpin(void)
curthread->td_pinned--;
}
-void ast_scheduler(struct thread *td, int tda);
-
-/* sched_add arguments (formerly setrunqueue) */
-#define SRQ_BORING 0x0000 /* No special circumstances. */
-#define SRQ_YIELDING 0x0001 /* We are yielding (from mi_switch). */
-#define SRQ_OURSELF 0x0002 /* It is ourself (from mi_switch). */
-#define SRQ_INTR 0x0004 /* It is probably urgent. */
-#define SRQ_PREEMPTED 0x0008 /* has been preempted.. be kind */
-#define SRQ_BORROWING 0x0010 /* Priority updated due to prio_lend */
-#define SRQ_HOLD 0x0020 /* Return holding original td lock */
-#define SRQ_HOLDTD 0x0040 /* Return holding td lock */
-
-/* Scheduler stats. */
+/*
+ * Scheduler statistics.
+ */
#ifdef SCHED_STATS
DPCPU_DECLARE(long, sched_switch_stats[SWT_COUNT]);
@@ -237,6 +460,7 @@ SYSINIT(name, SI_SUB_LAST, SI_ORDER_MIDDLE, name ## _add_proc, NULL);
SCHED_STAT_DECLARE(ithread_demotions);
SCHED_STAT_DECLARE(ithread_preemptions);
+/* Dtrace. */
SDT_PROBE_DECLARE(sched, , , change__pri);
SDT_PROBE_DECLARE(sched, , , dequeue);
SDT_PROBE_DECLARE(sched, , , enqueue);
@@ -254,95 +478,50 @@ extern dtrace_vtime_switch_func_t dtrace_vtime_switch_func;
#endif
/*
- * Fixup scheduler state for proc0 and thread0
+ * Scheduler instance structure.
*/
-void schedinit(void);
-
-/*
- * Fixup scheduler state for secondary APs
- */
-void schedinit_ap(void);
-
-/*
- * Find an L2 neighbor of the given CPU or return -1 if none found. This
- * does not distinguish among multiple L2 neighbors if the given CPU has
- * more than one (it will always return the same result in that case).
- */
-int sched_find_l2_neighbor(int cpu);
-
-/*
- * The scheduler selection interface uses names that are reserved words in
- * C++, causing problems for downstream projects that use C++ in the
- * kernel.
- */
-#ifndef __cplusplus
-
+#define _SCHED_ITF_FUN(args, ret_type, fn, ...) \
+ ret_type (*SCHED_ITF_FIELD_NAME(fn)) \
+ (SCHED_ITF_ARGS_PROTO_NONAME(__VA_ARGS__));
struct sched_instance {
- int (*load)(void);
- int (*rr_interval)(void);
- bool (*runnable)(void);
- void (*exit)(struct proc *p, struct thread *childtd);
- void (*fork)(struct thread *td, struct thread *childtd);
- void (*fork_exit)(struct thread *td);
- void (*class)(struct thread *td, int class);
- void (*nice)(struct proc *p, int nice);
- void (*ap_entry)(void);
- void (*exit_thread)(struct thread *td, struct thread *child);
- u_int (*estcpu)(struct thread *td);
- void (*fork_thread)(struct thread *td, struct thread *child);
- void (*ithread_prio)(struct thread *td, u_char prio);
- void (*lend_prio)(struct thread *td, u_char prio);
- void (*lend_user_prio)(struct thread *td, u_char pri);
- void (*lend_user_prio_cond)(struct thread *td, u_char pri);
- fixpt_t (*pctcpu)(struct thread *td);
- void (*prio)(struct thread *td, u_char prio);
- void (*sleep)(struct thread *td, int prio);
- void (*sswitch)(struct thread *td, int flags);
- void (*throw)(struct thread *td);
- void (*unlend_prio)(struct thread *td, u_char prio);
- void (*user_prio)(struct thread *td, u_char prio);
- void (*userret_slowpath)(struct thread *td);
- void (*add)(struct thread *td, int flags);
- struct thread *(*choose)(void);
- void (*clock)(struct thread *td, int cnt);
- void (*idletd)(void *);
- void (*preempt)(struct thread *td);
- void (*relinquish)(struct thread *td);
- void (*rem)(struct thread *td);
- void (*wakeup)(struct thread *td, int srqflags);
- void (*bind)(struct thread *td, int cpu);
- void (*unbind)(struct thread *td);
- int (*is_bound)(struct thread *td);
- void (*affinity)(struct thread *td);
- int (*sizeof_proc)(void);
- int (*sizeof_thread)(void);
- char *(*tdname)(struct thread *td);
- void (*clear_tdname)(struct thread *td);
- int (*find_l2_neighbor)(int cpuid);
- void (*init)(void);
- void (*init_ap)(void);
- void (*setup)(void);
- void (*initticks)(void);
- /* Scheduler init, to be called only from 'sched_shim.c'. */
- void (*sysinit)(void);
+ SCHED_ITF_NOCOMMON(_SCHED_ITF_FUN, )
};
+#undef _SCHED_ITF_FUN
-extern const struct sched_instance *active_sched;
-
+/*
+ * Scheduler instance declaration.
+ */
struct sched_selection {
const char *name;
const struct sched_instance *instance;
};
-#define DECLARE_SCHEDULER(xsel_name, xsched_name, xsched_instance) \
- static struct sched_selection xsel_name = { \
- .name = xsched_name, \
- .instance = xsched_instance, \
- }; \
- DATA_SET(sched_instance_set, xsel_name);
+
+#define _SCHED_DECLARE_FIELD_FUN(args, ret_type, fn, ...) \
+ .SCHED_ITF_FIELD_NAME(fn) = &_SCHED_ITF_IMPL_FUNCTION_NAME( \
+ _SCHED_ITF_ARG1 args, fn),
+
+#define DECLARE_SCHEDULER(var_name, string_name) \
+ static const struct sched_instance \
+ __CONCAT(_sched_instance_, var_name) = { \
+ SCHED_ITF_NOCOMMON(_SCHED_DECLARE_FIELD_FUN, \
+ var_name) \
+ }; \
+ static const struct sched_selection \
+ __CONCAT(_sched_selector_, var_name) = { \
+ .name = string_name, \
+ .instance = &__CONCAT(_sched_instance_, var_name), \
+ }; \
+ DATA_SET(sched_instance_set, \
+ __CONCAT(_sched_selector_, var_name));
void sched_instance_select(void);
-#endif /* !__cplusplus */
+/*
+ * Miscellaneous.
+ */
+
+void ast_scheduler(struct thread *td, int tda);
+
#endif /* _KERNEL */
@@ -359,10 +538,10 @@ struct sched_param {
int sched_priority;
};
+#ifndef _KERNEL
/*
* POSIX scheduling declarations for userland.
*/
-#ifndef _KERNEL
#include <sys/cdefs.h>
#include <sys/_timespec.h>
#include <sys/_types.h>
diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c
index c01822569030..eff18b1875af 100644
--- a/sys/x86/x86/mp_x86.c
+++ b/sys/x86/x86/mp_x86.c
@@ -1085,7 +1085,7 @@ init_secondary_tail(void)
/* Initialize curthread. */
KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
PCPU_SET(curthread, PCPU_GET(idlethread));
- schedinit_ap();
+ sched_init_ap();
mca_init();