mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00: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:
parent
cdba937662
commit
2b47727c68
@ -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
|
||||
|
||||
|
@ -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.
|
||||
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
|
@ -74,7 +74,6 @@ routines = \
|
||||
pthread_self \
|
||||
pthread_setschedparam \
|
||||
pthread_sigmask \
|
||||
register-atfork \
|
||||
|
||||
shared-only-routines = forward
|
||||
static-only-routines = pthread_atfork
|
||||
|
@ -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 \
|
||||
|
@ -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
|
@ -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/>. */
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user