|
PROLOG | NAME | SYNOPSIS | DESCRIPTION | RETURN VALUE | ERRORS | EXAMPLES | APPLICATION USAGE | RATIONALE | FUTURE DIRECTIONS | SEE ALSO | COPYRIGHT |
|
PTHREAD_ATFORK(3P) POSIX Programmer's Manual PTHREAD_ATFORK(3P)
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.
pthread_atfork — register fork handlers
#include <pthread.h>
int pthread_atfork(void (*prepare)(void), void (*parent)(void),
void (*child)(void));
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() processing 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.
Upon successful completion, pthread_atfork() shall return a value of
zero; otherwise, an error number shall be returned to indicate the
error.
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.
None.
None.
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
example, 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 unsatisfactory 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
routines 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 problematic for mutexes and locks in
dynamically allocated memory. All mutexes and locks internal to the
implementation must be locked, too. This possibly delays the thread
calling fork() for a long time or even indefinitely 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
inconsistent. 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.
None.
atexit(3p), exec(1p), fork(3p)
The Base Definitions volume of POSIX.1‐2008, pthread.h(0p),
sys_types.h(0p)
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 Electrical 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.kernel.org/doc/man-pages/reporting_bugs.html .
IEEE/The Open Group 2013 PTHREAD_ATFORK(3P)
Pages that refer to this page: pthread.h(0p), exec(3p), fork(3p), system(3p)