Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/sched_shim.c
- This file was added.
| /* | ||||||||||||||||||||||||||
| * Copyright 2026 The FreeBSD Foundation | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * SPDX-License-Identifier: BSD-2-Clause | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * This software was developed by Konstantin Belousov <kib@FreeBSD.org> | ||||||||||||||||||||||||||
| * under sponsorship from the FreeBSD Foundation. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| #include <sys/systm.h> | ||||||||||||||||||||||||||
| #include <sys/kernel.h> | ||||||||||||||||||||||||||
| #include <sys/lock.h> | ||||||||||||||||||||||||||
| #include <sys/proc.h> | ||||||||||||||||||||||||||
| #include <sys/runq.h> | ||||||||||||||||||||||||||
| #include <sys/sbuf.h> | ||||||||||||||||||||||||||
| #include <sys/sched.h> | ||||||||||||||||||||||||||
| #include <sys/sysctl.h> | ||||||||||||||||||||||||||
| #include <machine/ifunc.h> | ||||||||||||||||||||||||||
| const struct sched_instance *active_sched; | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, int, sched_load, (void)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->load); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, int, sched_rr_interval, (void)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->rr_interval); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, bool, sched_runnable, (void)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->runnable); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_exit, (struct proc *p, struct thread *childtd)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->exit); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_fork, (struct thread *td, struct thread *childtd)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->fork); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_fork_exit, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->fork_exit); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_class, (struct thread *td, int class)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->class); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_nice, (struct proc *p, int nice)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->nice); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_ap_entry, (void)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->ap_entry); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_exit_thread, (struct thread *td, struct thread *child)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->exit_thread); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, u_int, sched_estcpu, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->estcpu); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_fork_thread, (struct thread *td, struct thread *child)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->fork_thread); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_ithread_prio, (struct thread *td, u_char prio)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->ithread_prio); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_lend_prio, (struct thread *td, u_char prio)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->lend_prio); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_lend_user_prio, (struct thread *td, u_char pri)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->lend_user_prio); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_lend_user_prio_cond, (struct thread *td, u_char pri)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->lend_user_prio_cond); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, fixpt_t, sched_pctcpu, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->pctcpu); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_prio, (struct thread *td, u_char prio)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->prio); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_sleep, (struct thread *td, int prio)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->sleep); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_switch, (struct thread *td, int flags)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->sswitch); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_throw, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->throw); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_unlend_prio, (struct thread *td, u_char prio)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->unlend_prio); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_user_prio, (struct thread *td, u_char prio)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->user_prio); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_userret_slowpath, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->userret_slowpath); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, fixpt_t, sched_pctcpu_delta, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->pctcpu_delta); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_add, (struct thread *td, int flags)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->add); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, struct thread *, sched_choose, (void)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->choose); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_clock, (struct thread *td, int cnt)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->clock); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_idletd, (void *)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->idletd); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_preempt, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->preempt); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_relinquish, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->relinquish); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_rem, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->rem); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_wakeup, (struct thread *td, int srqflags)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->wakeup); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_bind, (struct thread *td, int cpu)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->bind); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_unbind, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->unbind); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, int, sched_is_bound, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->is_bound); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_affinity, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->affinity); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, int, sched_sizeof_proc, (void)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->sizeof_proc); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, int, sched_sizeof_thread, (void)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->sizeof_thread); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, char *, sched_tdname, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->tdname); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, sched_clear_tdname, (struct thread *td)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->clear_tdname); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, void, schedinit_ap, (void)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->init_ap); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, bool, sched_do_timer_accounting, (void)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->do_timer_accounting); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DEFINE_IFUNC(, int, sched_find_l2_neighbor, (int cpu)) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return (active_sched->find_l2_neighbor); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| static char sched_instance_name[32] = "ULE"; | ||||||||||||||||||||||||||
| SET_DECLARE(sched_instance_set, struct sched_selection); | ||||||||||||||||||||||||||
| void | ||||||||||||||||||||||||||
| sched_instance_select(void) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| struct sched_selection *s, **ss; | ||||||||||||||||||||||||||
| int i; | ||||||||||||||||||||||||||
| bool match; | ||||||||||||||||||||||||||
| TUNABLE_STR_FETCH("kern.sched.selection", sched_instance_name, | ||||||||||||||||||||||||||
| sizeof(sched_instance_name)); | ||||||||||||||||||||||||||
olce: I'd use `kern.sched.name` here, to match the `kern.sched.name` knob (see herald comment). | ||||||||||||||||||||||||||
| SET_FOREACH(ss, sched_instance_set) { | ||||||||||||||||||||||||||
| s = *ss; | ||||||||||||||||||||||||||
Done Inline ActionsThere's the problem here that 4BSD is not the default when it is the only one compiled-in. Could you change the logic so that, if there's only one scheduler, it is automatically selected? Additionally, if an explicit scheduler has been passed and is not available, then what about printing a warning and continuing running with some arbitrary one? olce: There's the problem here that 4BSD is not the default when it is the only one compiled-in. | ||||||||||||||||||||||||||
| match = true; | ||||||||||||||||||||||||||
| for (i = 0; s->name[i] != 0 && sched_instance_name[i] != 0; | ||||||||||||||||||||||||||
| i++) { | ||||||||||||||||||||||||||
| if (s->name[i] != sched_instance_name[i]) { | ||||||||||||||||||||||||||
| match = false; | ||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| if (!match) | ||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||
| active_sched = s->instance; | ||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| void | ||||||||||||||||||||||||||
| schedinit(void) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| if (active_sched == NULL) | ||||||||||||||||||||||||||
| panic("Cannot find scheduler %s", sched_instance_name); | ||||||||||||||||||||||||||
| active_sched->init(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| static void | ||||||||||||||||||||||||||
| sched_setup(void *dummy) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| active_sched->setup(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| SYSINIT(sched_setup, SI_SUB_RUN_QUEUE, SI_ORDER_FIRST, sched_setup, NULL); | ||||||||||||||||||||||||||
| static void | ||||||||||||||||||||||||||
| sched_initticks(void *dummy) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| active_sched->initticks(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| SYSINIT(sched_initticks, SI_SUB_CLOCKS, SI_ORDER_THIRD, sched_initticks, | ||||||||||||||||||||||||||
| NULL); | ||||||||||||||||||||||||||
| static void | ||||||||||||||||||||||||||
| sched_schedcpu(void) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| active_sched->schedcpu(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| SYSINIT(schedcpu, SI_SUB_LAST, SI_ORDER_FIRST, sched_schedcpu, NULL); | ||||||||||||||||||||||||||
| SYSCTL_NODE(_kern, OID_AUTO, sched, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, | ||||||||||||||||||||||||||
| "Scheduler"); | ||||||||||||||||||||||||||
| SYSCTL_STRING(_kern_sched, OID_AUTO, name, CTLFLAG_RD, sched_instance_name, 0, | ||||||||||||||||||||||||||
| "Scheduler name"); | ||||||||||||||||||||||||||
| static int | ||||||||||||||||||||||||||
| sysctl_kern_sched_available(SYSCTL_HANDLER_ARGS) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| struct sched_selection *s, **ss; | ||||||||||||||||||||||||||
| struct sbuf *sb, sm; | ||||||||||||||||||||||||||
| int error; | ||||||||||||||||||||||||||
| bool first; | ||||||||||||||||||||||||||
| sb = sbuf_new_for_sysctl(&sm, NULL, 0, req); | ||||||||||||||||||||||||||
| if (sb == NULL) | ||||||||||||||||||||||||||
| return (ENOMEM); | ||||||||||||||||||||||||||
| first = true; | ||||||||||||||||||||||||||
| SET_FOREACH(ss, sched_instance_set) { | ||||||||||||||||||||||||||
| s = *ss; | ||||||||||||||||||||||||||
| if (first) | ||||||||||||||||||||||||||
| first = false; | ||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||
| sbuf_cat(sb, ","); | ||||||||||||||||||||||||||
| sbuf_cat(sb, s->name); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| error = sbuf_finish(sb); | ||||||||||||||||||||||||||
| sbuf_delete(sb); | ||||||||||||||||||||||||||
| return (error); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| SYSCTL_PROC(_kern_sched, OID_AUTO, available, | ||||||||||||||||||||||||||
| CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, | ||||||||||||||||||||||||||
| NULL, 0, sysctl_kern_sched_available, "A", | ||||||||||||||||||||||||||
| "List of available schedulers"); | ||||||||||||||||||||||||||
Done Inline Actions
jrtc27: | ||||||||||||||||||||||||||
Done Inline Actions
jrtc27: | ||||||||||||||||||||||||||
Done Inline Actions
This currently matches if one is a prefix of the other, since the loop terminates as soon as you hit the terminator of one string and treats it as a match. This is one way of writing a fixed version (I believe), based on lib/libc/string/strcmp.c's structure. jrtc27: This currently matches if one is a prefix of the other, since the loop terminates as soon as… | ||||||||||||||||||||||||||
I'd use kern.sched.name here, to match the kern.sched.name knob (see herald comment).