PTHREAD_ATFORK(3)          POSIX Programmer's Manual         PTHREAD_ATFORK(3)



PPRROOLLOOGG
       This manual page is part of the POSIX Programmer's Manual.  The OS
       implementation of this interface may differ (consult the corresponding
       OS manual page for details of OS behavior), or the interface may not be
       implemented on OS.

NNAAMMEE
       pthread_atfork -- register fork handlers

SSYYNNOOPPSSIISS
       #include <pthread.h>

       int pthread_atfork(void (*_p_r_e_p_a_r_e)(void), void (*_p_a_r_e_n_t)(void),
           void (*_c_h_i_l_d)(void));

DDEESSCCRRIIPPTTIIOONN
       The _p_t_h_r_e_a_d___a_t_f_o_r_k() function shall declare fork handlers to be called
       before and after _f_o_r_k(), in the context of the thread that called
       _f_o_r_k().  The _p_r_e_p_a_r_e fork handler shall be called before _f_o_r_k()
       processing commences. The _p_a_r_e_n_t fork handle shall be called after
       _f_o_r_k() processing completes in the parent process. The _c_h_i_l_d fork
       handler shall be called after _f_o_r_k() 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.

       If a _f_o_r_k() call in a multi-threaded process leads to a _c_h_i_l_d fork
       handler calling any function that is not async-signal-safe, the
       behavior is undefined.

       The order of calls to _p_t_h_r_e_a_d___a_t_f_o_r_k() is significant. The _p_a_r_e_n_t and
       _c_h_i_l_d fork handlers shall be called in the order in which they were
       established by calls to _p_t_h_r_e_a_d___a_t_f_o_r_k().  The _p_r_e_p_a_r_e fork handlers
       shall be called in the opposite order.

RREETTUURRNN VVAALLUUEE
       Upon successful completion, _p_t_h_r_e_a_d___a_t_f_o_r_k() shall return a value of
       zero; otherwise, an error number shall be returned to indicate the
       error.

EERRRROORRSS
       The _p_t_h_r_e_a_d___a_t_f_o_r_k() function shall fail if:

       EENNOOMMEEMM Insufficient table space exists to record the fork handler
              addresses.

       The _p_t_h_r_e_a_d___a_t_f_o_r_k() function shall not return an error code of
       [[EEIINNTTRR]].

       _T_h_e _f_o_l_l_o_w_i_n_g _s_e_c_t_i_o_n_s _a_r_e _i_n_f_o_r_m_a_t_i_v_e_.

EEXXAAMMPPLLEESS
       None.

AAPPPPLLIICCAATTIIOONN UUSSAAGGEE
       The original usage pattern envisaged for _p_t_h_r_e_a_d___a_t_f_o_r_k() was for the
       _p_r_e_p_a_r_e fork handler to lock mutexes and other locks, and for the
       _p_a_r_e_n_t and _c_h_i_l_d handlers to unlock them. However, since all of the
       relevant unlocking functions, except _s_e_m___p_o_s_t(), are not async-signal-
       safe, this usage results in undefined behavior in the child process
       unless the only such unlocking function it calls is _s_e_m___p_o_s_t().

RRAATTIIOONNAALLEE
       There are at least two serious problems with the semantics of _f_o_r_k() 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 _f_o_r_k().  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 _f_o_r_k() call an _e_x_e_c 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 _f_o_r_k() and _e_x_e_c 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 _f_o_r_k() 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 _f_o_r_k() and
       _e_x_e_c calls to effect I/O redirection. The solution may require locking
       mutex variables during _f_o_r_k(), or it may entail simply resetting the
       state in the child after the _f_o_r_k() processing completes.

       The _p_t_h_r_e_a_d___a_t_f_o_r_k() function was intended to provide multi-threaded
       libraries with a means to protect themselves from innocent application
       programs that call _f_o_r_k(), and to provide multi-threaded application
       programs with a standard mechanism for protecting themselves from
       _f_o_r_k() 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 _f_o_r_k() 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 _s_t_d_i_n, _s_t_d_o_u_t, _s_t_d_e_r_r) must be protected by locking
       the stream with _f_l_o_c_k_f_i_l_e().  But the application itself could have
       done that, possibly in the same thread calling _f_o_r_k().  In this case,
       the process will deadlock.

       Alternatively, some libraries might have been able to supply just a
       _c_h_i_l_d 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 _*___i_n_i_t() and
       _*___d_e_s_t_r_o_y() calls for mutexes and locks if the mutex or lock is still
       locked. In this case, the _c_h_i_l_d routine is not able to reinitialize the
       mutexes and locks.

       When _f_o_r_k() 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 _f_o_r_k() 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 _p_t_h_r_e_a_d___a_t_f_o_r_k().  In addition, any critical threads
       would have needed to be recreated and reinitialized to the proper state
       in the child (also via _p_t_h_r_e_a_d___a_t_f_o_r_k()).

       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 _p_t_h_r_e_a_d___a_t_f_o_r_k() 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 _f_o_r_k() in a multi-threaded process only
       calls async-signal-safe interfaces.

FFUUTTUURREE DDIIRREECCTTIIOONNSS
       The _p_t_h_r_e_a_d___a_t_f_o_r_k() function may be formally deprecated (for example,
       by shading it OB) in a future version of this standard.

SSEEEE AALLSSOO
       _a_t_e_x_i_t(), _e_x_e_c, _f_o_r_k()

       The Base Definitions volume of POSIX.1-2017, <<pptthhrreeaadd..hh>>, <<ssyyss__ttyyppeess..hh>>

CCOOPPYYRRIIGGHHTT
       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 .

       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                  2017                    PTHREAD_ATFORK(3)
