Namuthan
Namuthan

Reputation: 45

Why is there an infinite loop at the end of do_exit() defined in kernel/exit.c?

In the Linux kernel, I am confused about the purpose of having the loop at the end of do_exit().

Isn't the call to schedule() the last code that will be ever executed by do_exit()..?

666 void do_exit(long code)
667 {
668         struct task_struct *tsk = current;
669         int group_dead;
670 
671         ..........

833         /* causes final put_task_struct in finish_task_switch(). */
834         tsk->state = TASK_DEAD;
835         tsk->flags |= PF_NOFREEZE;      /* tell freezer to ignore us */
836         schedule();
837         BUG();
838         /* Avoid "noreturn function does return".  */
839         for (;;)
840                 cpu_relax();    /* For when BUG is null */
841 }
842 

Upvotes: 1

Views: 1144

Answers (1)

Michael Petch
Michael Petch

Reputation: 47593

Depending on the kernel it may appear differently but generally the structure is the same.

In some implementations it starts with:

NORET_TYPE void do_exit(long code)

NORET_TYPE may be different across varying GCC compilers (it may be an attribute that marks a no return function) or it may be volatile. What does such a declaration on a function do? It effectively says I won't return. You can find more about it in the GCC documentation which says:

The attribute noreturn is not implemented in GCC versions earlier than 2.5. An alternative way to declare that a function does not return, which works in the current version and in some older versions, is as follows:

     typedef void voidfn ();         
     volatile voidfn fatal;

volatile void functions are non-conforming extensions to the C standard created by the GCC developers. You won't find it in the ANSI C Standard (C89).

It happens to be when the kernel reaches do_exit() it doesn't intend to return from the function.Generally it will block indefinitely or until something resets the system (usually). The problem is that if you mark a function as not returning the compiler will warn you if your function exits. So you generally see an infinite loop of some sort (a while, for, goto etc). In your case it does:

/* Avoid "noreturn function does return".  */
for (;;) 

Interestingly enough the comment pretty much gives the reason. noreturn function does return is a gcc compiler warning. an infinite loop that is obvious to the compiler (like for (;;)) is enough to stop the compiler from complaining as it it will determine that the function can't reach a point where it can exit.

Even if there is no compiler warning to worry about the infinite loop prevents the function from returning. At some point a kernel (not necessarily Linux) is going to be faced with fact that it was called by a jmp instruction to get it started (At least on x86 systems). Often the jmp is used to set the code segment for entering protected mode or at the most basic level the BIOS jumps to the code that loads the boot sector (in very simple OSes). This means that there is a finite end to the code and to prevent the processor from executing invalid instructions it is better to make it busy doing nothing of interest.

The code cpu_relax(); /* For when BUG is null */ is to fix a kernel bug. It is mentioned in this post my Linus

sched: Fix ancient race in do_exit()

Upvotes: 2

Related Questions