退出的Syscall实现()
我写了一个简单的C程序,只调用exit()函数,但是strace说二进制文件实际上是调用exit_group,exit()是一个exit_group()包装器吗? 这两个function是否相同? 如果是这样,为什么编译器会选择exit_group()而不是exit()?
Linux和glibc手册页记录了所有这些(请参阅NOTES部分中的“C库/内核差异”)。
-
_exit(2)
:在glibc 2.3及更高版本中,这个包装函数实际调用Linuxsys_exit_group
系统调用来退出所有线程。 在glibc2.3之前,它是sys_exit的一个包装器,sys_exit
退出当前线程。 -
sys_exit
:仅终止当前线程,使其他线程继续运行。 AFAIK,现代glibc没有这个Linux系统调用的包装函数,因为它通常没用。 -
exit_group(2)
:sys_exit_group
glibc包装器,退出所有线程。 -
exit(3)
:ISO C89函数,它刷新缓冲区然后退出整个过程。 (它总是使用exit_group()
因为检查进程是否是单线程并决定使用sys_exit
与sys_exit_group
没有任何好处。 正如@Matteo所指出的 ,最近的ISO C或POSIX标准是线程感知的,其中一个或两个可能需要这种行为。但显然
exit(3)
本身不是线程安全的(在C库清理部分),所以我猜不要一次从多个线程调用它。
只有exit()
,而不是_exit()
或exit_group()
,刷新stdout
,导致新手asm程序中的“ printf
不打印任何东西”问题,如果写入管道(使stdout
全缓冲而不是行缓冲) ,或者如果您忘记格式字符串中的\n
。 例如, 如何_exit(0)(由syscall退出)阻止我接收任何标准内容? 。 如果你使用任何缓冲的I / O函数,或at_exit
,或类似的东西,通常最好直接调用libc exit(3)
函数而不是系统调用。 但是当然你可以在sys_exit_group
之前调用fflush
。
它当然不是选择任何东西的编译器 ,它是libc。 当您包含头文件并写入read(fd, buf, 123)
或exit(1)
,C编译器只会看到普通的函数调用。
一些C库(例如musl ,但不是glibc)可以使用内联asm将syscall
指令内联到二进制文件中,但是头文件仍然是C库的一部分,而不是编译器。