pthread_atfork(3p) — Linux manual page

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)

PROLOG         top

       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         top

       pthread_atfork — register fork handlers

SYNOPSIS         top

       #include <pthread.h>

       int pthread_atfork(void (*prepare)(void), void (*parent)(void),
           void (*child)(void));

DESCRIPTION         top

       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.

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

       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         top

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

ERRORS         top

       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         top

       None.

APPLICATION USAGE         top

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

RATIONALE         top

       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.

FUTURE DIRECTIONS         top

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

SEE ALSO         top

       atexit(3p), exec(1p), fork(3p)

       The Base Definitions volume of POSIX.1‐2017, pthread.h(0p),
       sys_types.h(0p)

COPYRIGHT         top

       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(3P)

Pages that refer to this page: pthread.h(0p)exec(3p)fork(3p)system(3p)