Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sched_ext: Documentation: improve accuracy of task lifecycle pseudo-code

* Add ops.quiescent() and ops.runnable() to the sched_change path.
When a queued task has one of its scheduling properties changed
(e.g. nice, affinity), it goes through dequeue() -> quiescent() ->
(property change callback, e.g. ops.set_weight()) -> runnable() ->
enqueue().

* Change && to || in ops.enqueue() condition. We want to enqueue tasks
that have a non-zero slice and are not in any DSQ.

* Call ops.dispatch() and ops.dequeue() only for tasks that have had
ops.enqueue() called. This is to account for tasks direct-dispatched
from ops.select_cpu().

* Add a note explaining that the pseudo-code provides a simplified view
of the task lifecycle and list some examples of cases that the
pseudo-code does not account for.

Fixes: a4f61f0a1afd ("sched_ext: Documentation: Add ops.dequeue() to task lifecycle")
Signed-off-by: Kuba Piecuch <jpiecuch@google.com>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
Signed-off-by: Tejun Heo <tj@kernel.org>

authored by

Kuba Piecuch and committed by
Tejun Heo
71ba9a5c ff1befcb

+37 -8
+37 -8
Documentation/scheduler/sched-ext.rst
··· 408 408 Task Lifecycle 409 409 -------------- 410 410 411 - The following pseudo-code summarizes the entire lifecycle of a task managed 412 - by a sched_ext scheduler: 411 + The following pseudo-code presents a rough overview of the entire lifecycle 412 + of a task managed by a sched_ext scheduler: 413 413 414 414 .. code-block:: c 415 415 ··· 423 423 ops.runnable(); /* Task becomes ready to run */ 424 424 425 425 while (task_is_runnable(task)) { 426 - if (task is not in a DSQ && task->scx.slice == 0) { 426 + if (task is not in a DSQ || task->scx.slice == 0) { 427 427 ops.enqueue(); /* Task can be added to a DSQ */ 428 428 429 429 /* Task property change (i.e., affinity, nice, etc.)? */ 430 430 if (sched_change(task)) { 431 431 ops.dequeue(); /* Exiting BPF scheduler custody */ 432 + ops.quiescent(); 433 + 434 + /* Property change callback, e.g. ops.set_weight() */ 435 + 436 + ops.runnable(); 432 437 continue; 433 438 } 439 + 440 + /* Any usable CPU becomes available */ 441 + 442 + ops.dispatch(); /* Task is moved to a local DSQ */ 443 + ops.dequeue(); /* Exiting BPF scheduler custody */ 434 444 } 435 - 436 - /* Any usable CPU becomes available */ 437 - 438 - ops.dispatch(); /* Task is moved to a local DSQ */ 439 - ops.dequeue(); /* Exiting BPF scheduler custody */ 440 445 441 446 ops.running(); /* Task starts running on its assigned CPU */ 442 447 ··· 460 455 461 456 ops.disable(); /* Disable BPF scheduling for the task */ 462 457 ops.exit_task(); /* Task is destroyed */ 458 + 459 + Note that the above pseudo-code does not cover all possible state transitions 460 + and edge cases, to name a few examples: 461 + 462 + * ``ops.dispatch()`` may fail to move the task to a local DSQ due to a racing 463 + property change on that task, in which case ``ops.dispatch()`` will be 464 + retried. 465 + 466 + * The task may be direct-dispatched to a local DSQ from ``ops.enqueue()``, 467 + in which case ``ops.dispatch()`` and ``ops.dequeue()`` are skipped and we go 468 + straight to ``ops.running()``. 469 + 470 + * Property changes may occur at virtually any point during the task's lifecycle, 471 + not just when the task is queued and waiting to be dispatched. For example, 472 + changing a property of a running task will lead to the callback sequence 473 + ``ops.stopping()`` -> ``ops.quiescent()`` -> (property change callback) -> 474 + ``ops.runnable()`` -> ``ops.running()``. 475 + 476 + * A sched_ext task can be preempted by a task from a higher-priority scheduling 477 + class, in which case it will exit the tick-dispatch loop even though it is runnable 478 + and has a non-zero slice. 479 + 480 + See the "Scheduling Cycle" section for a more detailed description of how 481 + a freshly woken up task gets on a CPU. 463 482 464 483 Where to Look 465 484 =============