3

I'm reading the start_kernel function in /init/main.c. The last function called in start_kernel is rest_init, and at the end of rest_init, cpu_idle is called.

Why is it called as the last function of the start_kernel routine, and what does it do?

5

To answer your first question,

What does cpu_idle do?

In general (without regards to the context of the question), when the CPU is in an idle state, it means that the kernel currently has no work for the CPU to perform, and thus the CPU is idly awaiting more work from the kernel.

You can think of how the kernel works as a manager, giving work to the CPU (according to a schedule). When no work is available for the CPU to take on, the CPU will be put into an idle state and await an interupt. You can read more about CPU interupts here.

With regards to the context of your question, you can read the exact implementation of what cpu_idle does:

cpu_idle(void)
{
    set_thread_flag(TIF_POLLING_NRFLAG);

    while (1) {
        /* FIXME -- EV6 and LCA45 know how to power down
           the CPU.  */

        while (!need_resched())
            cpu_relax();
        schedule();
    }
}

In summary, cpu_idle puts the CPU into a state where it is idle. This is achieved through using while loops to handle scheduling of processes when needed; else, the CPU is made idle with cpu_relax.

Why is it called as the last function of the start_kernel routine?

The reason this function is executed as the last instruction in the start_kernel routine is because the CPU has executed all necessary work to start the kernel - no further instructions will be executed, thus the CPU will become idle, awaiting the next task or interupt. To indicate this, the CPU should be put into an idle state, as it is no longer required for initialization of the kernel.

2

A central processing unit always has to be executing something. If there's nothing to do, it simply loops in an infinite loop, which an interrupt (such as the system heartbeat interrupt) will break it out of.

In older multi-process/multi-threaded operating systems, if the dispatcher (the low-level scheduler that picks and switches to the next thread to run off the runnable threads queue) finds no thread ready to run it would simply enter such an infinite loop.

This is a problem for multi-processor operating systems, though, as the infinite loop is executed in the context of whatever thread the dispatcher was leaving. This could end up with the same thread "running" on two processors at once, which causes a range of problems.

So a more recent (comparatively more recent, that is; as this idea is some several decades old) design was to have, for each processor in the system, an idle thread. This thread does nothing but loop indefinitely, and is always runnable. So there is always a thread that the dispatcher can pick, and there's never a situation where there is no runnable thread for a processor to run.

In old versions of actual Unix, when system initialization has finished, the initialization code has set up data structures describing it as process #0. This has the traditional name of the "swapper process", because of what it did. It had to do something after initialization had finished, so what it did was run the code that swapped process segments between main RAM and the DASD swap area.

The idea of swapping went away in the late 1970s with the advent of demand paging designs; and process #0 became first the idle process and then the system process that contained all of the idle threads.

And that is what is also happening in Linux.

Of course, power management has been a consideration for over a quarter of a century at this point, and the traditional infinite loop of an unconditional branch instruction branching to itself causes a lot of unnecessary busywork and power drain. Modern (again a relative term) idle threads invoke special processor instructions that instruct the executing processor to wait, potentially lowering its clock rate to save power, for it to receive a hardware interrupt. (Over the years on x86 instruction architectures this has changed from hlt to pause, a.k.a. rep nop, trading the complete release of resources by an execution core within a "hyperthreaded" processor for cross-processor shoulder taps that do not involve interrupts, effectively turning idle threads into perpetual waiters for a spin lock.)

Further reading

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.