Blame sysdeps/nptl/fork.c

Packit 6c4009
/* Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#include <libio/libioP.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
#include <hp-timing.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <stdio-lock.h>
Packit 6c4009
#include <atomic.h>
Packit 6c4009
#include <nptl/pthreadP.h>
Packit 6c4009
#include <fork.h>
Packit 6c4009
#include <arch-fork.h>
Packit 6c4009
#include <futex-internal.h>
Packit 6c4009
#include <malloc/malloc-internal.h>
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
fresetlockfiles (void)
Packit 6c4009
{
Packit 6c4009
  _IO_ITER i;
Packit 6c4009
Packit 6c4009
  for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
Packit 6c4009
    if ((_IO_iter_file (i)->_flags & _IO_USER_LOCK) == 0)
Packit 6c4009
      _IO_lock_init (*((_IO_lock_t *) _IO_iter_file(i)->_lock));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
pid_t
Packit 6c4009
__libc_fork (void)
Packit 6c4009
{
Packit 6c4009
  pid_t pid;
Packit 6c4009
Packit 6c4009
  /* Determine if we are running multiple threads.  We skip some fork
Packit 6c4009
     handlers in the single-thread case, to make fork safer to use in
Packit 6c4009
     signal handlers.  POSIX requires that fork is async-signal-safe,
Packit 6c4009
     but our current fork implementation is not.  */
Packit 6c4009
  bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads);
Packit 6c4009
Packit Service 794fa9
  __run_fork_handlers (atfork_run_prepare, multiple_threads);
Packit 6c4009
Packit 6c4009
  /* If we are not running multiple threads, we do not have to
Packit 6c4009
     preserve lock state.  If fork runs from a signal handler, only
Packit 6c4009
     async-signal-safe functions can be used in the child.  These data
Packit 6c4009
     structures are only used by unsafe functions, so their state does
Packit 6c4009
     not matter if fork was called from a signal handler.  */
Packit 6c4009
  if (multiple_threads)
Packit 6c4009
    {
Packit 6c4009
      _IO_list_lock ();
Packit 6c4009
Packit 6c4009
      /* Acquire malloc locks.  This needs to come last because fork
Packit 6c4009
	 handlers may use malloc, and the libio list lock has an
Packit 6c4009
	 indirect malloc dependency as well (via the getdelim
Packit 6c4009
	 function).  */
Packit 6c4009
      call_function_static_weak (__malloc_fork_lock_parent);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  pid = arch_fork (&THREAD_SELF->tid);
Packit 6c4009
Packit 6c4009
  if (pid == 0)
Packit 6c4009
    {
Packit 6c4009
      struct pthread *self = THREAD_SELF;
Packit 6c4009
Packit 6c4009
      /* See __pthread_once.  */
Packit 6c4009
      if (__fork_generation_pointer != NULL)
Packit 6c4009
	*__fork_generation_pointer += __PTHREAD_ONCE_FORK_GEN_INCR;
Packit 6c4009
Packit 6c4009
#ifdef __NR_set_robust_list
Packit 6c4009
      /* Initialize the robust mutex list setting in the kernel which has
Packit 6c4009
	 been reset during the fork.  We do not check for errors because if
Packit 6c4009
	 it fails here, it must have failed at process startup as well and
Packit 6c4009
	 nobody could have used robust mutexes.
Packit 6c4009
	 Before we do that, we have to clear the list of robust mutexes
Packit 6c4009
	 because we do not inherit ownership of mutexes from the parent.
Packit 6c4009
	 We do not have to set self->robust_head.futex_offset since we do
Packit 6c4009
	 inherit the correct value from the parent.  We do not need to clear
Packit 6c4009
	 the pending operation because it must have been zero when fork was
Packit 6c4009
	 called.  */
Packit 6c4009
# if __PTHREAD_MUTEX_HAVE_PREV
Packit 6c4009
      self->robust_prev = &self->robust_head;
Packit 6c4009
# endif
Packit 6c4009
      self->robust_head.list = &self->robust_head;
Packit 6c4009
# ifdef SHARED
Packit 6c4009
      if (__builtin_expect (__libc_pthread_functions_init, 0))
Packit 6c4009
	PTHFCT_CALL (ptr_set_robust, (self));
Packit 6c4009
# else
Packit 6c4009
      extern __typeof (__nptl_set_robust) __nptl_set_robust
Packit 6c4009
	__attribute__((weak));
Packit 6c4009
      if (__builtin_expect (__nptl_set_robust != NULL, 0))
Packit 6c4009
	__nptl_set_robust (self);
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      /* Reset the lock state in the multi-threaded case.  */
Packit 6c4009
      if (multiple_threads)
Packit 6c4009
	{
Packit 6c4009
	  /* Release malloc locks.  */
Packit 6c4009
	  call_function_static_weak (__malloc_fork_unlock_child);
Packit 6c4009
Packit 6c4009
	  /* Reset the file list.  These are recursive mutexes.  */
Packit 6c4009
	  fresetlockfiles ();
Packit 6c4009
Packit 6c4009
	  /* Reset locks in the I/O code.  */
Packit 6c4009
	  _IO_list_resetlock ();
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Reset the lock the dynamic loader uses to protect its data.  */
Packit 6c4009
      __rtld_lock_initialize (GL(dl_load_lock));
Packit 6c4009
Packit 6c4009
      /* Run the handlers registered for the child.  */
Packit Service 794fa9
      __run_fork_handlers (atfork_run_child, multiple_threads);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Release acquired locks in the multi-threaded case.  */
Packit 6c4009
      if (multiple_threads)
Packit 6c4009
	{
Packit 6c4009
	  /* Release malloc locks, parent process variant.  */
Packit 6c4009
	  call_function_static_weak (__malloc_fork_unlock_parent);
Packit 6c4009
Packit 6c4009
	  /* We execute this even if the 'fork' call failed.  */
Packit 6c4009
	  _IO_list_unlock ();
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Run the handlers registered for the parent.  */
Packit Service 794fa9
      __run_fork_handlers (atfork_run_parent, multiple_threads);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return pid;
Packit 6c4009
}
Packit 6c4009
weak_alias (__libc_fork, __fork)
Packit 6c4009
libc_hidden_def (__fork)
Packit 6c4009
weak_alias (__libc_fork, fork)