Kylix for Delphi programmers - Linux Thread Priority

Under Delphi, TThread.Priority is an enum, and priorities like
THREAD_PRIORITY_LOWEST and THREAD_PRIORITY_ABOVE_NORMAL have
obvious interpretations. Under Kylix, scheduling is much more complicated. To start
with, Linux processes have both static and dynamic priorities. TThread.Priority affects
only the static priority. The dynamic priority is automatically increased whenever a
normal process is ready to run but has to wait for other processes, and can be manually
altered with the nice() or setpriority() system calls (below).

TThread.Priority is an integer from 0 to 99, where higher values have higher priority. In
addition, Thread Priority is tightly bound to the scheduling Policy. Tasks running with
superuser privileges can set Policy to SCHED_RR (real-time, round-robin scheduling),
SCHED_FIFO (real-time, first-in first-out scheduling) or SCHED_OTHER (regular, non-
real-time scheduling). Tasks running without superuser privileges can only use the
default SCHED_OTHER Policy.

In the two real time policies, SCHED_RR and SCHED_FIFO, Priority can be set to a
number from 1..99; in the standard policy, SCHED_OTHER, Priority must be 0. When a
process with a high static priority becomes ready to run (emerges from a wait or a sleep),
it preempts any running process with a lower static priority. SCHED_FIFO processes can
only be preempted by higher priority tasks; they run until they block, yield, or terminate.
SCHED_FIFO processes are not timeshared. SCHED_RR processes are much like
SCHED_FIFO, except that they are timeshared and can be preempted by a waiting
SCHED_RR task of the same priority. When the high priority process blocks, yields,
terminates or is pre-empted, the next process of the same priority is run. If there is no
process with the same priority ready to run, Linux gives the CPU (or "a CPU", on SMP
machines) to the ready process with the next highest priority. Thus, normal
SCHED_OTHER processes (with a static priority of 0) are only run if there is no real-
time processes (which have a higher static priority) ready to run.

The "Linux scheduling policies" table summarizes the meaning of the three scheduling
policies; see man sched_setscheduler for more information.

Linux scheduling policies

Policy

PriorityRange

Policy

SCHED_OTHER

0

The default Linux time-sharing policy. Processes are only run
when there is no waiting real-time process. You can change the
dynamic priority with the nice() and setpriority() system calls.

SCHED_FIFO

1..99

The basic real-time scheduling policy. The system maintains a
FIFO queue for each process priority; a FIFO process runs until
it surrenders control or is preempted by a higher priority
process. A preempted process stays at the head of its queue,
and resumes execution as soon as there are no higher priority
processes waiting.

SCHED_RR

1..99

A more sophisticated real-time scheduling policy. RR
processes are subject to preemption if they exceed their CPU
time "quantum" and there is at least one task of the same
priority waiting. RR processes preempted by higher priority
processes stay at the head of their queue and get the rest of
their "quantum" before they time out. Process that exceed their
quantum are placed at the end of the queue, and are not
executed again until all currently waiting processes of the same
priority have had a chance.

When there are more than one normal processes (with a static priority of 0) waiting for
execution, execution order is governed by the dynamic priority. Dynamic priority does
not apply to processes with a non-zero static priority. A normal process's dynamic
priority is automatically increased whenever the process is ready to run but has to wait
for other processes. When the scheduler is selecting a process to run, it will choose the
highest priority waiting process; if there is more than process with the same high priority,
it will choose the one that's been waiting longest. Dynamic priorities run from 20 to 20;
unlike static priorities, a smaller number is a higher priority. That is, a dynamic priority
of 0 is a higher priority than a dynamic priority of 20, and a dynamic priority of -20 is a
higher priority than a dynamic priority of 0.

You can retrieve a process's dynamic priority with Libc.getpriority(ProcessID, 0), and
if your process is running as a superuser - you can set it with Libc.setpriority(ProcessID,
0, NewPriority). Normal user processes can not use setpriority() which allows them to
raise priority, but they can use Libc.nice() to lower their priority. That is, applications
running as (for) normal users can only lower their priority or their thread's priority; they
can't raise it.

Note that a ThreadId is not the same as a process ID (PID). To get the thread's PID to
pass to getpriority() or setpriority(), you can use Libc.getpid. This returns the current
process's PID. If you call it from the main (GUI) thread, you will get a different result
than if you call it from a background thread.