_EXIT(3P)
๐ _EXIT(3P) โ POSIX Programmer's Manual ๐
okay bestie, welcome to _EXIT(3P), aka the POSIX Programmer's Manual page for _Exit and _exit ๐ซถ we're in the POSIX Programmer's Manual here, so buckle up.
โจ PROLOG โจ
so like, this manual page is part of the POSIX Programmer's Manual. no cap. but heads up: the Linux implementation of this interface may differ (so go consult the corresponding Linux manual page for the deets on Linux behavior), or honestly the interface might not even be implemented on Linux at all. it's giving "read the fine print" ๐
๐ธ NAME ๐ธ
_Exit, _exit โ terminate a process. that's it, that's the vibe. your process is done, bestie. periodt.
๐ SYNOPSIS ๐
#include <stdlib.h>
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
two headers, two functions, one shared destiny โจ
๐ DESCRIPTION ๐
okay so for _Exit() specifically: the functionality described on this reference page is aligned with the ISO C standard. if there's any conflict between what's written here and the ISO C standard, that conflict is unintentional โ nobody's trying to start drama. this volume of POSIX.1โ2017 defers to the ISO C standard, periodt.
the value of status may be 0, EXIT_SUCCESS, EXIT_FAILURE, or literally any other value you want, but โ and this is the important part โ only the least significant 8 bits (that is, status & 0377) shall be available from wait() and waitpid(). the full value shall be available from waitid() and in the siginfo_t passed to a signal handler for SIGCHLD. so like, if you wanted to send a whole novel through your exit status... bestie, only 8 bits make it through the main channels ๐ญ
the _Exit() and _exit() functions shall be functionally equivalent. same energy, same behavior, two names. iconic.
and now the big one: the _Exit() and _exit() functions shall not call functions registered with atexit() nor any registered signal handlers. Open streams shall not be flushed. whether open streams are closed (without flushing) is implementation-defined. finally, the calling process shall be terminated with the consequences described below. no cleanup era. no goodbye tour. you just go. ๐
๐ฆ Consequences of Process Termination ๐ฆ
process termination caused by any reason shall have the following consequences:
Note: these consequences are all extensions to the ISO C standard and are not further CX shaded. However, functionality relating to the XSI option is shaded.
- All of the file descriptors, directory streams, conversion descriptors, and message catalog descriptors open in the calling process shall be closed. everything. gone. closed.
- If the parent process of the calling process has set its
SA_NOCLDWAITflag or has set the action for theSIGCHLDsignal toSIG_IGN:- The process' status information (see Section 2.13, Status Information), if any, shall be discarded.
- The lifetime of the calling process shall end immediately. If
SA_NOCLDWAITis set, it is implementation-defined whether aSIGCHLDsignal is sent to the parent process. - If a thread in the parent process of the calling process is blocked in
wait(),waitpid(), orwaitid(), and the parent process has no remaining child processes in the set of waited-for children, thewait(),waitid(), orwaitpid()function shall fail and seterrnoto[ECHILD].
Otherwise:
- Status information (see Section 2.13, Status Information) shall be generated.
- The calling process shall be transformed into a zombie process ๐ง Its status information shall be made available to the parent process until the process' lifetime ends.
- The process' lifetime shall end once its parent obtains the process' status information via a currently-blocked or future call to
wait(),waitid()(withoutWNOWAIT), orwaitpid(). - If one or more threads in the parent process of the calling process is blocked in a call to
wait(),waitid(), orwaitpid()awaiting termination of the process, one (or, if any are callingwaitid()withWNOWAIT, possibly more) of these threads shall obtain the process' status information as specified in Section 2.13, Status Information and become unblocked. - A
SIGCHLDshall be sent to the parent process.
- Termination of a process does not directly terminate its children. The sending of a
SIGHUPsignal as described below indirectly terminates children in some circumstances. so like... the drama travels, but only sometimes. - The parent process ID of all of the existing child processes and zombie processes of the calling process shall be set to the process ID of an implementation-defined system process. That is, these processes shall be inherited by a special system process. adopted by the system, fr fr ๐ซถ
- Each attached shared-memory segment is detached and the value of
shm_nattch(seeshmget()) in the data structure associated with its shared memory ID shall be decremented by 1. - For each semaphore for which the calling process has set a
semadjvalue (seesemop()), that value shall be added to thesemvalof the specified semaphore. - If the process is a controlling process, the
SIGHUPsignal shall be sent to each process in the foreground process group of the controlling terminal belonging to the calling process. - If the process is a controlling process, the controlling terminal associated with the session shall be disassociated from the session, allowing it to be acquired by a new controlling process. new main character, who dis ๐
- If the exit of the process causes a process group to become orphaned, and if any member of the newly-orphaned process group is stopped, then a
SIGHUPsignal followed by aSIGCONTsignal shall be sent to each process in the newly-orphaned process group. - All open named semaphores in the calling process shall be closed as if by appropriate calls to
sem_close(). - Any memory locks established by the process via calls to
mlockall()ormlock()shall be removed. If locked pages in the address space of the calling process are also mapped into the address spaces of other processes and are locked by those processes, the locks established by the other processes shall be unaffected by the call by this process to_Exit()or_exit(). not your locks, not your problem ๐ - Memory mappings that were created in the process shall be unmapped before the process is destroyed.
- Any blocks of typed memory that were mapped in the calling process shall be unmapped, as if
munmap()was implicitly called to unmap them. - All open message queue descriptors in the calling process shall be closed as if by appropriate calls to
mq_close(). - Any outstanding cancelable asynchronous I/O operations may be canceled. Those asynchronous I/O operations that are not canceled shall complete as if the
_Exit()or_exit()operation had not yet occurred, but any associated signal notifications shall be suppressed. The_Exit()or_exit()operation may block awaiting such I/O completion. Whether any I/O is canceled, and which I/O may be canceled upon_Exit()or_exit(), is implementation-defined. - Threads terminated by a call to
_Exit()or_exit()shall not invoke their cancellation cleanup handlers or per-thread data destructors. no last words, no final texts, just gone ๐ญ - If the calling process is a trace controller process, any trace streams that were created by the calling process shall be shut down as described by the
posix_trace_shutdown()function, and mapping of trace event names to trace event type identifiers of any process built for these trace streams may be deallocated.
โญ RETURN VALUE โญ
these functions do not return. they literally cannot come back. it's giving "left on read forever" ๐
๐ ERRORS ๐
No errors are defined.
the following sections are informative. (iykyk โ that means they're not normative, bestie, they're just for the vibes and the helpfulness.)
๐ EXAMPLES ๐
None. (nothing to show, move along โจ)
๐ APPLICATION USAGE ๐
normally, applications should use exit() rather than _Exit() or _exit(). like, exit() is the one that actually says goodbye and flushes stuff. _Exit()/_exit() is the "leaving the group chat with no explanation" option ๐โ๏ธ๐จ
โจ RATIONALE โจ
Okay bestie, so this is the why behind all the _exit() drama, and it's lowkey a whole history lesson. Let's get into it. ๐
๐ซง Process Termination ๐ซง
So back in the day, early proposals were like "there's normal termination and abnormal termination," and abnormal termination was only caused by certain signals and led to implementation-defined โactionsโ (we'll talk about those). Then later proposals were like "no, actually there are three types": normal termination (which is what we have in the current specification), simple abnormal termination, and abnormal termination with actions. The difference between the two abnormal types was that they came from different signals, and the implementation-defined actions would happen in the latter case. But since those actions were completely implementation-defined, the early proposals were only saying when the actions could happen and how you could detect them, not what they actually were. That was of little or no use to conforming applications, so this volume of POSIX.1-2017 just doesn't make that distinction. Periodt.
In most historical implementations, those implementation-defined actions usually include creating a file named core in the current working directory of the process. This file has an image of the memory of the process, plus descriptive information about the process, maybe enough to reconstruct the state of the process when it got the signal. ๐
Potential security problem alert! ๐จ Creating acorefile can be a security issue if the process was set-user-ID and the current user is not the owner of the program, if the process was set-group-ID and none of the user's groups match the group of the program, or if the user does not have permission to write in the current directory. In that situation, an implementation either should not create acorefile or should make it unreadable by the user. No cap.
Even though this volume of POSIX.1-2017 stays silent on this feature, applications are advised not to create files named core because of potential conflicts in many implementations. Some implementations use a name other than core for the file โ for example, by appending the process ID to the filename. So like, don't do it. ๐
๐ Terminating a Process ๐
It's super important that the consequences of process termination as described happen regardless of whether the process called _exit() (maybe indirectly through exit()) or instead got terminated due to a signal or for some other reason. And in the specific case of exit(), that means the status argument to exit() is treated the same way as the status argument to _exit(). Same vibe, same energy.
A language other than C may have other termination primitives than the C-language exit() function, and programs written in such a language should use its native termination primitives, but those should have the behavior of _exit() as described as part of their function. However, implementations in languages other than C are outside the scope of this version of this volume of POSIX.1-2017. So like, not our problem bestie. ๐คทโโ๏ธ
As required by the ISO C standard, using return from main() has the same behavior (other than with respect to language scope issues) as calling exit() with the returned value. Reaching the end of the main() function has the same behavior as calling exit(0). Iconic.
A value of zero (or EXIT_SUCCESS, which is required to be zero) for the status argument conventionally indicates successful termination. This corresponds to the specification for exit() in the ISO C standard. Utilities such as make and various shells follow this convention โ they interpret a zero status from a child process as success. For this reason, applications should not call exit(0) or _exit(0) when they terminate unsuccessfully; for example, in signal-catching functions. That's a big yikes. ๐ญ
Historically, the implementation-defined process that inherits children whose parents have terminated without waiting on them is called init and has a process ID of 1. The original main character.
The sending of a SIGHUP to the foreground process group when a controlling process terminates corresponds to somewhat different historical implementations. In System V, the kernel sends a SIGHUP on termination of (essentially) a controlling process. In 4.2 BSD, the kernel does not send SIGHUP in a case like this, but the termination of a controlling process is usually noticed by a system daemon, which arranges to send a SIGHUP to the foreground process group with the vhangup() function. However, in 4.2 BSD, due to the behavior of the shells that support job control, the controlling process is usually a shell with no other processes in its process group. So a change to make _exit() behave this way in such systems should not cause problems with existing applications. Slay.
The termination of a process may cause a process group to become orphaned in either of two ways. The connection of a process group to its parent(s) outside of the group depends on both the parents and their children. So a process group may be orphaned by the termination of the last connecting parent process outside of the group, or by the termination of the last direct descendant of the parent process(es). In either case, if the termination of a process causes a process group to become orphaned, processes within the group are disconnected from their job control shell, which no longer has any information on the existence of the process group. Stopped processes within the group would languish forever. ๐ To avoid this problem, newly orphaned process groups that contain stopped processes are sent a SIGHUP signal and a SIGCONT signal to indicate that they have been disconnected from their session. The SIGHUP signal causes the process group members to terminate unless they are catching or ignoring SIGHUP. Under most circumstances, all of the members of the process group are stopped if any of them are stopped.
The action of sending a SIGHUP and a SIGCONT signal to members of a newly orphaned process group is similar to the action of 4.2 BSD, which sends SIGHUP and SIGCONT to each stopped child of an exiting process. If such children exit in response to the SIGHUP, any additional descendants receive similar treatment at that time. In this volume of POSIX.1-2017, the signals are sent to the entire process group at the same time. Also, in this volume of POSIX.1-2017, but not in 4.2 BSD, stopped processes may be orphaned, but may be members of a process group that is not orphaned; therefore, the action taken at _exit() must consider processes other than child processes. It's giving thorough.
It is possible for a process group to be orphaned by a call to setpgid() or setsid(), as well as by process termination. This volume of POSIX.1-2017 does not require sending SIGHUP and SIGCONT in those cases, because โ unlike process termination โ those cases are not caused accidentally by applications that are unaware of job control. An implementation can choose to send SIGHUP and SIGCONT in those cases as an extension; such an extension must be documented as required in <signal.h>. Okay so read the docs, bestie. ๐
The ISO/IEC 9899:1999 standard adds the _Exit() function that results in immediate program termination without triggering signals or atexit()-registered functions. In POSIX.1-2008, this is equivalent to the _exit() function. The more you know. โญ
๐ฎ FUTURE DIRECTIONS ๐ฎ
None.
Like, literally none. The future is a mystery, but this section is empty. ๐
๐ SEE ALSO ๐
atexit()exit()mlock()mlockall()mq_close()munmap()posix_trace_create()sem_close()semop()setpgid()setsid()shmget()wait()waitid()
Also, the Base Definitions volume of POSIX.1-2017, <stdlib.h>, <unistd.h>. Go read those too. ๐ซถ
ยฉ๏ธ COPYRIGHT ยฉ๏ธ
So like, some of this text is reprinted and reproduced in electronic form from IEEE Std 1003.1-2017, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 7, 2018 Edition. The copyright is (C) 2018 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. If this version and the original IEEE and The Open Group Standard disagree, the original IEEE and The Open Group Standard is the referee document, periodt. You can grab the original Standard online at http://www.opengroup.org/unix/online.html .
Any typographical or formatting errors in this page are most likely from converting the source files to man page format. To report such errors, see https://www.kernel.org/doc/man-pages/reporting_bugs.html .
And that's the whole vibe, bestie. Source: IEEE/The Open Group, 2017, _EXIT(3P) โ so iconic, so useful, so done. Bye! ๐โจ๐๐ฆ๐ธ๐
๐ฆ where this page comes from
- alpine 3.22: man-pages-posix 2017a-r0 ยท custom
- alpine 3.23: man-pages-posix 2017a-r0 ยท custom
- alpine 3.24: man-pages-posix 2017a-r0 ยท custom
- arch rolling: man-pages 6.19-1
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages-posix 2017a
- opensuse-leap 16.0: man-pages-posix 2017a-160000.4.1 ยท SUSE-IEEE
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms