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:
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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
|
@ -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
|
||||||
|
@ -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 \
|
||||||
|
@ -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
|
@ -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/>. */
|
||||||
|
@ -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. */
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
|
||||||
|
Reference in New Issue
Block a user