Reputation: 45
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
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