]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
posix: Consolidate fork implementation
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Mon, 18 Jan 2021 18:18:13 +0000 (15:18 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Thu, 24 Jun 2021 13:02:06 +0000 (10:02 -0300)
The Linux nptl implementation is used as base for generic fork
implementation to handle the internal locks and mutexes.  The
system specific bits are moved a new internal _Fork symbol.

(This new implementation will be used to provide a async-signal-safe
_Fork now that POSIX has clarified that fork might not be
async-signal-safe [1]).

For Hurd it means that the __nss_database_fork_prepare_parent and
__nss_database_fork_subprocess will be run in a slight different
order.

[1] https://austingroupbugs.net/view.php?id=62

include/unistd.h
posix/Makefile
posix/_Fork.c [new file with mode: 0644]
posix/fork.c
sysdeps/generic/fork.h [new file with mode: 0644]
sysdeps/mach/hurd/_Fork.c [moved from sysdeps/mach/hurd/fork.c with 98% similarity]
sysdeps/nptl/_Fork.c [new file with mode: 0644]
sysdeps/nptl/fork.c [deleted file]
sysdeps/nptl/fork.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/arch-fork.h

index 34872d8b4133a9c925f5b42076800316a8e0d8e9..691405a945aea0298bcc70589eb47df2815463f2 100644 (file)
@@ -140,6 +140,8 @@ extern __pid_t __vfork (void);
 libc_hidden_proto (__vfork)
 extern int __ttyname_r (int __fd, char *__buf, size_t __buflen);
 libc_hidden_proto (__ttyname_r)
+extern __pid_t _Fork (void);
+libc_hidden_proto (_Fork);
 extern int __isatty (int __fd) attribute_hidden;
 extern int __link (const char *__from, const char *__to);
 extern int __symlink (const char *__from, const char *__to);
index 8d139e54f6f0fb31c0212dfb84881eba100c2aad..3bd7d605dfb4143bbe3b864234bb17702c9aea30 100644 (file)
@@ -39,7 +39,7 @@ routines :=                                                                 \
        times                                                                 \
        wait waitpid wait3 wait4 waitid                                       \
        alarm sleep pause nanosleep                                           \
-       fork vfork _exit register-atfork                                      \
+       fork _Fork vfork _exit register-atfork                                \
        execve fexecve execv execle execl execvp execlp execvpe               \
        getpid getppid                                                        \
        getuid geteuid getgid getegid getgroups setuid setgid group_member    \
@@ -266,6 +266,7 @@ CFLAGS-execl.os = -fomit-frame-pointer
 CFLAGS-execvp.os = -fomit-frame-pointer
 CFLAGS-execlp.os = -fomit-frame-pointer
 CFLAGS-nanosleep.c += -fexceptions -fasynchronous-unwind-tables
+CFLAGS-fork.c = $(libio-mtsafe)
 
 tstgetopt-ARGS = -a -b -cfoobar --required foobar --optional=bazbug \
                --none random --col --color --colour
diff --git a/posix/_Fork.c b/posix/_Fork.c
new file mode 100644 (file)
index 0000000..4a998c0
--- /dev/null
@@ -0,0 +1,34 @@
+/* _Fork implementation.  Generic version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Clone the calling process, creating an exact copy.  Return -1 for errors,
+   0 to the new process, and the process ID of the new process to the
+   old process.
+   Different than fork, this functions is marked as async-signal-safe by
+   POSIX (by Austin Group issue 62).  */
+pid_t
+_Fork (void)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}
+libc_hidden_def (_Fork)
+stub_warning (_Fork)
index 05bda04ac5a7926f7b88fa412cb0b5a143744f64..44caf8d16633fc83ad7b90325cfbb535f7590e3a 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2021 Free Software Foundation, Inc.
+/* fork - create a child process.
+   Copyright (C) 1991-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <errno.h>
-#include <unistd.h>
+#include <fork.h>
+#include <libio/libioP.h>
+#include <ldsodefs.h>
+#include <malloc/malloc-internal.h>
+#include <nss/nss_database.h>
+#include <register-atfork.h>
+#include <stdio-lock.h>
+#include <sys/single_threaded.h>
+#include <unwind-link.h>
 
+static void
+fresetlockfiles (void)
+{
+  _IO_ITER i;
+
+  for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
+    if ((_IO_iter_file (i)->_flags & _IO_USER_LOCK) == 0)
+      _IO_lock_init (*((_IO_lock_t *) _IO_iter_file(i)->_lock));
+}
 
-/* Clone the calling process, creating an exact copy.
-   Return -1 for errors, 0 to the new process,
-   and the process ID of the new process to the old process.  */
-int
-__fork (void)
+pid_t
+__libc_fork (void)
 {
-  __set_errno (ENOSYS);
-  return -1;
+  /* Determine if we are running multiple threads.  We skip some fork
+     handlers in the single-thread case, to make fork safer to use in
+     signal handlers.  */
+  bool multiple_threads = __libc_single_threaded == 0;
+
+  __run_fork_handlers (atfork_run_prepare, multiple_threads);
+
+  struct nss_database_data nss_database_data;
+
+  /* If we are not running multiple threads, we do not have to
+     preserve lock state.  If fork runs from a signal handler, only
+     async-signal-safe functions can be used in the child.  These data
+     structures are only used by unsafe functions, so their state does
+     not matter if fork was called from a signal handler.  */
+  if (multiple_threads)
+    {
+      call_function_static_weak (__nss_database_fork_prepare_parent,
+                                &nss_database_data);
+
+      _IO_list_lock ();
+
+      /* Acquire malloc locks.  This needs to come last because fork
+        handlers may use malloc, and the libio list lock has an
+        indirect malloc dependency as well (via the getdelim
+        function).  */
+      call_function_static_weak (__malloc_fork_lock_parent);
+    }
+
+  pid_t pid = _Fork ();
+
+  if (pid == 0)
+    {
+      fork_system_setup ();
+
+      /* Reset the lock state in the multi-threaded case.  */
+      if (multiple_threads)
+       {
+         __libc_unwind_link_after_fork ();
+
+         fork_system_setup_after_fork ();
+
+         /* Release malloc locks.  */
+         call_function_static_weak (__malloc_fork_unlock_child);
+
+         /* Reset the file list.  These are recursive mutexes.  */
+         fresetlockfiles ();
+
+         /* Reset locks in the I/O code.  */
+         _IO_list_resetlock ();
+
+         call_function_static_weak (__nss_database_fork_subprocess,
+                                    &nss_database_data);
+       }
+
+      /* Reset the lock the dynamic loader uses to protect its data.  */
+      __rtld_lock_initialize (GL(dl_load_lock));
+
+      reclaim_stacks ();
+
+      /* Run the handlers registered for the child.  */
+      __run_fork_handlers (atfork_run_child, multiple_threads);
+    }
+  else
+    {
+      /* Release acquired locks in the multi-threaded case.  */
+      if (multiple_threads)
+       {
+         /* Release malloc locks, parent process variant.  */
+         call_function_static_weak (__malloc_fork_unlock_parent);
+
+         /* We execute this even if the 'fork' call failed.  */
+         _IO_list_unlock ();
+       }
+
+      /* Run the handlers registered for the parent.  */
+      __run_fork_handlers (atfork_run_parent, multiple_threads);
+    }
+
+  return pid;
 }
