22.3.4.1 Introduction To Traditional Scheduling

Long before there was absolute priority (See Absolute Priority),
Unix systems were scheduling the CPU using this system. When Posix came
in like the Romans and imposed absolute priorities to accommodate the
needs of realtime processing, it left the indigenous Absolute Priority
Zero processes to govern themselves by their own familiar scheduling
policy.

Indeed, absolute priorities higher than zero are not available on many
systems today and are not typically used when they are, being intended
mainly for computers that do realtime processing. So this section
describes the only scheduling many programmers need to be concerned
about.

But just to be clear about the scope of this scheduling: Any time a
process with an absolute priority of 0 and a process with an absolute
priority higher than 0 are ready to run at the same time, the one with
absolute priority 0 does not run. If it’s already running when the
higher priority ready-to-run process comes into existence, it stops
immediately.

In addition to its absolute priority of zero, every process has another
priority, which we will refer to as "dynamic priority" because it changes
over time. The dynamic priority is meaningless for processes with
an absolute priority higher than zero.

The dynamic priority sometimes determines who gets the next turn on the
CPU. Sometimes it determines how long turns last. Sometimes it
determines whether a process can kick another off the CPU.

In Linux, the value is a combination of these things, but mostly it is
just determines the length of the time slice. The higher a process’
dynamic priority, the longer a shot it gets on the CPU when it gets one.
If it doesn’t use up its time slice before giving up the CPU to do
something like wait for I/O, it is favored for getting the CPU back when
it’s ready for it, to finish out its time slice. Other than that,
selection of processes for new time slices is basically round robin.
But the scheduler does throw a bone to the low priority processes: A
process’ dynamic priority rises every time it is snubbed in the
scheduling process. In Linux, even the fat kid gets to play.

The fluctuation of a process’ dynamic priority is regulated by another
value: The “nice” value. The nice value is an integer, usually in the
range -20 to 20, and represents an upper limit on a process’ dynamic
priority. The higher the nice number, the lower that limit.

On a typical Linux system, for example, a process with a nice value of
20 can get only 10 milliseconds on the CPU at a time, whereas a process
with a nice value of -20 can achieve a high enough priority to get 400
milliseconds.

The idea of the nice value is deferential courtesy. In the beginning,
in the Unix garden of Eden, all processes shared equally in the bounty
of the computer system. But not all processes really need the same
share of CPU time, so the nice value gave a courteous process the
ability to refuse its equal share of CPU time that others might prosper.
Hence, the higher a process’ nice value, the nicer the process is.
(Then a snake came along and offered some process a negative nice value
and the system became the crass resource allocation system we know
today).

Dynamic priorities tend upward and downward with an objective of
smoothing out allocation of CPU time and giving quick response time to
infrequent requests. But they never exceed their nice limits, so on a
heavily loaded CPU, the nice value effectively determines how fast a
process runs.

In keeping with the socialistic heritage of Unix process priority, a
process begins life with the same nice value as its parent process and
can raise it at will. A process can also raise the nice value of any
other process owned by the same user (or effective user). But only a
privileged process can lower its nice value. A privileged process can
also raise or lower another process’ nice value.