I wrote a simple C program which just calls the exit() function, however strace says that the binary is actually calling exit_group, is exit() a exit_group() wrapper? Are these two functions equivalent? If so why would the compiler choose exit_group() over exit()?
On many computer operating systems, a computer process terminates its execution by making an exit system call. More generally, an exit in a multithreading environment means that a thread of execution has stopped running. For resource management, the operating system reclaims resources (memory, files, etc.)
Description. The function _exit() terminates the calling process "immediately". Any open file descriptors belonging to the process are closed; any children of the process are inherited by process 1, init, and the process's parent is sent a SIGCHLD signal.
A system call is implemented by a ``software interrupt'' that transfers control to kernel code; in Linux/i386 this is ``interrupt 0x80''. The specific system call being invoked is stored in the EAX register, abd its arguments are held in the other processor registers.
Exit() is a core function in the C/C++ programming language that is used to instantly end the calling process (function). It is possible to call from any function. It informs the operating system of the state of program termination by passing an int value. It is usually used when software crashes unexpectedly.
The Linux and glibc man pages document all of this (See especially the "C library/kernel differences" in the NOTES section).
_exit(2)
: In glibc 2.3 and later, this wrapper function actually uses the Linux SYS_exit_group
system call to exit all threads. Before glibc2.3, it was a wrapper for SYS_exit
to exit just the current thread.
exit_group(2)
: glibc wrapper for SYS_exit_group
, which exits all threads.
exit(3)
: The ISO C89 function which flushes buffers and then exits the whole process. (It always uses exit_group()
because there's no benefit to checking if the process was single-threaded and deciding to use SYS_exit
vs. SYS_exit_group
). As @Matteo points out, recent ISO C / POSIX standards are thread-aware and one or both probably require this behaviour.
But apparently exit(3)
itself is not thread-safe (in the C library cleanup parts), so I guess don't call it from multiple threads at once.
syscall
/ int 0x80
with SYS_exit
: terminates just the current thread, leaving others running. AFAIK, modern glibc has no thin wrapper function for this Linux system call, but I think pthread_exit()
uses it if this isn't the last thread. (Otherwise exit(3) -> exit_group(2).)
Only exit()
, not _exit()
or exit_group()
, flushes stdout
, leading to "printf
doesn't print anything" problems in newbie asm programs if writing to a pipe (which makes stdout
full-buffered instead of line-buffered), or if you forgot the \n
in the format string. For example, How come _exit(0) (exiting by syscall) prevents me from receiving any stdout content?. If you use any buffered I/O functions, or at_exit
, or anything like that, it's usually a good idea to call the libc exit(3)
function instead of the system call directly. But of course you can call fflush
before SYS_exit_group
.
(Also related: On x64 Linux, what is the difference between syscall, int 0x80 and ret to exit a program? - ret
from main is equivalent to calling exit(3)
)
It's not of course the compiler that chose anything, it's libc. When you include headers and write read(fd, buf, 123)
or exit(1)
, the C compiler just sees an ordinary function call.
Some C libraries (e.g. musl, but not glibc) may use inline asm to inline a syscall
instruction into your binary, but still the headers are part of the C library, not the compiler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With