+weak_alias (__libc_fork, __fork)
 libc_hidden_def (__fork)
-stub_warning (fork)
-
-weak_alias (__fork, fork)
+weak_alias (__libc_fork, fork)
diff --git a/sysdeps/generic/fork.h b/sysdeps/generic/fork.h
new file mode 100644 (file)
index 0000000..be42cf2
--- /dev/null
@@ -0,0 +1,32 @@
+/* System specific fork hooks.  Generic version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+static inline void
+fork_system_setup (void)
+{
+}
+
+static inline void
+fork_system_setup_after_fork (void)
+{
+}
+
+static inline void
+reclaim_stacks (void)
+{
+}
similarity index 98%
rename from sysdeps/mach/hurd/fork.c
rename to sysdeps/mach/hurd/_Fork.c
index 92a51693e0942ca437bf709eaf3267f39890774e..df4ee05faae607b1abdb437513e0f742418f3c2e 100644 (file)
@@ -58,16 +58,13 @@ DEFINE_HOOK (_hurd_fork_parent_hook, (void));
    Return -1 for errors, 0 to the new process,
    and the process ID of the new process to the old process.  */
 pid_t
-__fork (void)
+_Fork (void)
 {
   jmp_buf env;
   pid_t pid;
   size_t i;
   error_t err;
   struct hurd_sigstate *volatile ss;
-  struct nss_database_data nss_database_data;
-
-  __run_fork_handlers (atfork_run_prepare, true);
 
   ss = _hurd_self_sigstate ();
 retry:
@@ -108,9 +105,6 @@ retry:
       /* Run things that prepare for forking before we create the task.  */
       RUN_HOOK (_hurd_fork_prepare_hook, ());
 
-      call_function_static_weak (__nss_database_fork_prepare_parent,
-                                &nss_database_data);
-
       /* Lock things that want to be locked before we fork.  */
       {
        void *const *p;
@@ -670,9 +664,6 @@ retry:
       _hurd_malloc_fork_child ();
       call_function_static_weak (__malloc_fork_unlock_child);
 
-      call_function_static_weak (__nss_database_fork_subprocess,
-                                &nss_database_data);
-
       /* Run things that want to run in the child task to set up.  */
       RUN_HOOK (_hurd_fork_child_hook, ());
 
@@ -723,14 +714,6 @@ retry:
     /* Got a signal while inside an RPC of the critical section, retry again */
     goto retry;
 
-  if (!err)
-    {
-      __run_fork_handlers (pid == 0 ? atfork_run_child : atfork_run_parent,
-                          true);
-    }
-
   return err ? __hurd_fail (err) : pid;
 }
-libc_hidden_def (__fork)
-
-weak_alias (__fork, fork)
+libc_hidden_def (_Fork)
diff --git a/sysdeps/nptl/_Fork.c b/sysdeps/nptl/_Fork.c
new file mode 100644 (file)
index 0000000..6eae146
--- /dev/null
@@ -0,0 +1,52 @@
+/* _Fork implementation.  Linux version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arch-fork.h>
+#include <pthreadP.h>
+
+/* Pointer to the fork generation counter in the thread library.  */
+extern unsigned long int *__fork_generation_pointer attribute_hidden;
+
+pid_t
+_Fork (void)
+{
+  pid_t pid = arch_fork (&THREAD_SELF->tid);
+  if (pid == 0)
+    {
+      struct pthread *self = THREAD_SELF;
+
+      /* Initialize the robust mutex list setting in the kernel which has
+        been reset during the fork.  We do not check for errors because if
+        it fails here, it must have failed at process startup as well and
+        nobody could have used robust mutexes.
+        Before we do that, we have to clear the list of robust mutexes
+        because we do not inherit ownership of mutexes from the parent.
+        We do not have to set self->robust_head.futex_offset since we do
+        inherit the correct value from the parent.  We do not need to clear
+        the pending operation because it must have been zero when fork was
+        called.  */
+#if __PTHREAD_MUTEX_HAVE_PREV
+      self->robust_prev = &self->robust_head;
+#endif
+      self->robust_head.list = &self->robust_head;
+      INTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head,
+                            sizeof (struct robust_list_head));
+    }
+  return pid;
+}
+libc_hidden_def (_Fork)
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
deleted file mode 100644 (file)
index 39ab797..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-/* Copyright (C) 2002-2021 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sysdep.h>
-#include <libio/libioP.h>
-#include <tls.h>
-#include <hp-timing.h>
-#include <ldsodefs.h>
-#include <stdio-lock.h>
-#include <atomic.h>
-#include <pthreadP.h>
-#include <register-atfork.h>
-#include <arch-fork.h>
-#include <futex-internal.h>
-#include <malloc/malloc-internal.h>
-#include <nss/nss_database.h>
-#include <unwind-link.h>
-#include <sys/single_threaded.h>
-#include <list.h>
-
-static void
-fresetlockfiles (void)
-{
-  _IO_ITER i;
-
-  for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
-    if ((_IO_iter_file (i)->_flags & _IO_USER_LOCK) == 0)
-      _IO_lock_init (*((_IO_lock_t *) _IO_iter_file(i)->_lock));
-}
-
-/* In case of a fork() call the memory allocation in the child will be
-   the same but only one thread is running.  All stacks except that of
-   the one running thread are not used anymore.  We have to recycle
-   them.  */
-static void
-reclaim_stacks (void)
-{
-  struct pthread *self = (struct pthread *) THREAD_SELF;
-
-  /* No locking necessary.  The caller is the only stack in use.  But
-     we have to be aware that we might have interrupted a list
-     operation.  */
-
-  if (GL (dl_in_flight_stack) != 0)
-    {
-      bool add_p = GL (dl_in_flight_stack) & 1;
-      list_t *elem = (list_t *) (GL (dl_in_flight_stack) & ~(uintptr_t) 1);
-
-      if (add_p)
-       {
-         /* We always add at the beginning of the list.  So in this case we
-            only need to check the beginning of these lists to see if the
-            pointers at the head of the list are inconsistent.  */
-         list_t *l = NULL;
-
-         if (GL (dl_stack_used).next->prev != &GL (dl_stack_used))
-           l = &GL (dl_stack_used);
-         else if (GL (dl_stack_cache).next->prev != &GL (dl_stack_cache))
-           l = &GL (dl_stack_cache);
-
-         if (l != NULL)
-           {
-             assert (l->next->prev == elem);
-             elem->next = l->next;
-             elem->prev = l;
-             l->next = elem;
-           }
-       }
-      else
-       {
-         /* We can simply always replay the delete operation.  */
-         elem->next->prev = elem->prev;
-         elem->prev->next = elem->next;
-       }
-
-      GL (dl_in_flight_stack) = 0;
-    }
-
-  /* Mark all stacks except the still running one as free.  */
-  list_t *runp;
-  list_for_each (runp, &GL (dl_stack_used))
-    {
-      struct pthread *curp = list_entry (runp, struct pthread, list);
-      if (curp != self)
-       {
-         /* This marks the stack as free.  */
-         curp->tid = 0;
-
-         /* Account for the size of the stack.  */
-         GL (dl_stack_cache_actsize) += curp->stackblock_size;
-
-         if (curp->specific_used)
-           {
-             /* Clear the thread-specific data.  */
-             memset (curp->specific_1stblock, '\0',
-                     sizeof (curp->specific_1stblock));
-
-             curp->specific_used = false;
-
-             for (size_t cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
-               if (curp->specific[cnt] != NULL)
-                 {
-                   memset (curp->specific[cnt], '\0',
-                           sizeof (curp->specific_1stblock));
-
-                   /* We have allocated the block which we do not
-                      free here so re-set the bit.  */
-                   curp->specific_used = true;
-                 }
-           }
-       }
-    }
-
-  /* Add the stack of all running threads to the cache.  */
-  list_splice (&GL (dl_stack_used), &GL (dl_stack_cache));
-
-  /* Remove the entry for the current thread to from the cache list
-     and add it to the list of running threads.  Which of the two
-     lists is decided by the user_stack flag.  */
-  list_del (&self->list);
-
-  /* Re-initialize the lists for all the threads.  */
-  INIT_LIST_HEAD (&GL (dl_stack_used));
-  INIT_LIST_HEAD (&GL (dl_stack_user));
-
-  if (__glibc_unlikely (THREAD_GETMEM (self, user_stack)))
-    list_add (&self->list, &GL (dl_stack_user));
-  else
-    list_add (&self->list, &GL (dl_stack_used));
-}
-
-pid_t
-__libc_fork (void)
-{
-  pid_t pid;
-
-  /* Determine if we are running multiple threads.  We skip some fork
-     handlers in the single-thread case, to make fork safer to use in
-     signal handlers.  POSIX requires that fork is async-signal-safe,
-     but our current fork implementation is not.  */
-  bool multiple_threads = __libc_single_threaded == 0;
-
-  __run_fork_handlers (atfork_run_prepare, multiple_threads);
-
-  struct nss_database_data nss_database_data;
-
-  /* If we are not running multiple threads, we do not have to
-     preserve lock state.  If fork runs from a signal handler, only
-     async-signal-safe functions can be used in the child.  These data
-     structures are only used by unsafe functions, so their state does
-     not matter if fork was called from a signal handler.  */
-  if (multiple_threads)
-    {
-      call_function_static_weak (__nss_database_fork_prepare_parent,
-                                &nss_database_data);
-
-      _IO_list_lock ();
-
-      /* Acquire malloc locks.  This needs to come last because fork
-        handlers may use malloc, and the libio list lock has an
-        indirect malloc dependency as well (via the getdelim
-        function).  */
-      call_function_static_weak (__malloc_fork_lock_parent);
-    }
-
-  pid = arch_fork (&THREAD_SELF->tid);
-
-  if (pid == 0)
-    {
-      struct pthread *self = THREAD_SELF;
-
-      /* See __pthread_once.  */
-      __fork_generation += __PTHREAD_ONCE_FORK_GEN_INCR;
-
-      /* Initialize the robust mutex list setting in the kernel which has
-        been reset during the fork.  We do not check for errors because if
-        it fails here, it must have failed at process startup as well and
-        nobody could have used robust mutexes.
-        Before we do that, we have to clear the list of robust mutexes
-        because we do not inherit ownership of mutexes from the parent.
-        We do not have to set self->robust_head.futex_offset since we do
-        inherit the correct value from the parent.  We do not need to clear
-        the pending operation because it must have been zero when fork was
-        called.  */
-#if __PTHREAD_MUTEX_HAVE_PREV
-      self->robust_prev = &self->robust_head;
-#endif
-      self->robust_head.list = &self->robust_head;
-      INTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head,
-                            sizeof (struct robust_list_head));
-
-      /* Reset the lock state in the multi-threaded case.  */
-      if (multiple_threads)
-       {
-         __libc_unwind_link_after_fork ();
-
-         /* There is one thread running.  */
-         __nptl_nthreads = 1;
-
-         /* Initialize thread library locks.  */
-         GL (dl_stack_cache_lock) = LLL_LOCK_INITIALIZER;
-         __default_pthread_attr_lock = LLL_LOCK_INITIALIZER;
-
-         /* Release malloc locks.  */
-         call_function_static_weak (__malloc_fork_unlock_child);
-
-         /* Reset the file list.  These are recursive mutexes.  */
-         fresetlockfiles ();
-
-         /* Reset locks in the I/O code.  */
-         _IO_list_resetlock ();
-
-         call_function_static_weak (__nss_database_fork_subprocess,
-                                    &nss_database_data);
-       }
-
-      /* Reset the lock the dynamic loader uses to protect its data.  */
-      __rtld_lock_initialize (GL(dl_load_lock));
-
-      reclaim_stacks ();
-
-      /* Run the handlers registered for the child.  */
-      __run_fork_handlers (atfork_run_child, multiple_threads);
-    }
-  else
-    {
-      /* Release acquired locks in the multi-threaded case.  */
-      if (multiple_threads)
-       {
-         /* Release malloc locks, parent process variant.  */
-         call_function_static_weak (__malloc_fork_unlock_parent);
-
-         /* We execute this even if the 'fork' call failed.  */
-         _IO_list_unlock ();
-       }
-
-      /* Run the handlers registered for the parent.  */
-      __run_fork_handlers (atfork_run_parent, multiple_threads);
-    }
-
-  return pid;
-}
-weak_alias (__libc_fork, __fork)
-libc_hidden_def (__fork)
-weak_alias (__libc_fork, fork)
diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
new file mode 100644 (file)
index 0000000..3134d7a
--- /dev/null
@@ -0,0 +1,148 @@
+/* System specific fork hooks.  Linux version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _FORK_H
+#define _FORK_H
+
+#include <assert.h>
+#include <ldsodefs.h>
+#include <list.h>
+#include <pthreadP.h>
+#include <sysdep.h>
+
+static inline void
+fork_system_setup (void)
+{
+  /* See __pthread_once.  */
+  __fork_generation += __PTHREAD_ONCE_FORK_GEN_INCR;
+}
+
+static void
+fork_system_setup_after_fork (void)
+{
+  /* There is one thread running.  */
+  __nptl_nthreads = 1;
+
+  /* Initialize thread library locks.  */
+  GL (dl_stack_cache_lock) = LLL_LOCK_INITIALIZER;
+  __default_pthread_attr_lock = LLL_LOCK_INITIALIZER;
+}
+
+/* In case of a fork() call the memory allocation in the child will be
+   the same but only one thread is running.  All stacks except that of
+   the one running thread are not used anymore.  We have to recycle
+   them.  */
+static void
+reclaim_stacks (void)
+{
+  struct pthread *self = (struct pthread *) THREAD_SELF;
+
+  /* No locking necessary.  The caller is the only stack in use.  But
+     we have to be aware that we might have interrupted a list
+     operation.  */
+
+  if (GL (dl_in_flight_stack) != 0)
+    {
+      bool add_p = GL (dl_in_flight_stack) & 1;
+      list_t *elem = (list_t *) (GL (dl_in_flight_stack) & ~(uintptr_t) 1);
+
+      if (add_p)
+       {
+         /* We always add at the beginning of the list.  So in this case we
+            only need to check the beginning of these lists to see if the
+            pointers at the head of the list are inconsistent.  */
+         list_t *l = NULL;
+
+         if (GL (dl_stack_used).next->prev != &GL (dl_stack_used))
+           l = &GL (dl_stack_used);
+         else if (GL (dl_stack_cache).next->prev != &GL (dl_stack_cache))
+           l = &GL (dl_stack_cache);
+
+         if (l != NULL)
+           {
+             assert (l->next->prev == elem);
+             elem->next = l->next;
+             elem->prev = l;
+             l->next = elem;
+           }
+       }
+      else
+       {
+         /* We can simply always replay the delete operation.  */
+         elem->next->prev = elem->prev;
+         elem->prev->next = elem->next;
+       }
+
+      GL (dl_in_flight_stack) = 0;
+    }
+
+  /* Mark all stacks except the still running one as free.  */
+  list_t *runp;
+  list_for_each (runp, &GL (dl_stack_used))
+    {
+      struct pthread *curp = list_entry (runp, struct pthread, list);
+      if (curp != self)
+       {
+         /* This marks the stack as free.  */
+         curp->tid = 0;
+
+         /* Account for the size of the stack.  */
+         GL (dl_stack_cache_actsize) += curp->stackblock_size;
+
+         if (curp->specific_used)
+           {
+             /* Clear the thread-specific data.  */
+             memset (curp->specific_1stblock, '\0',
+                     sizeof (curp->specific_1stblock));
+
+             curp->specific_used = false;
+
+             for (size_t cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
+               if (curp->specific[cnt] != NULL)
+                 {
+                   memset (curp->specific[cnt], '\0',
+                           sizeof (curp->specific_1stblock));
+
+                   /* We have allocated the block which we do not
+                      free here so re-set the bit.  */
+                   curp->specific_used = true;
+                 }
+           }
+       }
+    }
+
+  /* Add the stack of all running threads to the cache.  */
+  list_splice (&GL (dl_stack_used), &GL (dl_stack_cache));
+
+  /* Remove the entry for the current thread to from the cache list
+     and add it to the list of running threads.  Which of the two
+     lists is decided by the user_stack flag.  */
+  list_del (&self->list);
+
+  /* Re-initialize the lists for all the threads.  */
+  INIT_LIST_HEAD (&GL (dl_stack_used));
+  INIT_LIST_HEAD (&GL (dl_stack_user));
+
+  if (__glibc_unlikely (THREAD_GETMEM (self, user_stack)))
+    list_add (&self->list, &GL (dl_stack_user));
+  else
+    list_add (&self->list, &GL (dl_stack_used));
+}
+
+
+#endif
index 35d9397ff8dc69771cbe9525c7282a415f648a06..b846da08f98839aef336868de24850626428509c 100644 (file)
@@ -19,6 +19,9 @@
 #ifndef __ARCH_FORK_H
 #define __ARCH_FORK_H
 
+#include <sysdep.h>
+#include <sched.h>
+#include <signal.h>
 #include <unistd.h>
 
 /* Call the clone syscall with fork semantic.  The CTID address is used