PTHREAD_ATFORK(3P) POSIX Programmer's Manual PTHREAD_ATFORK(3P)
PROLOG
This manual page is part of the POSIX Programmer's Manual. The Linux
implementation of this interface may differ (consult the corresponding
Linux manual page for details of Linux behavior), or the interface may
not be implemented on Linux.
NAME
pthread_atfork -- register fork handlers
SYNOPSIS
#include <pthread.h>
int pthread_atfork(void (*prepare)(void), void (*parent)(void),
void (*child)(void));
DESCRIPTION
The pthread_atfork() function shall declare fork handlers to be called
before and after fork(), in the context of the thread that called
fork(). The prepare fork handler shall be called before fork() pro-
cessing commences. The parent fork handle shall be called after fork()
processing completes in the parent process. The child fork handler
shall be called after fork() processing completes in the child process.
If no handling is desired at one or more of these three points, the
corresponding fork handler address(es) may be set to NULL.
The order of calls to pthread_atfork() is significant. The parent and
child fork handlers shall be called in the order in which they were
established by calls to pthread_atfork(). The prepare fork handlers
shall be called in the opposite order.
RETURN VALUE
Upon successful completion, pthread_atfork() shall return a value of
zero; otherwise, an error number shall be returned to indicate the
error.
ERRORS
The pthread_atfork() function shall fail if:
ENOMEM Insufficient table space exists to record the fork handler
addresses.
The pthread_atfork() function shall not return an error code of
[EINTR].
The following sections are informative.
EXAMPLES
None.
APPLICATION USAGE
None.
RATIONALE
There are at least two serious problems with the semantics of fork() in
a multi-threaded program. One problem has to do with state (for exam-
ple, memory) covered by mutexes. Consider the case where one thread has
a mutex locked and the state covered by that mutex is inconsistent
while another thread calls fork(). In the child, the mutex is in the
locked state (locked by a nonexistent thread and thus can never be
unlocked). Having the child simply reinitialize the mutex is unsatis-
factory since this approach does not resolve the question about how to
correct or otherwise deal with the inconsistent state in the child.
It is suggested that programs that use fork() call an exec function
very soon afterwards in the child process, thus resetting all states.
In the meantime, only a short list of async-signal-safe library rou-
tines are promised to be available.
Unfortunately, this solution does not address the needs of multi-
threaded libraries. Application programs may not be aware that a multi-
threaded library is in use, and they feel free to call any number of
library routines between the fork() and exec calls, just as they always
have. Indeed, they may be extant single-threaded programs and cannot,
therefore, be expected to obey new restrictions imposed by the threads
library.
On the other hand, the multi-threaded library needs a way to protect
its internal state during fork() in case it is re-entered later in the
child process. The problem arises especially in multi-threaded I/O
libraries, which are almost sure to be invoked between the fork() and
exec calls to effect I/O redirection. The solution may require locking
mutex variables during fork(), or it may entail simply resetting the
state in the child after the fork() processing completes.
The pthread_atfork() function was intended to provide multi-threaded
libraries with a means to protect themselves from innocent application
programs that call fork(), and to provide multi-threaded application
programs with a standard mechanism for protecting themselves from
fork() calls in a library routine or the application itself.
The expected usage was that the prepare handler would acquire all mutex
locks and the other two fork handlers would release them.
For example, an application could have supplied a prepare routine that
acquires the necessary mutexes the library maintains and supplied child
and parent routines that release those mutexes, thus ensuring that the
child would have got a consistent snapshot of the state of the library
(and that no mutexes would have been left stranded). This is good in
theory, but in reality not practical. Each and every mutex and lock in
the process must be located and locked. Every component of a program
including third-party components must participate and they must agree
who is responsible for which mutex or lock. This is especially problem-
atic for mutexes and locks in dynamically allocated memory. All mutexes
and locks internal to the implementation must be locked, too. This pos-
sibly delays the thread calling fork() for a long time or even indefi-
nitely since uses of these synchronization objects may not be under
control of the application. A final problem to mention here is the
problem of locking streams. At least the streams under control of the
system (like stdin, stdout, stderr) must be protected by locking the
stream with flockfile(). But the application itself could have done
that, possibly in the same thread calling fork(). In this case, the
process will deadlock.
Alternatively, some libraries might have been able to supply just a
child routine that reinitializes the mutexes in the library and all
associated states to some known value (for example, what it was when
the image was originally executed). This approach is not possible,
though, because implementations are allowed to fail *_init() and
*_destroy() calls for mutexes and locks if the mutex or lock is still
locked. In this case, the child routine is not able to reinitialize the
mutexes and locks.
When fork() is called, only the calling thread is duplicated in the
child process. Synchronization variables remain in the same state in
the child as they were in the parent at the time fork() was called.
Thus, for example, mutex locks may be held by threads that no longer
exist in the child process, and any associated states may be inconsis-
tent. The intention was that the parent process could have avoided this
by explicit code that acquires and releases locks critical to the child
via pthread_atfork(). In addition, any critical threads would have
needed to be recreated and reinitialized to the proper state in the
child (also via pthread_atfork()).
A higher-level package may acquire locks on its own data structures
before invoking lower-level packages. Under this scenario, the order
specified for fork handler calls allows a simple rule of initialization
for avoiding package deadlock: a package initializes all packages on
which it depends before it calls the pthread_atfork() function for
itself.
As explained, there is no suitable solution for functionality which
requires non-atomic operations to be protected through mutexes and
locks. This is why the POSIX.1 standard since the 1996 release requires
that the child process after fork() in a multi-threaded process only
calls async-signal-safe interfaces.
FUTURE DIRECTIONS
None.
SEE ALSO
atexit(), exec, fork()
The Base Definitions volume of POSIX.1-2008, <pthread.h>, <sys_types.h>
COPYRIGHT
Portions of this text are reprinted and reproduced in electronic form
from IEEE Std 1003.1, 2013 Edition, Standard for Information Technology
-- Portable Operating System Interface (POSIX), The Open Group Base
Specifications Issue 7, Copyright (C) 2013 by the Institute of Electri-
cal and Electronics Engineers, Inc and The Open Group. (This is
POSIX.1-2008 with the 2013 Technical Corrigendum 1 applied.) In the
event of any discrepancy between this version and the original IEEE and
The Open Group Standard, the original IEEE and The Open Group Standard
is the referee document. The original Standard can be obtained online
at http://www.unix.org/online.html .
Any typographical or formatting errors that appear in this page are
most likely to have been introduced during the conversion of the source
files to man page format. To report such errors, see https://www.ker-
nel.org/doc/man-pages/reporting_bugs.html .
IEEE/The Open Group 2013 PTHREAD_ATFORK(3P)