\section{The code}

Here is a copy of the relevant code from
/usr/src/linux/kernel/sched.c, annotated and abridged.

\begin{screen}\begin{verbatim}
void schedule(void)
{
        int i,next,c;
        struct task_struct ** p;

/* check alarm, wake up any interruptible tasks that have got a signal */

        need_resched = 0;
        for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
\end{verbatim}\end{screen}
The process table is an array of pointers to {\tt struct task\_struct}
structures.
See /usr/include/linux/sched.h for the definition of this structure.
\begin{screen}\begin{verbatim}
                if (!*p || ((*p)->state != TASK_INTERRUPTIBLE))
                        continue;
                if ((*p)->timeout && (*p)->timeout < jiffies) {
\end{verbatim}\end{screen}
If a process has a timeout and has reached it, then {\tt jiffies} (the
number of 100th's of a second since system start) will have passed
{\tt timeout}.  {\tt timeout} was originally set as {\tt jiffies + \em
desired\_timeout}.
\begin{screen}\begin{verbatim}
                        (*p)->timeout = 0;
                        (*p)->state = TASK_RUNNING;
                } else if ((*p)->signal & ~(*p)->blocked)
\end{verbatim}\end{screen}
If the process has been sent a signal, and is no longer blocked, then
let the process be allowed to run again, when its turn comes.
\begin{screen}\begin{verbatim}
                        (*p)->state = TASK_RUNNING;
        }
\end{verbatim}\end{screen}
At this point, all runnable processes have been flagged as runnable,
and we are ready to choose one to run, by running through the process
table.  What we are looking for is the process with the largest
counter.  The counter for each runnable process is incremented each
time the scheduler is called by an amount that is weighted by the
priority, which is the kernel version of the `nice' value.  (It
differs in that the priority is never negative.)
\begin{screen}\begin{verbatim}
/* this is the scheduler proper: */

        while (1) {
                c = -1;
                next = 0;
                i = NR_TASKS;
                p = &task[NR_TASKS];
                while (--i) {
                        if (!*--p)
\end{verbatim}\end{screen}
If there is no process in this slot then don't bother\dots
\begin{screen}\begin{verbatim}
                                continue;
                        if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
                                c = (*p)->counter, next = i;
\end{verbatim}\end{screen}
If the counter is higher than any previous counter, then make the
process the next process, unless, of course, an even higher one is
encountered later in the loop.
\begin{screen}\begin{verbatim}
                }
                if (c)
                        break;
                for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                        if (*p)
                                (*p)->counter = ((*p)->counter >> 1) +
                                                (*p)->priority;
\end{verbatim}\end{screen}
Here is where the counter is set.  It is first divided by 2, and then
the priority is added.  Note that this happens only if no process has
been found to switch to, because of the {\tt break;} line.
\begin{screen}\begin{verbatim}
        }
        sti();
        switch_to(next);
}
\end{verbatim}\end{screen}
{\tt sti()} enables interrupts again, and {\tt switch\_to()} (defined
in linux/sched.h) sets things up so that when we return to {\tt
ret\_to\_sys\_call()}, we will return from {\tt ret\_to\_sys\_call()}
into the {\em new} process.

I have truncated {\tt do\_timer()} extremely, only showing the pieces
that relate specifically to {\tt schedule()}.  For information on the
rest, see the appropriate section.  For instance, for commentary on the
{\tt itimer} mechanism see the section on {\tt itimers}.  {\bf [I
suppose I need to {\em write} that section now\dots  I will need to
put a reference here to that section.]}  I have specifically left out
all the accounting stuff, all the timer stuff, and the floppy timer.
\begin{screen}\begin{verbatim}

static void do_timer(struct pt_regs * regs)
{
        unsigned long mask;
        struct timer_struct *tp = timer_table+0;
        struct task_struct ** task_p;

        jiffies++;
\end{verbatim}\end{screen}
Here is where {\tt jiffies} is incremented.  This is all-important to
the rest of the kernel, because all time calculations (except for
timed delay loops) are based on this variable.
\begin{screen}\begin{verbatim}

        if (current == task[0] || (--current->counter)<=0) {
                current->counter=0;
                need_resched = 1;
        }
}

\end{verbatim}\end{screen}
Don't let task 0 run if anything else can run, because task 0 doesn't
do anything.  If task 0 is running, the machine is idle, but don't let
it be idle if anything else is happening, so run schedudule as soon as
possible.  Set the {\tt need\_resched} flag if necessary so that
schedule gets called again as soon as possible.
