about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2021-01-18 15:10:02 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2021-03-12 10:19:22 -0300
commit2b47727c68b6329cf8890e56fc9dbaa4e7300961 (patch)
treea6068c64f81fa0221cddd7f96d4a2ed3fbf816a9
parentcdba937662b16fc3685a8115f21e73f21330a44c (diff)
downloadglibc-2b47727c68b6329cf8890e56fc9dbaa4e7300961.tar.gz
glibc-2b47727c68b6329cf8890e56fc9dbaa4e7300961.tar.xz
glibc-2b47727c68b6329cf8890e56fc9dbaa4e7300961.zip
posix: Consolidate register-atfork
Both htl and nptl uses a different data structure to implement atfork
handlers.  The nptl one was refactored by 27761a1042d to use a dynarray
which simplifies the code.

This patch moves the nptl one to be the generic implementation and
replace Hurd linked one.  Different than previous NPTL, Hurd also uses
a global lock, so performance should be similar.

Checked on x86_64-linux-gnu, i686-linux-gnu, and with a build for
i686-gnu.
-rw-r--r--htl/Makefile2
-rw-r--r--htl/register-atfork.c157
-rw-r--r--include/register-atfork.h (renamed from sysdeps/htl/fork.h)38
-rw-r--r--nptl/Makefile1
-rw-r--r--posix/Makefile2
-rw-r--r--posix/register-atfork.c (renamed from nptl/register-atfork.c)8
-rw-r--r--sysdeps/generic/fork.h19
-rw-r--r--sysdeps/htl/pt-atfork.c1
-rw-r--r--sysdeps/mach/hurd/fork.c15
-rw-r--r--sysdeps/nptl/fork.h42
10 files changed, 66 insertions, 219 deletions
diff --git a/htl/Makefile b/htl/Makefile
index c15c1b194e..895a6f777c 100644
--- a/htl/Makefile
+++ b/htl/Makefile
@@ -165,7 +165,7 @@ headers :=				\
 
 distribute :=
 
-routines := forward libc_pthread_init alloca_cutoff register-atfork pt-atfork
+routines := forward libc_pthread_init alloca_cutoff pt-atfork
 shared-only-routines = forward
 static-only-routines = pt-atfork
 
