- To move a task from the blocked state to the ready state (TASK_RUNNING), try_to_wake_up() is called + try_to_wake_up() changes the state to TASK_WAKING, then invokes select_task_rq() (with all rqs unlocked!) + select_task_rq() -> p->sched_class->select_task_rq() + If a new rq is selected for the task, set_task_cpu() is invoked + set_task_cpu() might invoke p->sched_class->migrate_task_rq() to notify the scheduling class that the task is migrating! + Then, after deciding on which core the task will be scheduled (in which rq it will be inserted), invokes ttwu_queue() + ttwu_queue() locks the rq, then invokes ttwu_do_activate() + ttwu_do_activate() -> activate_task() -> enqueue_task() -> p->sched_class->enqueue_task() + ttwu_do_activate() -> ttwu_do_wakeup() + ttwu_do_wakeup() finally sets the state to TASK_RUNNING, eventually invokes p->sched_class->task_woken() and updates some statistics - To block a task, change its state to something different from TASK_RUNNING and invoked the scheduler + __schedule() is invoked; "prev" is the previous "current" (the task that is going to be blocked) + If the task can be woken up by a signal (TASK_INTERRUPTIBLE) and there are pending signals, signal_pending_state(prev->state, prev)) is true + Then, the task does not block (prev->state is set again to TASK_RUNNING) + Otherwise, deactivate_task() is invoked + deactivate_task() -> dequeue_task() -> p->sched_class->dequeue_task() - To select a new task to be scheduled, __schedule() invokes pick_next_task() + pick_next_task() has an optimization: if all tasks are in the fair scheduling class (CFS: SCHED_OTHER & friends), then it directly invokes pick_next_task_fair() + Small complication: pick_next_task_fair() might return RETRY_TASK, meaning that in the meanwhile a ready task appeared in a high priority class (pick_next_task_fair() might release the rq lock!) + Otherwise, it invokes class->balance() in all scheduling classes, then put_prev_task() + Then, it invokes class->pick_next_task(rq) (starting from high priority scheduling classes and going down) until a task is selected. The lowest priority scheduling class (idle scheduling class) always has a ready task (the idle task), so a task is guaranteed to be found! - As a last thing, __schedule() invokes balance_callback() -> the pending push and pull operations are performed The scheduling class methods actually work on the specific rq. For example, the deadline class defines enqueue_task_dl() as enqueue_task(), and enqueue_task_dl() takes care of updating the task scheduling deadline (if needed) and inserting the task's scheduling entity (specifically, its dl scheduling entity) in the RB tree representing the ready task list ordered by scheduling deadline.