diff options
author | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2021-01-18 15:10:02 -0300 |
---|---|---|
committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2021-03-12 10:19:22 -0300 |
commit | 2b47727c68b6329cf8890e56fc9dbaa4e7300961 (patch) | |
tree | a6068c64f81fa0221cddd7f96d4a2ed3fbf816a9 | |
parent | cdba937662b16fc3685a8115f21e73f21330a44c (diff) | |
download | glibc-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/Makefile | 2 | ||||
-rw-r--r-- | htl/register-atfork.c | 157 | ||||
-rw-r--r-- | include/register-atfork.h (renamed from sysdeps/htl/fork.h) | 38 | ||||
-rw-r--r-- | nptl/Makefile | 1 | ||||
-rw-r--r-- | posix/Makefile | 2 | ||||
-rw-r--r-- | posix/register-atfork.c (renamed from nptl/register-atfork.c) | 8 | ||||
-rw-r--r-- | sysdeps/generic/fork.h | 19 | ||||
-rw-r--r-- | sysdeps/htl/pt-atfork.c | 1 | ||||
-rw-r--r-- | sysdeps/mach/hurd/fork.c | 15 | ||||
-rw-r--r-- | sysdeps/nptl/fork.h | 42 |
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) |