diff --git a/htl/register-atfork.c b/htl/register-atfork.c
deleted file mode 100644
index 8be132f981..0000000000
--- a/htl/register-atfork.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/* Atfork handling.  Hurd pthread version.
-   Copyright (C) 2002-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 <stdlib.h>
-#include <libc-lock.h>
-#include <fork.h>
-
-struct atfork
-{
-  void (*prepare) (void);
-  void (*parent) (void);
-  void (*child) (void);
-  void *dso_handle;
-  struct atfork *prev;
-  struct atfork *next;
-};
-
-/* TODO: better locking */
-__libc_lock_define_initialized (static, atfork_lock);
-static struct atfork *fork_handlers, *fork_last_handler;
-
-static void
-atfork_pthread_prepare (void)
-{
-  struct atfork *handlers, *last_handler;
-
-  __libc_lock_lock (atfork_lock);
-  handlers = fork_handlers;
-  last_handler = fork_last_handler;
-  __libc_lock_unlock (atfork_lock);
-
-  if (last_handler == NULL)
-    return;
-
-  while (1)
-    {
-      if (last_handler->prepare != NULL)
-	last_handler->prepare ();
-      if (last_handler == handlers)
-	break;
-      last_handler = last_handler->prev;
-    }
-}
-text_set_element (_hurd_atfork_prepare_hook, atfork_pthread_prepare);
-
-static void
-atfork_pthread_parent (void)
-{
-  struct atfork *handlers;
-
-  __libc_lock_lock (atfork_lock);
-  handlers = fork_handlers;
-  __libc_lock_unlock (atfork_lock);
-
-  while (handlers != NULL)
-    {
-      if (handlers->parent != NULL)
-	handlers->parent ();
-      handlers = handlers->next;
-    }
-}
-text_set_element (_hurd_atfork_parent_hook, atfork_pthread_parent);
-
-static void
-atfork_pthread_child (void)
-{
-  struct atfork *handlers;
-
-  __libc_lock_lock (atfork_lock);
-  handlers = fork_handlers;
-  __libc_lock_unlock (atfork_lock);
-
-  while (handlers != NULL)
-    {
-      if (handlers->child != NULL)
-	handlers->child ();
-      handlers = handlers->next;
-    }
-}
-text_set_element (_hurd_atfork_child_hook, atfork_pthread_child);
-
-int
-__register_atfork (void (*prepare) (void),
-		   void (*parent) (void),
-		   void (*child) (void),
-		   void *dso_handle)
-{
-  struct atfork *new = malloc (sizeof (*new));
-  if (new == NULL)
-    return errno;
-
-  new->prepare = prepare;
-  new->parent = parent;
-  new->child = child;
-  new->dso_handle = dso_handle;
-  new->next = NULL;
-
-  __libc_lock_lock (atfork_lock);
-  new->prev = fork_last_handler;
-  if (fork_last_handler != NULL)
-    fork_last_handler->next = new;
-  if (fork_handlers == NULL)
-    fork_handlers = new;
-  fork_last_handler = new;
-  __libc_lock_unlock (atfork_lock);
-
-  return 0;
-}
-libc_hidden_def (__register_atfork)
-
-void
-__unregister_atfork (void *dso_handle)
-{
-  struct atfork **handlers, *prev = NULL, *next;
-  __libc_lock_lock (atfork_lock);
-  handlers = &fork_handlers;
-  while (*handlers != NULL)
-    {
-      if ((*handlers)->dso_handle == dso_handle)
-	{
-	  /* Drop this handler from the list.  */
-	  if (*handlers == fork_last_handler)
-	    {
-	      /* Was last, new last is prev, if any.  */
-	      fork_last_handler = prev;
-	    }
-
-	  next = (*handlers)->next;
-	  if (next != NULL)
-	    next->prev = prev;
-	  *handlers = next;
-	}
-      else
-	{
-	  /* Just proceed to next handler.  */
-	  prev = *handlers;
-	  handlers = &prev->next;
-	}
-    }
-  __libc_lock_unlock (atfork_lock);
-}
diff --git a/sysdeps/htl/fork.h b/include/register-atfork.h
index 0fccc309f8..fadde14700 100644
--- a/sysdeps/htl/fork.h
+++ b/include/register-atfork.h
@@ -1,5 +1,5 @@
-/* Register fork handlers.  Generic version.
-   Copyright (C) 2002-2021 Free Software Foundation, Inc.
+/* Internal pthread_atfork definitions.
+   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
@@ -16,10 +16,42 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#ifndef _REGISTER_ATFORK_H
+#define _REGISTER_ATFORK_H
+
+/* Elements of the fork handler lists.  */
+struct fork_handler
+{
+  void (*prepare_handler) (void);
+  void (*parent_handler) (void);
+  void (*child_handler) (void);
+  void *dso_handle;
+};
+
 /* Function to call to unregister fork handlers.  */
 extern void __unregister_atfork (void *dso_handle) attribute_hidden;
 #define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle)
 
