1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-30 22:43:12 +03:00

posix: Consolidate register-atfork

Both htl and nptl uses a different data structure to implement atfork
handlers.  The nptl one was refactored by 27761a1042 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.
This commit is contained in:
Adhemerval Zanella
2021-01-18 15:10:02 -03:00
parent cdba937662
commit 2b47727c68
10 changed files with 66 additions and 219 deletions

View File

@ -165,7 +165,7 @@ headers := \
distribute := 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 shared-only-routines = forward
static-only-routines = pt-atfork static-only-routines = pt-atfork

View File

@ -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);
}

View File

@ -1,5 +1,5 @@
/* Register fork handlers. Generic version. /* Internal pthread_atfork definitions.
Copyright (C) 2002-2021 Free Software Foundation, Inc. Copyright (C) 2021 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or 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 License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */ <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. */ /* Function to call to unregister fork handlers. */
extern void __unregister_atfork (void *dso_handle) attribute_hidden; extern void __unregister_atfork (void *dso_handle) attribute_hidden;
#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle) #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. */ /* C library side function to register new fork handlers. */
extern int __register_atfork (void (*__prepare) (void), extern int __register_atfork (void (*__prepare) (void),
@ -27,3 +59,5 @@ extern int __register_atfork (void (*__prepare) (void),
void (*__child) (void), void (*__child) (void),
void *dso_handle); void *dso_handle);
libc_hidden_proto (__register_atfork) libc_hidden_proto (__register_atfork)
#endif

View File

@ -74,7 +74,6 @@ routines = \
pthread_self \ pthread_self \
pthread_setschedparam \ pthread_setschedparam \
pthread_sigmask \ pthread_sigmask \
register-atfork \
shared-only-routines = forward shared-only-routines = forward
static-only-routines = pthread_atfork static-only-routines = pthread_atfork

View File

@ -39,7 +39,7 @@ routines := \
times \ times \
wait waitpid wait3 wait4 waitid \ wait waitpid wait3 wait4 waitid \
alarm sleep pause nanosleep \ alarm sleep pause nanosleep \
fork vfork _exit \ fork vfork _exit register-atfork \
execve fexecve execv execle execl execvp execlp execvpe \ execve fexecve execv execle execl execvp execlp execvpe \
getpid getppid \ getpid getppid \
getuid geteuid getgid getegid getgroups setuid setgid group_member \ getuid geteuid getgid getegid getgroups setuid setgid group_member \

View File

@ -16,11 +16,9 @@
License along with the GNU C Library; if not, see License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#include <errno.h> #include <libc-lock.h>
#include <stdlib.h> #include <stdbool.h>
#include <string.h> #include <register-atfork.h>
#include <fork.h>
#include <atomic.h>
#define DYNARRAY_ELEMENT struct fork_handler #define DYNARRAY_ELEMENT struct fork_handler
#define DYNARRAY_STRUCT fork_handler_list #define DYNARRAY_STRUCT fork_handler_list

View File

@ -6,3 +6,22 @@
parameter which is the DSO handle for the DSO which gets unloaded. parameter which is the DSO handle for the DSO which gets unloaded.
The function so called has to remove the atfork handlers registered The function so called has to remove the atfork handlers registered
by this module. */ 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/>. */

View File

@ -20,6 +20,7 @@
#include <pt-internal.h> #include <pt-internal.h>
#include <fork.h> #include <fork.h>
#include <dso_handle.h> #include <dso_handle.h>
#include <register-atfork.h>
/* Hide the symbol so that no definition but the one locally in the /* Hide the symbol so that no definition but the one locally in the
executable or DSO is used. */ executable or DSO is used. */

View File

@ -30,6 +30,7 @@
#include <malloc/malloc-internal.h> #include <malloc/malloc-internal.h>
#include <nss/nss_database.h> #include <nss/nss_database.h>
#include <unwind-link.h> #include <unwind-link.h>
#include <register-atfork.h>
#undef __fork #undef __fork
@ -37,12 +38,6 @@
/* Things that want to be locked while forking. */ /* Things that want to be locked while forking. */
symbol_set_declare (_hurd_fork_locks) 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 /* 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. */ task_create, when the new child task will inherit our address space. */
DEFINE_HOOK (_hurd_fork_prepare_hook, (void)); DEFINE_HOOK (_hurd_fork_prepare_hook, (void));
@ -72,7 +67,7 @@ __fork (void)
struct hurd_sigstate *volatile ss; struct hurd_sigstate *volatile ss;
struct nss_database_data nss_database_data; struct nss_database_data nss_database_data;
RUN_HOOK (_hurd_atfork_prepare_hook, ()); __run_fork_handlers (atfork_run_prepare, true);
ss = _hurd_self_sigstate (); ss = _hurd_self_sigstate ();
__spin_lock (&ss->critical_section_lock); __spin_lock (&ss->critical_section_lock);
@ -726,10 +721,8 @@ __fork (void)
if (!err) if (!err)
{ {
if (pid != 0) __run_fork_handlers (pid == 0 ? atfork_run_child : atfork_run_parent,
RUN_HOOK (_hurd_atfork_parent_hook, ()); true);
else
RUN_HOOK (_hurd_atfork_child_hook, ());
} }
return err ? __hurd_fail (err) : pid; return err ? __hurd_fail (err) : pid;

View File

@ -17,50 +17,10 @@
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#include <lowlevellock.h> #include <lowlevellock.h>
#include <register-atfork.h>
/* The fork generation counter, defined in libpthread. */ /* The fork generation counter, defined in libpthread. */
extern unsigned long int __fork_generation attribute_hidden; extern unsigned long int __fork_generation attribute_hidden;
/* Pointer to the fork generation counter in the thread library. */ /* Pointer to the fork generation counter in the thread library. */
extern unsigned long int *__fork_generation_pointer attribute_hidden; 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)