为什么在kernel / exit.c中定义的do_exit()末尾有一个无限循环?

时间:2014-11-04 04:28:54

标签: linux linux-kernel

在Linux内核中,我对在do_exit()结尾处循环的目的感到困惑。

调度schedule()不是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 

1 个答案:

答案 0 :(得分:2)

取决于内核,它可能看起来不同,但通常结构是相同的。

在某些实现中,它以:

开头
NORET_TYPE void do_exit(long code)

NORET_TYPE在不同的 GCC 编译器中可能有所不同(它可能是标记无返回功能的属性),也可能是volatile。这样一个函数的声明是做什么的?它有效地说我不会回来。您可以在GCC documentation中找到有关它的更多信息:

  

属性noreturn未在2.5之前的GCC版本中实现。声明函数不返回的另一种方法,在当前版本和某些旧版本中有效,如下所示:

     typedef void voidfn ();         
     volatile voidfn fatal;

volatile void函数是GCC开发人员创建的C标准的不符合扩展。您在ANSI C标准(C89)中找不到它。

恰好是当内核到达do_exit()时它不打算从函数返回。一般情况下它会无限期地阻塞或直到某些东西重置系统(通常)。问题是,如果将函数标记为not returning,编译器将在您的函数退出时发出警告。所以你通常会看到某种无限循环(whileforgoto等等。在你的情况下它确实:

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

有趣的是,评论几乎给出了理由。 noreturn function does return是gcc编译器警告。编译器显而易见的无限循环(如for (;;))足以阻止编译器抱怨,因为它将确定函数无法到达可退出的点。

即使没有编译器警告担心无限循环也会阻止函数返回。在某些时候,内核(不一定是Linux)将面临这样一个事实:它被jmp指令调用以启动它(至少在x86系统上)。通常jmp用于设置进入保护模式的代码段,或者在最基本的级别,BIOS跳转到加载引导扇区的代码(在非常简单的操作系统中)。这意味着代码有一个有限的结束,并且为了防止处理器执行无效指令,最好让它忙于无所事事。

代码cpu_relax(); /* For when BUG is null */用于修复内核错误。在post my Linus

中提到了它
sched: Fix ancient race in do_exit()