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