+enum __run_fork_handler_type
+{
+  atfork_run_prepare,
+  atfork_run_child,
+  atfork_run_parent
+};
+
+/* Run the atfork handlers and lock/unlock the internal lock depending
+   of the WHO argument:
+
+   - atfork_run_prepare: run all the PREPARE_HANDLER in reverse order of
+			 insertion and locks the internal lock.
+   - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal
+		       lock.
+   - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal
+			lock.
+
+   Perform locking only if DO_LOCKING.  */
+extern void __run_fork_handlers (enum __run_fork_handler_type who,
+				 _Bool do_locking) attribute_hidden;
 
 /* C library side function to register new fork handlers.  */
 extern int __register_atfork (void (*__prepare) (void),
@@ -27,3 +59,5 @@ extern int __register_atfork (void (*__prepare) (void),
 			      void (*__child) (void),
 			      void *dso_handle);
 libc_hidden_proto (__register_atfork)
+
+#endif
diff --git a/nptl/Makefile b/nptl/Makefile
index 33766eaf7a..e5d69e8858 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -74,7 +74,6 @@ routines = \
   pthread_self \
   pthread_setschedparam \
   pthread_sigmask \
-  register-atfork \
 
 shared-only-routines = forward
 static-only-routines = pthread_atfork
diff --git a/posix/Makefile b/posix/Makefile
index 305ec757cd..be0c72f0bb 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -39,7 +39,7 @@ routines :=								      \
 	times								      \
 	wait waitpid wait3 wait4 waitid					      \
 	alarm sleep pause nanosleep					      \
-	fork vfork _exit						      \
+	fork vfork _exit register-atfork				      \
 	execve fexecve execv execle execl execvp execlp execvpe		      \
 	getpid getppid							      \
 	getuid geteuid getgid getegid getgroups setuid setgid group_member    \
diff --git a/nptl/register-atfork.c b/posix/register-atfork.c
index 30c16fba40..6fd9e4c56a 100644
--- a/nptl/register-atfork.c
+++ b/posix/register-atfork.c
@@ -16,11 +16,9 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fork.h>
-#include <atomic.h>
+#include <libc-lock.h>
+#include <stdbool.h>
+#include <register-atfork.h>
 
 #define DYNARRAY_ELEMENT           struct fork_handler
 #define DYNARRAY_STRUCT            fork_handler_list
diff --git a/sysdeps/generic/fork.h b/sysdeps/generic/fork.h
index 623cae28df..6cc842a425 100644
--- a/sysdeps/generic/fork.h
+++ b/sysdeps/generic/fork.h
@@ -6,3 +6,22 @@
      parameter which is the DSO handle for the DSO which gets unloaded.
      The function so called has to remove the atfork handlers registered
      by this module.  */
+
+
+/* System specific fork definition.  Generic version.
+   Copyright (C) 2002-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/>.  */
diff --git a/sysdeps/htl/pt-atfork.c b/sysdeps/htl/pt-atfork.c
index 3d115d3819..dbb3b8f0cc 100644
--- a/sysdeps/htl/pt-atfork.c
+++ b/sysdeps/htl/pt-atfork.c
@@ -20,6 +20,7 @@
 #include <pt-internal.h>
 #include <fork.h>
 #include <dso_handle.h>
+#include <register-atfork.h>
 
 /* Hide the symbol so that no definition but the one locally in the
    executable or DSO is used.  */
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index 2b39f4e8b5..1c5299e686 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -30,6 +30,7 @@
 #include <malloc/malloc-internal.h>
 #include <nss/nss_database.h>
 #include <unwind-link.h>
+#include <register-atfork.h>
 
 #undef __fork
 
@@ -37,12 +38,6 @@
 /* Things that want to be locked while forking.  */
 symbol_set_declare (_hurd_fork_locks)
 
-
-/* Application callbacks registered through pthread_atfork.  */
-DEFINE_HOOK (_hurd_atfork_prepare_hook, (void));
-DEFINE_HOOK (_hurd_atfork_child_hook, (void));
-DEFINE_HOOK (_hurd_atfork_parent_hook, (void));
-
 /* Things that want to be called before we fork, to prepare the parent for
    task_create, when the new child task will inherit our address space.  */
 DEFINE_HOOK (_hurd_fork_prepare_hook, (void));
@@ -72,7 +67,7 @@ __fork (void)
   struct hurd_sigstate *volatile ss;
   struct nss_database_data nss_database_data;
 
-  RUN_HOOK (_hurd_atfork_prepare_hook, ());
+  __run_fork_handlers (atfork_run_prepare, true);
 
   ss = _hurd_self_sigstate ();
   __spin_lock (&ss->critical_section_lock);
@@ -726,10 +721,8 @@ __fork (void)
 
   if (!err)
     {
-      if (pid != 0)
-	RUN_HOOK (_hurd_atfork_parent_hook, ());
-      else
-	RUN_HOOK (_hurd_atfork_child_hook, ());
+      __run_fork_handlers (pid == 0 ? atfork_run_child : atfork_run_parent,
+			   true);
     }
 
   return err ? __hurd_fail (err) : pid;
diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
index 25002287b1..5246754290 100644
--- a/sysdeps/nptl/fork.h
+++ b/sysdeps/nptl/fork.h
@@ -17,50 +17,10 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <lowlevellock.h>
+#include <register-atfork.h>
 
 /* The fork generation counter, defined in libpthread.  */
 extern unsigned long int __fork_generation attribute_hidden;
 
 /* Pointer to the fork generation counter in the thread library.  */
 extern unsigned long int *__fork_generation_pointer attribute_hidden;
-
-/* Elements of the fork handler lists.  */
-struct fork_handler
-{
-  void (*prepare_handler) (void);
-  void (*parent_handler) (void);
-  void (*child_handler) (void);
-  void *dso_handle;
-};
-
-/* Function to call to unregister fork handlers.  */
-extern void __unregister_atfork (void *dso_handle) attribute_hidden;
-#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle)
-
-enum __run_fork_handler_type
-{
-  atfork_run_prepare,
-  atfork_run_child,
-  atfork_run_parent
-};
-
-/* Run the atfork handlers and lock/unlock the internal lock depending
-   of the WHO argument:
-
-   - atfork_run_prepare: run all the PREPARE_HANDLER in reverse order of
-			 insertion and locks the internal lock.
-   - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal
-		       lock.
-   - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal
-			lock.
-
-   Perform locking only if DO_LOCKING.  */
-extern void __run_fork_handlers (enum __run_fork_handler_type who,
-				 _Bool do_locking) attribute_hidden;
-
-/* C library side function to register new fork handlers.  */
-extern int __register_atfork (void (*__prepare) (void),
-			      void (*__parent) (void),
-			      void (*__child) (void),
-			      void *dso_handle);
-libc_hidden_proto (__register_atfork)