在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
答案 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
,编译器将在您的函数退出时发出警告。所以你通常会看到某种无限循环(while
,for
,goto
等等。在你的情况下它确实:
/* 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()