CSF(9)

πŸ“¦ version 11.0, in nixpkgs unstable

πŸ’… CSF(9) β€” the NetBSD common scheduler framework πŸ’…

okay so welcome to the Kernel Developer's Manual, section 9 (that (9) is the kernel-dev section, iykyk), and today's main character is CSF β€” the NetBSD common scheduler framework. it's giving "the friend who organizes the group chat so everyone actually shows up on time" but for threads. 🧚✨


✨ SYNOPSIS ✨

like all good kernel things, it starts with an include. copy these exactly, bestie, no freestyling:

#include <sys/sched.h>

void
sched_rqinit(void);

void
sched_setup(void);

void
sched_cpuattach(struct cpu_info *);

void
sched_tick(struct cpu_info *);

void
sched_schedclock(lwp_t *);

bool
sched_curcpu_runnable_p(void);

lwp_t *
sched_nextlwp(void);

void
sched_enqueue(lwp_t *, bool);

void
sched_dequeue(lwp_t *);

void
sched_nice(struct proc *, int);

void
sched_proc_fork(struct proc *, struct proc *);

void
sched_proc_exit(struct proc *, struct proc *);

void
sched_lwp_fork(lwp_t *);

void
sched_lwp_exit(lwp_t *);

void
sched_setrunnable(lwp_t *);

void
sched_print_runqueue(void (*pr)(const char *, ...));

void
sched_pstats_hook(struct proc *, int);

void
sched_pstats(void *arg);

pri_t
sched_kpri(lwp_t *);

void
resched_cpu(lwp_t *);

void
setrunnable();

void
schedclock(lwp_t *);

void
sched_init(void);

that's a lot of prototypes but honestly? iconic. πŸ’…


πŸ’– DESCRIPTION πŸ’–

okay so CSF provides a modular and self-contained interface for implementing different thread scheduling algorithms. the different schedulers can be selected at compile-time β€” so you pick your fave before the build, not at runtime, no cap.

currently the schedulers available are:

  • sched_4bsd(9) β€” the traditional 4.4BSD thread scheduler, the OG 🫢
  • sched_m2(9) β€” which implements a SVR4/Solaris like approach ✨

the interface is split into two parts:

  1. a set of functions each scheduler needs to implement
  2. common functions used by all schedulers

🌸 SCHEDULER-SPECIFIC FUNCTIONS 🌸

the following functions have to be implemented by the individual scheduler. like, mandatory. no skipping. πŸ™ˆ

πŸŽ€ Scheduler initialization

  • void sched_cpuattach(struct cpu_info *) β€” per-CPU scheduler initialization routine. it's giving "getting each CPU dressed and ready for the day". πŸ’œ
  • void sched_rqinit(void) β€” initialize the scheduler's runqueue data structures. the runqueues need a glow-up before they can hold anything, bestie.
  • void sched_setup(void) β€” setup initial scheduling parameters and kick off timeout driven events. literally the "let's get this party started" function. πŸŽ‰

πŸ¦‹ Runqueue handling

runqueue handling is completely internal to the scheduler, so other parts of the kernel should access runqueues only through the following functions. like, respect the boundaries pls:

  • void sched_enqueue(lwp_t *, bool) β€” place an LWP within the scheduler's runqueue structures. get in, bestie, you're in the queue now. 🫢
  • void sched_dequeue(lwp_t *) β€” remove an LWP from the scheduler's runqueue structures. bye bestie, you're out. πŸ‘‹
  • lwp_t * sched_nextlwp(void) β€” return the LWP that should run the CPU next. the way this function picks the next one up? main character selection energy fr fr. πŸ‘‘
  • bool sched_curcpu_runnable_p(void) β€” indicate if there is a runnable LWP for the current CPU. just a little vibe check. βœ…
  • void sched_print_runqueue(void (*pr)(const char *, ...)) β€” print runqueues in DDB. debugging time, and the printer function is passed in as pr. πŸ’€

⭐ Core scheduler functions

  • void sched_tick(struct cpu_info *) β€” periodically called from hardclock(9). it determines if a reschedule is necessary, if the running LWP has used up its quantum. like a "you've had your turn, share the aux" moment. 😭
  • void sched_schedclock(lwp_t *) β€” periodically called from schedclock() in order to handle priority adjustment. ✨

πŸ“ Priority adjustment

  • void sched_nice(struct proc *, int) β€” recalculate the process priority according to its nice value. it's giving "be nice or be recalculated", and honestly both are valid. πŸŽ€

🌈 General helper functions

  • void sched_proc_fork(struct proc *, struct proc *) β€” inherit the scheduling history of the parent process after fork(). generational wealth but make it scheduling data. πŸ’–
  • void sched_proc_exit(struct proc *, struct proc *) β€” charge back a processes parent for its resource usage. yes, the parent gets the bill. that's just how it is. πŸ’Έ
  • void sched_lwp_fork(lwp_t *) β€” LWP-specific version of the above.
  • void sched_lwp_exit(lwp_t *) β€” LWP-specific version of the above.
  • void sched_setrunnable(lwp_t *) β€” scheduler-specific actions for setrunnable(). 🧚
  • void sched_pstats_hook(struct proc *, int) β€” scheduler-specific actions for sched_pstats(). ⭐

πŸ’œ COMMON SCHEDULER FUNCTIONS πŸ’œ

these are the shared ones, the communal wardrobe of the scheduler world:

  • pri_t sched_kpri(lwp_t *) β€” scale a priority level to a kernel priority level, usually for an LWP that is about to sleep. sleepy time conversion service. 😴
  • void sched_pstats(void *) β€” update process statistics and check CPU resource allocation. the "how are we all doing, is everyone okay" function. πŸ“Š
  • inline void resched_cpu(lwp_t *) β€” arrange for a reschedule. simple, effective, slay. πŸ’…
  • void setrunnable(lwp_t *) β€” change process state to be runnable, placing it on a runqueue if it is in memory, awakening the swapper otherwise. two paths, one function, both valid. πŸ¦‹
  • void schedclock(lwp_t *) β€” scheduler clock. periodically called from statclock(). ticking away like a little timekeeper fairy. ⏰
  • void sched_init(void) β€” initialize callout for sched_pstats() and call sched_setup() to initialize any other scheduler-specific data. the opening ceremony, basically. πŸŽ€
no cap: sched_curcpu_runnable_p() and sched_nextlwp() are in the runqueue-handling club, so if you're poking at runqueues directly from outside the scheduler you're doing it wrong. other parts of the kernel go through the functions above, periodt. βœ‹

πŸ”₯ CODE REFERENCES πŸ”₯

where to find all this in the source, for when you need to go read it yourself (and you will, bestie):

  • the CSF programming interface is defined within the file sys/sys/sched.h
  • functions common to all scheduler implementations are in sys/kern/kern_synch.c
  • the traditional 4.4BSD scheduler is implemented in sys/kern/sched_4bsd.c
  • the M2 scheduler is implemented in sys/kern/sched_m2.c

🌈 SEE ALSO 🌈

go read these next, they're all part of the same lore:


πŸ¦‹ HISTORY πŸ¦‹

the CSF appeared in NetBSD 5.0. a whole era. πŸ‘‘


πŸŽ€ AUTHORS πŸŽ€

the CSF was written by Daniel Sieger ⟨dsieger@NetBSD.org⟩. give them their flowers, fr fr. πŸ’


and that's the page, bestie!! 🫢 this one came from the Debian source line, dated October 27, 2014, and it's CSF(9) in the Kernel Developer's Manual β€” go forth and schedule responsibly βœ¨πŸ’…πŸŽ€

πŸ“¦ where this page comes from