How exactly does the core scheduler code (pick_next_task()) ask the scheduling classes whether they have any threads that want to run? We have already seen this, but I feel it's worthwhile repeating the following code fragment for clarity (called mostly from __schedule() and also from the thread migration code path):
// kernel/sched/core.c
[ ... ]
static inline struct task_struct *
pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
{
const struct sched_class *class;
struct task_struct *p;
[ ... ]
for_each_class(class) { p = class->pick_next_task(rq, NULL, NULL); if (p) return p; }
[ ... ]
Notice the object orientation in action: the class->pick_next_task() code, for all practical purposes, is invoking a method, pick_next_task(), of the scheduling class, class! The return value, conveniently, is the pointer to the task structure of the picked task...