pthread_atfork.3p (9294B)
- '\" et
- .TH PTHREAD_ATFORK "3P" 2017 "IEEE/The Open Group" "POSIX Programmer's Manual"
- .\"
- .SH 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.
- .\"
- .SH NAME
- pthread_atfork
- \(em register fork handlers
- .SH SYNOPSIS
- .LP
- .nf
- #include <pthread.h>
- .P
- int pthread_atfork(void (*\fIprepare\fP)(void), void (*\fIparent\fP)(void),
- void (*\fIchild\fP)(void));
- .fi
- .SH DESCRIPTION
- The
- \fIpthread_atfork\fR()
- function shall declare fork handlers to be called before and after
- \fIfork\fR(),
- in the context of the thread that called
- \fIfork\fR().
- The
- .IR prepare
- fork handler shall be called before
- \fIfork\fR()
- processing commences. The
- .IR parent
- fork handle shall be called after
- \fIfork\fR()
- processing completes in the parent process. The
- .IR child
- fork handler shall be called after
- \fIfork\fR()
- 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.
- .P
- If a
- \fIfork\fR()
- call in a multi-threaded process leads to a
- .IR child
- fork handler calling any function that is not async-signal-safe, the
- behavior is undefined.
- .P
- The order of calls to
- \fIpthread_atfork\fR()
- is significant. The
- .IR parent
- and
- .IR child
- fork handlers shall be called in the order in which they were
- established by calls to
- \fIpthread_atfork\fR().
- The
- .IR prepare
- fork handlers shall be called in the opposite order.
- .SH "RETURN VALUE"
- Upon successful completion,
- \fIpthread_atfork\fR()
- shall return a value of zero; otherwise, an error number shall be
- returned to indicate the error.
- .SH ERRORS
- The
- \fIpthread_atfork\fR()
- function shall fail if:
- .TP
- .BR ENOMEM
- Insufficient table space exists to record the fork handler addresses.
- .P
- The
- \fIpthread_atfork\fR()
- function shall not return an error code of
- .BR [EINTR] .
- .LP
- .IR "The following sections are informative."
- .SH EXAMPLES
- None.
- .SH "APPLICATION USAGE"
- The original usage pattern envisaged for
- \fIpthread_atfork\fR()
- was for the
- .IR prepare
- fork handler to lock mutexes and other locks, and for the
- .IR parent
- and
- .IR child
- handlers to unlock them. However, since all of the relevant unlocking
- functions, except
- \fIsem_post\fR(),
- are not async-signal-safe, this usage results in undefined behavior in
- the child process unless the only such unlocking function it calls is
- \fIsem_post\fR().
- .SH RATIONALE
- There are at least two serious problems with the semantics of
- \fIfork\fR()
- 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
- \fIfork\fR().
- 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.
- .P
- It is suggested that programs that use
- \fIfork\fR()
- call an
- .IR 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.
- .P
- 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
- \fIfork\fR()
- and
- .IR 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.
- .P
- On the other hand, the multi-threaded library needs a way to protect
- its internal state during
- \fIfork\fR()
- 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
- \fIfork\fR()
- and
- .IR exec
- calls to effect I/O redirection. The solution may require locking
- mutex variables during
- \fIfork\fR(),
- or it may entail simply resetting the state in the child after the
- \fIfork\fR()
- processing completes.
- .P
- The
- \fIpthread_atfork\fR()
- function was intended to provide multi-threaded libraries with a means
- to protect themselves from innocent application programs that call
- \fIfork\fR(),
- and to provide multi-threaded application programs with a standard
- mechanism for protecting themselves from
- \fIfork\fR()
- calls in a library routine or the application itself.
- .P
- The expected usage was that the prepare handler would acquire all mutex
- locks and the other two fork handlers would release them.
- .P
- 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
- \fIfork\fR()
- 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
- .IR stdin ,
- .IR stdout ,
- .IR stderr )
- must be protected by locking the stream with
- \fIflockfile\fR().
- But the application itself could have done that, possibly in the same
- thread calling
- \fIfork\fR().
- In this case, the process will deadlock.
- .P
- Alternatively, some libraries might have been able to supply just a
- .IR 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
- .IR *_init (\|)
- and
- .IR *_destroy (\|)
- calls for mutexes and locks if the mutex or lock is still locked. In
- this case, the
- .IR child
- routine is not able to reinitialize the mutexes and locks.
- .P
- When
- \fIfork\fR()
- 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
- \fIfork\fR()
- 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
- \fIpthread_atfork\fR().
- In addition, any critical threads would have needed to be recreated and
- reinitialized to the proper state in the child (also via
- \fIpthread_atfork\fR()).
- .P
- 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
- \fIpthread_atfork\fR()
- function for itself.
- .P
- 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
- \fIfork\fR()
- in a multi-threaded process only calls async-signal-safe interfaces.
- .SH "FUTURE DIRECTIONS"
- The
- \fIpthread_atfork\fR()
- function may be formally deprecated (for example, by shading it OB) in
- a future version of this standard.
- .SH "SEE ALSO"
- .IR "\fIatexit\fR\^(\|)",
- .IR "\fIexec\fR\^",
- .IR "\fIfork\fR\^(\|)"
- .P
- The Base Definitions volume of POSIX.1\(hy2017,
- .IR "\fB<pthread.h>\fP",
- .IR "\fB<sys_types.h>\fP"
- .\"
- .SH COPYRIGHT
- Portions of this text are 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,
- Copyright (C) 2018 by the Institute of
- Electrical and Electronics Engineers, Inc and The Open Group.
- 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.opengroup.org/unix/online.html .
- .PP
- 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 .