* [PATCH v4 0/4] Add _Fork implementation
@ 2021-06-23 18:43 Adhemerval Zanella
2021-06-23 18:43 ` [PATCH v4 1/4] posix: Consolidate fork implementation Adhemerval Zanella
` (3 more replies)
0 siblings, 4 replies; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-23 18:43 UTC (permalink / raw)
To: libc-alpha
Austin Group issue 62 [1] dropped the async-signal-safe requirement
for fork and provided a async-signal-safe _Fork replacement that
does not run the atfork handlers. It will be included in the next
POSIX standard.
It allow close a long standing issue that ask fork to be AS-safe
(BZ#4737) now that we provide a similar call.
The first patch consolidates the fork implementation between Linux
and Hurd, moving the arch-specifics bits to the system specific
fork.h header. The process spawn core is moved to the internal
symbol _Fork, which will be exported in the final patch.
Second patch a minor issue with atfork handler.
Third patch consolidates the pthread_atfork implementation over
Linux and Hurd.
The final patch exports the new _Fork symbol and add some regression
tests.
*** BLURB HERE ***
Adhemerval Zanella (4):
posix: Consolidate fork implementation
posix: Do not clobber errno by atfork handlers
Consolidate pthread_atfork
posix: Add _Fork [BZ #4737]
NEWS | 8 +
htl/Makefile | 4 +-
include/unistd.h | 4 +
malloc/Makefile | 3 +
malloc/tst-mallocfork3.c | 213 ++++++++++++++
manual/process.texi | 39 ++-
nptl/Makefile | 1 -
posix/Makefile | 6 +-
posix/Versions | 1 +
posix/_Fork.c | 34 +++
posix/fork.c | 124 +++++++-
posix/tst-_Fork.c | 218 +++++++++++++++
posix/unistd.h | 7 +
.../{htl/old_pt-atfork.c => generic/fork.h} | 26 +-
sysdeps/htl/pt-atfork.c | 41 ---
sysdeps/htl/pthread_atfork_compat.h | 4 +
sysdeps/mach/hurd/{fork.c => _Fork.c} | 21 +-
sysdeps/nptl/_Fork.c | 52 ++++
sysdeps/nptl/fork.c | 264 ------------------
sysdeps/nptl/fork.h | 148 ++++++++++
sysdeps/nptl/pthread_atfork_compat.h | 4 +
sysdeps/pthread/Makefile | 4 +-
{nptl => sysdeps/pthread}/pthread_atfork.c | 1 +
.../pthread/pthread_atfork_compat.c | 8 +-
sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arc/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arch-fork.h | 3 +
sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 +
sysdeps/unix/sysv/linux/csky/libc.abilist | 1 +
sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 1 +
sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 +
.../sysv/linux/m68k/coldfire/libc.abilist | 1 +
.../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 +
.../sysv/linux/microblaze/be/libc.abilist | 1 +
.../sysv/linux/microblaze/le/libc.abilist | 1 +
.../sysv/linux/mips/mips32/fpu/libc.abilist | 1 +
.../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n32/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 +
.../linux/powerpc/powerpc32/fpu/libc.abilist | 1 +
.../powerpc/powerpc32/nofpu/libc.abilist | 1 +
.../linux/powerpc/powerpc64/be/libc.abilist | 1 +
.../linux/powerpc/powerpc64/le/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv32/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv64/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-32/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 +
.../sysv/linux/sparc/sparc32/libc.abilist | 1 +
.../sysv/linux/sparc/sparc64/libc.abilist | 1 +
.../unix/sysv/linux/x86_64/64/libc.abilist | 1 +
.../unix/sysv/linux/x86_64/x32/libc.abilist | 1 +
57 files changed, 898 insertions(+), 372 deletions(-)
create mode 100644 malloc/tst-mallocfork3.c
create mode 100644 posix/_Fork.c
create mode 100644 posix/tst-_Fork.c
rename sysdeps/{htl/old_pt-atfork.c => generic/fork.h} (61%)
delete mode 100644 sysdeps/htl/pt-atfork.c
create mode 100644 sysdeps/htl/pthread_atfork_compat.h
rename sysdeps/mach/hurd/{fork.c => _Fork.c} (98%)
create mode 100644 sysdeps/nptl/_Fork.c
delete mode 100644 sysdeps/nptl/fork.c
create mode 100644 sysdeps/nptl/fork.h
create mode 100644 sysdeps/nptl/pthread_atfork_compat.h
rename {nptl => sysdeps/pthread}/pthread_atfork.c (98%)
rename nptl/old_pthread_atfork.c => sysdeps/pthread/pthread_atfork_compat.c (84%)
--
2.30.2
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v4 1/4] posix: Consolidate fork implementation
2021-06-23 18:43 [PATCH v4 0/4] Add _Fork implementation Adhemerval Zanella
@ 2021-06-23 18:43 ` Adhemerval Zanella
2021-06-24 8:15 ` Florian Weimer
2021-06-23 18:43 ` [PATCH v4 2/4] posix: Do not clobber errno by atfork handlers Adhemerval Zanella
` (2 subsequent siblings)
3 siblings, 1 reply; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-23 18:43 UTC (permalink / raw)
To: libc-alpha
The Linux nptl implementation is used as base for generic fork
implementation to handle the internal locks and mutexes. The
system specific bits are moved a new internal _Fork symbol.
(This new implementation will be used to provide a async-signal-safe
_Fork now that POSIX has clarified that fork might not be
async-signal-safe [1]).
For Hurd it means that the __nss_database_fork_prepare_parent and
__nss_database_fork_subprocess will be run in a slight different
order.
[1] https://austingroupbugs.net/view.php?id=62
---
include/unistd.h | 4 +
posix/Makefile | 3 +-
posix/_Fork.c | 34 ++++
posix/fork.c | 116 +++++++++--
sysdeps/generic/fork.h | 32 ++++
sysdeps/mach/hurd/{fork.c => _Fork.c} | 21 +-
sysdeps/nptl/_Fork.c | 52 +++++
sysdeps/nptl/fork.c | 264 --------------------------
sysdeps/nptl/fork.h | 148 +++++++++++++++
sysdeps/unix/sysv/linux/arch-fork.h | 3 +
10 files changed, 380 insertions(+), 297 deletions(-)
create mode 100644 posix/_Fork.c
create mode 100644 sysdeps/generic/fork.h
rename sysdeps/mach/hurd/{fork.c => _Fork.c} (98%)
create mode 100644 sysdeps/nptl/_Fork.c
delete mode 100644 sysdeps/nptl/fork.c
create mode 100644 sysdeps/nptl/fork.h
diff --git a/include/unistd.h b/include/unistd.h
index 34872d8b41..d554d44edb 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -140,6 +140,10 @@ extern __pid_t __vfork (void);
libc_hidden_proto (__vfork)
extern int __ttyname_r (int __fd, char *__buf, size_t __buflen);
libc_hidden_proto (__ttyname_r)
+extern int __ttyname_r (int __fd, char *__buf, size_t __buflen)
+ attribute_hidden;
+extern __pid_t _Fork (void);
+libc_hidden_proto (_Fork);
extern int __isatty (int __fd) attribute_hidden;
extern int __link (const char *__from, const char *__to);
extern int __symlink (const char *__from, const char *__to);
diff --git a/posix/Makefile b/posix/Makefile
index 8d139e54f6..3bd7d605df 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 register-atfork \
+ fork _Fork vfork _exit register-atfork \
execve fexecve execv execle execl execvp execlp execvpe \
getpid getppid \
getuid geteuid getgid getegid getgroups setuid setgid group_member \
@@ -266,6 +266,7 @@ CFLAGS-execl.os = -fomit-frame-pointer
CFLAGS-execvp.os = -fomit-frame-pointer
CFLAGS-execlp.os = -fomit-frame-pointer
CFLAGS-nanosleep.c += -fexceptions -fasynchronous-unwind-tables
+CFLAGS-fork.c = $(libio-mtsafe)
tstgetopt-ARGS = -a -b -cfoobar --required foobar --optional=bazbug \
--none random --col --color --colour
diff --git a/posix/_Fork.c b/posix/_Fork.c
new file mode 100644
index 0000000000..4a998c04f1
--- /dev/null
+++ b/posix/_Fork.c
@@ -0,0 +1,34 @@
+/* _Fork implementation. Generic version.
+ 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
+ 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 <unistd.h>
+
+/* Clone the calling process, creating an exact copy. Return -1 for errors,
+ 0 to the new process, and the process ID of the new process to the
+ old process.
+ Different than fork, this functions is marked as async-signal-safe by
+ POSIX (by Austin Group issue 62). */
+pid_t
+_Fork (void)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (_Fork)
+stub_warning (_Fork)
diff --git a/posix/fork.c b/posix/fork.c
index 05bda04ac5..44caf8d166 100644
--- a/posix/fork.c
+++ b/posix/fork.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2021 Free Software Foundation, Inc.
+/* fork - create a child process.
+ Copyright (C) 1991-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
@@ -15,20 +16,109 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#include <errno.h>
-#include <unistd.h>
+#include <fork.h>
+#include <libio/libioP.h>
+#include <ldsodefs.h>
+#include <malloc/malloc-internal.h>
+#include <nss/nss_database.h>
+#include <register-atfork.h>
+#include <stdio-lock.h>
+#include <sys/single_threaded.h>
+#include <unwind-link.h>
+static void
+fresetlockfiles (void)
+{
+ _IO_ITER i;
+
+ for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
+ if ((_IO_iter_file (i)->_flags & _IO_USER_LOCK) == 0)
+ _IO_lock_init (*((_IO_lock_t *) _IO_iter_file(i)->_lock));
+}
-/* Clone the calling process, creating an exact copy.
- Return -1 for errors, 0 to the new process,
- and the process ID of the new process to the old process. */
-int
-__fork (void)
+pid_t
+__libc_fork (void)
{
- __set_errno (ENOSYS);
- return -1;
+ /* Determine if we are running multiple threads. We skip some fork
+ handlers in the single-thread case, to make fork safer to use in
+ signal handlers. */
+ bool multiple_threads = __libc_single_threaded == 0;
+
+ __run_fork_handlers (atfork_run_prepare, multiple_threads);
+
+ struct nss_database_data nss_database_data;
+
+ /* If we are not running multiple threads, we do not have to
+ preserve lock state. If fork runs from a signal handler, only
+ async-signal-safe functions can be used in the child. These data
+ structures are only used by unsafe functions, so their state does
+ not matter if fork was called from a signal handler. */
+ if (multiple_threads)
+ {
+ call_function_static_weak (__nss_database_fork_prepare_parent,
+ &nss_database_data);
+
+ _IO_list_lock ();
+
+ /* Acquire malloc locks. This needs to come last because fork
+ handlers may use malloc, and the libio list lock has an
+ indirect malloc dependency as well (via the getdelim
+ function). */
+ call_function_static_weak (__malloc_fork_lock_parent);
+ }
+
+ pid_t pid = _Fork ();
+
+ if (pid == 0)
+ {
+ fork_system_setup ();
+
+ /* Reset the lock state in the multi-threaded case. */
+ if (multiple_threads)
+ {
+ __libc_unwind_link_after_fork ();
+
+ fork_system_setup_after_fork ();
+
+ /* Release malloc locks. */
+ call_function_static_weak (__malloc_fork_unlock_child);
+
+ /* Reset the file list. These are recursive mutexes. */
+ fresetlockfiles ();
+
+ /* Reset locks in the I/O code. */
+ _IO_list_resetlock ();
+
+ call_function_static_weak (__nss_database_fork_subprocess,
+ &nss_database_data);
+ }
+
+ /* Reset the lock the dynamic loader uses to protect its data. */
+ __rtld_lock_initialize (GL(dl_load_lock));
+
+ reclaim_stacks ();
+
+ /* Run the handlers registered for the child. */
+ __run_fork_handlers (atfork_run_child, multiple_threads);
+ }
+ else
+ {
+ /* Release acquired locks in the multi-threaded case. */
+ if (multiple_threads)
+ {
+ /* Release malloc locks, parent process variant. */
+ call_function_static_weak (__malloc_fork_unlock_parent);
+
+ /* We execute this even if the 'fork' call failed. */
+ _IO_list_unlock ();
+ }
+
+ /* Run the handlers registered for the parent. */
+ __run_fork_handlers (atfork_run_parent, multiple_threads);
+ }
+
+ return pid;
}
+weak_alias (__libc_fork, __fork)
libc_hidden_def (__fork)
-stub_warning (fork)
-
-weak_alias (__fork, fork)
+weak_alias (__libc_fork, fork)
diff --git a/sysdeps/generic/fork.h b/sysdeps/generic/fork.h
new file mode 100644
index 0000000000..be42cf2481
--- /dev/null
+++ b/sysdeps/generic/fork.h
@@ -0,0 +1,32 @@
+/* System specific fork hooks. Generic version.
+ 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
+ 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/>. */
+
+static inline void
+fork_system_setup (void)
+{
+}
+
+static inline void
+fork_system_setup_after_fork (void)
+{
+}
+
+static inline void
+reclaim_stacks (void)
+{
+}
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/_Fork.c
similarity index 98%
rename from sysdeps/mach/hurd/fork.c
rename to sysdeps/mach/hurd/_Fork.c
index 92a51693e0..df4ee05faa 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/_Fork.c
@@ -58,16 +58,13 @@ DEFINE_HOOK (_hurd_fork_parent_hook, (void));
Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */
pid_t
-__fork (void)
+_Fork (void)
{
jmp_buf env;
pid_t pid;
size_t i;
error_t err;
struct hurd_sigstate *volatile ss;
- struct nss_database_data nss_database_data;
-
- __run_fork_handlers (atfork_run_prepare, true);
ss = _hurd_self_sigstate ();
retry:
@@ -108,9 +105,6 @@ retry:
/* Run things that prepare for forking before we create the task. */
RUN_HOOK (_hurd_fork_prepare_hook, ());
- call_function_static_weak (__nss_database_fork_prepare_parent,
- &nss_database_data);
-
/* Lock things that want to be locked before we fork. */
{
void *const *p;
@@ -670,9 +664,6 @@ retry:
_hurd_malloc_fork_child ();
call_function_static_weak (__malloc_fork_unlock_child);
- call_function_static_weak (__nss_database_fork_subprocess,
- &nss_database_data);
-
/* Run things that want to run in the child task to set up. */
RUN_HOOK (_hurd_fork_child_hook, ());
@@ -723,14 +714,6 @@ retry:
/* Got a signal while inside an RPC of the critical section, retry again */
goto retry;
- if (!err)
- {
- __run_fork_handlers (pid == 0 ? atfork_run_child : atfork_run_parent,
- true);
- }
-
return err ? __hurd_fail (err) : pid;
}
-libc_hidden_def (__fork)
-
-weak_alias (__fork, fork)
+libc_hidden_def (_Fork)
diff --git a/sysdeps/nptl/_Fork.c b/sysdeps/nptl/_Fork.c
new file mode 100644
index 0000000000..6eae146b4d
--- /dev/null
+++ b/sysdeps/nptl/_Fork.c
@@ -0,0 +1,52 @@
+/* _Fork implementation. Linux version.
+ 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
+ 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 <arch-fork.h>
+#include <pthreadP.h>
+
+/* Pointer to the fork generation counter in the thread library. */
+extern unsigned long int *__fork_generation_pointer attribute_hidden;
+
+pid_t
+_Fork (void)
+{
+ pid_t pid = arch_fork (&THREAD_SELF->tid);
+ if (pid == 0)
+ {
+ struct pthread *self = THREAD_SELF;
+
+ /* Initialize the robust mutex list setting in the kernel which has
+ been reset during the fork. We do not check for errors because if
+ it fails here, it must have failed at process startup as well and
+ nobody could have used robust mutexes.
+ Before we do that, we have to clear the list of robust mutexes
+ because we do not inherit ownership of mutexes from the parent.
+ We do not have to set self->robust_head.futex_offset since we do
+ inherit the correct value from the parent. We do not need to clear
+ the pending operation because it must have been zero when fork was
+ called. */
+#if __PTHREAD_MUTEX_HAVE_PREV
+ self->robust_prev = &self->robust_head;
+#endif
+ self->robust_head.list = &self->robust_head;
+ INTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head,
+ sizeof (struct robust_list_head));
+ }
+ return pid;
+}
+libc_hidden_def (_Fork)
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
deleted file mode 100644
index 39ab797612..0000000000
--- a/sysdeps/nptl/fork.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/* Copyright (C) 2002-2021 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
-
- 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 <assert.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sysdep.h>
-#include <libio/libioP.h>
-#include <tls.h>
-#include <hp-timing.h>
-#include <ldsodefs.h>
-#include <stdio-lock.h>
-#include <atomic.h>
-#include <pthreadP.h>
-#include <register-atfork.h>
-#include <arch-fork.h>
-#include <futex-internal.h>
-#include <malloc/malloc-internal.h>
-#include <nss/nss_database.h>
-#include <unwind-link.h>
-#include <sys/single_threaded.h>
-#include <list.h>
-
-static void
-fresetlockfiles (void)
-{
- _IO_ITER i;
-
- for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
- if ((_IO_iter_file (i)->_flags & _IO_USER_LOCK) == 0)
- _IO_lock_init (*((_IO_lock_t *) _IO_iter_file(i)->_lock));
-}
-
-/* In case of a fork() call the memory allocation in the child will be
- the same but only one thread is running. All stacks except that of
- the one running thread are not used anymore. We have to recycle
- them. */
-static void
-reclaim_stacks (void)
-{
- struct pthread *self = (struct pthread *) THREAD_SELF;
-
- /* No locking necessary. The caller is the only stack in use. But
- we have to be aware that we might have interrupted a list
- operation. */
-
- if (GL (dl_in_flight_stack) != 0)
- {
- bool add_p = GL (dl_in_flight_stack) & 1;
- list_t *elem = (list_t *) (GL (dl_in_flight_stack) & ~(uintptr_t) 1);
-
- if (add_p)
- {
- /* We always add at the beginning of the list. So in this case we
- only need to check the beginning of these lists to see if the
- pointers at the head of the list are inconsistent. */
- list_t *l = NULL;
-
- if (GL (dl_stack_used).next->prev != &GL (dl_stack_used))
- l = &GL (dl_stack_used);
- else if (GL (dl_stack_cache).next->prev != &GL (dl_stack_cache))
- l = &GL (dl_stack_cache);
-
- if (l != NULL)
- {
- assert (l->next->prev == elem);
- elem->next = l->next;
- elem->prev = l;
- l->next = elem;
- }
- }
- else
- {
- /* We can simply always replay the delete operation. */
- elem->next->prev = elem->prev;
- elem->prev->next = elem->next;
- }
-
- GL (dl_in_flight_stack) = 0;
- }
-
- /* Mark all stacks except the still running one as free. */
- list_t *runp;
- list_for_each (runp, &GL (dl_stack_used))
- {
- struct pthread *curp = list_entry (runp, struct pthread, list);
- if (curp != self)
- {
- /* This marks the stack as free. */
- curp->tid = 0;
-
- /* Account for the size of the stack. */
- GL (dl_stack_cache_actsize) += curp->stackblock_size;
-
- if (curp->specific_used)
- {
- /* Clear the thread-specific data. */
- memset (curp->specific_1stblock, '\0',
- sizeof (curp->specific_1stblock));
-
- curp->specific_used = false;
-
- for (size_t cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
- if (curp->specific[cnt] != NULL)
- {
- memset (curp->specific[cnt], '\0',
- sizeof (curp->specific_1stblock));
-
- /* We have allocated the block which we do not
- free here so re-set the bit. */
- curp->specific_used = true;
- }
- }
- }
- }
-
- /* Add the stack of all running threads to the cache. */
- list_splice (&GL (dl_stack_used), &GL (dl_stack_cache));
-
- /* Remove the entry for the current thread to from the cache list
- and add it to the list of running threads. Which of the two
- lists is decided by the user_stack flag. */
- list_del (&self->list);
-
- /* Re-initialize the lists for all the threads. */
- INIT_LIST_HEAD (&GL (dl_stack_used));
- INIT_LIST_HEAD (&GL (dl_stack_user));
-
- if (__glibc_unlikely (THREAD_GETMEM (self, user_stack)))
- list_add (&self->list, &GL (dl_stack_user));
- else
- list_add (&self->list, &GL (dl_stack_used));
-}
-
-pid_t
-__libc_fork (void)
-{
- pid_t pid;
-
- /* Determine if we are running multiple threads. We skip some fork
- handlers in the single-thread case, to make fork safer to use in
- signal handlers. POSIX requires that fork is async-signal-safe,
- but our current fork implementation is not. */
- bool multiple_threads = __libc_single_threaded == 0;
-
- __run_fork_handlers (atfork_run_prepare, multiple_threads);
-
- struct nss_database_data nss_database_data;
-
- /* If we are not running multiple threads, we do not have to
- preserve lock state. If fork runs from a signal handler, only
- async-signal-safe functions can be used in the child. These data
- structures are only used by unsafe functions, so their state does
- not matter if fork was called from a signal handler. */
- if (multiple_threads)
- {
- call_function_static_weak (__nss_database_fork_prepare_parent,
- &nss_database_data);
-
- _IO_list_lock ();
-
- /* Acquire malloc locks. This needs to come last because fork
- handlers may use malloc, and the libio list lock has an
- indirect malloc dependency as well (via the getdelim
- function). */
- call_function_static_weak (__malloc_fork_lock_parent);
- }
-
- pid = arch_fork (&THREAD_SELF->tid);
-
- if (pid == 0)
- {
- struct pthread *self = THREAD_SELF;
-
- /* See __pthread_once. */
- __fork_generation += __PTHREAD_ONCE_FORK_GEN_INCR;
-
- /* Initialize the robust mutex list setting in the kernel which has
- been reset during the fork. We do not check for errors because if
- it fails here, it must have failed at process startup as well and
- nobody could have used robust mutexes.
- Before we do that, we have to clear the list of robust mutexes
- because we do not inherit ownership of mutexes from the parent.
- We do not have to set self->robust_head.futex_offset since we do
- inherit the correct value from the parent. We do not need to clear
- the pending operation because it must have been zero when fork was
- called. */
-#if __PTHREAD_MUTEX_HAVE_PREV
- self->robust_prev = &self->robust_head;
-#endif
- self->robust_head.list = &self->robust_head;
- INTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head,
- sizeof (struct robust_list_head));
-
- /* Reset the lock state in the multi-threaded case. */
- if (multiple_threads)
- {
- __libc_unwind_link_after_fork ();
-
- /* There is one thread running. */
- __nptl_nthreads = 1;
-
- /* Initialize thread library locks. */
- GL (dl_stack_cache_lock) = LLL_LOCK_INITIALIZER;
- __default_pthread_attr_lock = LLL_LOCK_INITIALIZER;
-
- /* Release malloc locks. */
- call_function_static_weak (__malloc_fork_unlock_child);
-
- /* Reset the file list. These are recursive mutexes. */
- fresetlockfiles ();
-
- /* Reset locks in the I/O code. */
- _IO_list_resetlock ();
-
- call_function_static_weak (__nss_database_fork_subprocess,
- &nss_database_data);
- }
-
- /* Reset the lock the dynamic loader uses to protect its data. */
- __rtld_lock_initialize (GL(dl_load_lock));
-
- reclaim_stacks ();
-
- /* Run the handlers registered for the child. */
- __run_fork_handlers (atfork_run_child, multiple_threads);
- }
- else
- {
- /* Release acquired locks in the multi-threaded case. */
- if (multiple_threads)
- {
- /* Release malloc locks, parent process variant. */
- call_function_static_weak (__malloc_fork_unlock_parent);
-
- /* We execute this even if the 'fork' call failed. */
- _IO_list_unlock ();
- }
-
- /* Run the handlers registered for the parent. */
- __run_fork_handlers (atfork_run_parent, multiple_threads);
- }
-
- return pid;
-}
-weak_alias (__libc_fork, __fork)
-libc_hidden_def (__fork)
-weak_alias (__libc_fork, fork)
diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
new file mode 100644
index 0000000000..3134d7ab94
--- /dev/null
+++ b/sysdeps/nptl/fork.h
@@ -0,0 +1,148 @@
+/* System specific fork hooks. Linux version.
+ 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
+ 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/>. */
+
+#ifndef _FORK_H
+#define _FORK_H
+
+#include <assert.h>
+#include <ldsodefs.h>
+#include <list.h>
+#include <pthreadP.h>
+#include <sysdep.h>
+
+static inline void
+fork_system_setup (void)
+{
+ /* See __pthread_once. */
+ __fork_generation += __PTHREAD_ONCE_FORK_GEN_INCR;
+}
+
+static void
+fork_system_setup_after_fork (void)
+{
+ /* There is one thread running. */
+ __nptl_nthreads = 1;
+
+ /* Initialize thread library locks. */
+ GL (dl_stack_cache_lock) = LLL_LOCK_INITIALIZER;
+ __default_pthread_attr_lock = LLL_LOCK_INITIALIZER;
+}
+
+/* In case of a fork() call the memory allocation in the child will be
+ the same but only one thread is running. All stacks except that of
+ the one running thread are not used anymore. We have to recycle
+ them. */
+static void
+reclaim_stacks (void)
+{
+ struct pthread *self = (struct pthread *) THREAD_SELF;
+
+ /* No locking necessary. The caller is the only stack in use. But
+ we have to be aware that we might have interrupted a list
+ operation. */
+
+ if (GL (dl_in_flight_stack) != 0)
+ {
+ bool add_p = GL (dl_in_flight_stack) & 1;
+ list_t *elem = (list_t *) (GL (dl_in_flight_stack) & ~(uintptr_t) 1);
+
+ if (add_p)
+ {
+ /* We always add at the beginning of the list. So in this case we
+ only need to check the beginning of these lists to see if the
+ pointers at the head of the list are inconsistent. */
+ list_t *l = NULL;
+
+ if (GL (dl_stack_used).next->prev != &GL (dl_stack_used))
+ l = &GL (dl_stack_used);
+ else if (GL (dl_stack_cache).next->prev != &GL (dl_stack_cache))
+ l = &GL (dl_stack_cache);
+
+ if (l != NULL)
+ {
+ assert (l->next->prev == elem);
+ elem->next = l->next;
+ elem->prev = l;
+ l->next = elem;
+ }
+ }
+ else
+ {
+ /* We can simply always replay the delete operation. */
+ elem->next->prev = elem->prev;
+ elem->prev->next = elem->next;
+ }
+
+ GL (dl_in_flight_stack) = 0;
+ }
+
+ /* Mark all stacks except the still running one as free. */
+ list_t *runp;
+ list_for_each (runp, &GL (dl_stack_used))
+ {
+ struct pthread *curp = list_entry (runp, struct pthread, list);
+ if (curp != self)
+ {
+ /* This marks the stack as free. */
+ curp->tid = 0;
+
+ /* Account for the size of the stack. */
+ GL (dl_stack_cache_actsize) += curp->stackblock_size;
+
+ if (curp->specific_used)
+ {
+ /* Clear the thread-specific data. */
+ memset (curp->specific_1stblock, '\0',
+ sizeof (curp->specific_1stblock));
+
+ curp->specific_used = false;
+
+ for (size_t cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
+ if (curp->specific[cnt] != NULL)
+ {
+ memset (curp->specific[cnt], '\0',
+ sizeof (curp->specific_1stblock));
+
+ /* We have allocated the block which we do not
+ free here so re-set the bit. */
+ curp->specific_used = true;
+ }
+ }
+ }
+ }
+
+ /* Add the stack of all running threads to the cache. */
+ list_splice (&GL (dl_stack_used), &GL (dl_stack_cache));
+
+ /* Remove the entry for the current thread to from the cache list
+ and add it to the list of running threads. Which of the two
+ lists is decided by the user_stack flag. */
+ list_del (&self->list);
+
+ /* Re-initialize the lists for all the threads. */
+ INIT_LIST_HEAD (&GL (dl_stack_used));
+ INIT_LIST_HEAD (&GL (dl_stack_user));
+
+ if (__glibc_unlikely (THREAD_GETMEM (self, user_stack)))
+ list_add (&self->list, &GL (dl_stack_user));
+ else
+ list_add (&self->list, &GL (dl_stack_used));
+}
+
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/arch-fork.h b/sysdeps/unix/sysv/linux/arch-fork.h
index 35d9397ff8..b846da08f9 100644
--- a/sysdeps/unix/sysv/linux/arch-fork.h
+++ b/sysdeps/unix/sysv/linux/arch-fork.h
@@ -19,6 +19,9 @@
#ifndef __ARCH_FORK_H
#define __ARCH_FORK_H
+#include <sysdep.h>
+#include <sched.h>
+#include <signal.h>
#include <unistd.h>
/* Call the clone syscall with fork semantic. The CTID address is used
--
2.30.2
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v4 2/4] posix: Do not clobber errno by atfork handlers
2021-06-23 18:43 [PATCH v4 0/4] Add _Fork implementation Adhemerval Zanella
2021-06-23 18:43 ` [PATCH v4 1/4] posix: Consolidate fork implementation Adhemerval Zanella
@ 2021-06-23 18:43 ` Adhemerval Zanella
2021-06-24 8:19 ` Florian Weimer
2021-06-23 18:43 ` [PATCH v4 3/4] Consolidate pthread_atfork Adhemerval Zanella
2021-06-23 18:43 ` [PATCH v4 4/4] posix: Add _Fork [BZ #4737] Adhemerval Zanella
3 siblings, 1 reply; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-23 18:43 UTC (permalink / raw)
To: libc-alpha
Checked on x86_64-linux-gnu.
---
posix/fork.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/posix/fork.c b/posix/fork.c
index 44caf8d166..9340511198 100644
--- a/posix/fork.c
+++ b/posix/fork.c
@@ -103,6 +103,9 @@ __libc_fork (void)
}
else
{
+ /* If _Fork failed, preserve its errno value. */
+ int save_errno = errno;
+
/* Release acquired locks in the multi-threaded case. */
if (multiple_threads)
{
@@ -115,6 +118,8 @@ __libc_fork (void)
/* Run the handlers registered for the parent. */
__run_fork_handlers (atfork_run_parent, multiple_threads);
+
+ __set_errno (save_errno);
}
return pid;
--
2.30.2
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v4 3/4] Consolidate pthread_atfork
2021-06-23 18:43 [PATCH v4 0/4] Add _Fork implementation Adhemerval Zanella
2021-06-23 18:43 ` [PATCH v4 1/4] posix: Consolidate fork implementation Adhemerval Zanella
2021-06-23 18:43 ` [PATCH v4 2/4] posix: Do not clobber errno by atfork handlers Adhemerval Zanella
@ 2021-06-23 18:43 ` Adhemerval Zanella
2021-06-24 8:22 ` Florian Weimer
2021-06-23 18:43 ` [PATCH v4 4/4] posix: Add _Fork [BZ #4737] Adhemerval Zanella
3 siblings, 1 reply; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-23 18:43 UTC (permalink / raw)
To: libc-alpha
The pthread_atfork is similar between Linux and Hurd, only the compat
version bits differs. The generic version is place at sysdeps/pthread
with a common name.
It also fixes an issue with Hurd license, where the static-only object
did not use LGPL.
Checked on x86_64-linux-gnu, i686-linux-gnu, and with a build for
i686-gnu.
---
htl/Makefile | 4 +-
nptl/Makefile | 1 -
sysdeps/htl/old_pt-atfork.c | 26 ------------
sysdeps/htl/pt-atfork.c | 41 -------------------
sysdeps/htl/pthread_atfork_compat.h | 4 ++
sysdeps/nptl/pthread_atfork_compat.h | 4 ++
sysdeps/pthread/Makefile | 4 +-
{nptl => sysdeps/pthread}/pthread_atfork.c | 1 +
.../pthread/pthread_atfork_compat.c | 8 ++--
9 files changed, 18 insertions(+), 75 deletions(-)
delete mode 100644 sysdeps/htl/old_pt-atfork.c
delete mode 100644 sysdeps/htl/pt-atfork.c
create mode 100644 sysdeps/htl/pthread_atfork_compat.h
create mode 100644 sysdeps/nptl/pthread_atfork_compat.h
rename {nptl => sysdeps/pthread}/pthread_atfork.c (98%)
rename nptl/old_pthread_atfork.c => sysdeps/pthread/pthread_atfork_compat.c (84%)
diff --git a/htl/Makefile b/htl/Makefile
index 8c5ad3c5de..cf9d12fc12 100644
--- a/htl/Makefile
+++ b/htl/Makefile
@@ -121,7 +121,6 @@ libpthread-routines := pt-attr pt-attr-destroy pt-attr-getdetachstate \
pt-sigstate-destroy \
pt-sigstate \
\
- old_pt-atfork \
pt-kill \
pt-getcpuclockid \
\
@@ -165,9 +164,8 @@ headers := \
distribute :=
-routines := forward libc_pthread_init alloca_cutoff pt-atfork htlfreeres
+routines := forward libc_pthread_init alloca_cutoff htlfreeres
shared-only-routines = forward
-static-only-routines = pt-atfork
extra-libs := libpthread
extra-libs-others := $(extra-libs)
diff --git a/nptl/Makefile b/nptl/Makefile
index bbaf796771..c64e4af2f6 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -52,7 +52,6 @@ routines = \
nptl_nthreads \
nptl_setxid \
nptlfreeres \
- old_pthread_atfork \
old_pthread_cond_broadcast \
old_pthread_cond_destroy \
old_pthread_cond_init \
diff --git a/sysdeps/htl/old_pt-atfork.c b/sysdeps/htl/old_pt-atfork.c
deleted file mode 100644
index ca38d6ca42..0000000000
--- a/sysdeps/htl/old_pt-atfork.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Register fork handlers. 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/>. */
-
-#include <shlib-compat.h>
-
-#if SHLIB_COMPAT(libpthread, GLIBC_2_12, GLIBC_2_23)
-# define __pthread_atfork __dyn_pthread_atfork
-# include "pt-atfork.c"
-# undef __pthread_atfork
-compat_symbol (libpthread, __dyn_pthread_atfork, pthread_atfork, GLIBC_2_12);
-#endif
diff --git a/sysdeps/htl/pt-atfork.c b/sysdeps/htl/pt-atfork.c
deleted file mode 100644
index 3902f40835..0000000000
--- a/sysdeps/htl/pt-atfork.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Register fork handlers. 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/>. */
-
-#include <pthread.h>
-#include <pt-internal.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. */
-int
-#ifndef __pthread_atfork
-/* Don't mark the compatibility function as hidden. */
-attribute_hidden
-#endif
-__pthread_atfork (void (*prepare) (void),
- void (*parent) (void),
- void (*child) (void))
-{
- return __register_atfork (prepare, parent, child, __dso_handle);
-}
-#ifndef __pthread_atfork
-extern int pthread_atfork (void (*prepare) (void), void (*parent) (void),
- void (*child) (void)) attribute_hidden;
-weak_alias (__pthread_atfork, pthread_atfork)
-#endif
diff --git a/sysdeps/htl/pthread_atfork_compat.h b/sysdeps/htl/pthread_atfork_compat.h
new file mode 100644
index 0000000000..08afccbb3c
--- /dev/null
+++ b/sysdeps/htl/pthread_atfork_compat.h
@@ -0,0 +1,4 @@
+/* The compat version for the dynamic pthread_atfork provided by libpthread,
+ before supported __dso_handle was added. */
+#define PTHREAD_ATFORK_COMPAT_INTRODUCED GLIBC_2_12
+#define PTHREAD_ATFORK_COMPAT_OBSOLETED GLIBC_2_23
diff --git a/sysdeps/nptl/pthread_atfork_compat.h b/sysdeps/nptl/pthread_atfork_compat.h
new file mode 100644
index 0000000000..38edcbefe5
--- /dev/null
+++ b/sysdeps/nptl/pthread_atfork_compat.h
@@ -0,0 +1,4 @@
+/* The compat versions for the dynamic pthread_atfork provided by libpthread,
+ before supported __dso_handle was added. */
+#define PTHREAD_ATFORK_COMPAT_INTRODUCED GLIBC_2_0
+#define PTHREAD_ATFORK_COMPAT_OBSOLETED GLIBC_2_3
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 9e6ed3c6f7..fedb785d38 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -29,7 +29,7 @@ endif
ifneq (,$(filter $(subdir),htl nptl))
headers += threads.h
-routines += thrd_current thrd_equal thrd_sleep thrd_yield
+routines += thrd_current thrd_equal thrd_sleep thrd_yield pthread_atfork
$(libpthread-routines-var) += \
call_once \
@@ -45,6 +45,7 @@ $(libpthread-routines-var) += \
mtx_timedlock \
mtx_trylock \
mtx_unlock \
+ pthread_atfork_compat \
thrd_create \
thrd_detach \
thrd_exit \
@@ -134,6 +135,7 @@ tests-time64 := \
tst-sem5-time64 \
tst-thrd-sleep-time64 \
+static-only-routines = pthread_atfork
# Files which must not be linked with libpthread.
tests-nolibpthread += tst-unload
diff --git a/nptl/pthread_atfork.c b/sysdeps/pthread/pthread_atfork.c
similarity index 98%
rename from nptl/pthread_atfork.c
rename to sysdeps/pthread/pthread_atfork.c
index 6398688dab..7646fe7efc 100644
--- a/nptl/pthread_atfork.c
+++ b/sysdeps/pthread/pthread_atfork.c
@@ -36,6 +36,7 @@
#include "pthreadP.h"
#include <register-atfork.h>
#include <dso_handle.h>
+#include <register-atfork.h>
/* Hide the symbol so that no definition but the one locally in the
diff --git a/nptl/old_pthread_atfork.c b/sysdeps/pthread/pthread_atfork_compat.c
similarity index 84%
rename from nptl/old_pthread_atfork.c
rename to sysdeps/pthread/pthread_atfork_compat.c
index 675227c559..4533f765d1 100644
--- a/nptl/old_pthread_atfork.c
+++ b/sysdeps/pthread/pthread_atfork_compat.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2021 Free Software Foundation, Inc.
+/* Compat pthread_atfork implementation.
+ Copyright (C) 2002-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -16,11 +16,13 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <pthread_atfork_compat.h>
#include <shlib-compat.h>
#if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_3)
# define __pthread_atfork __dyn_pthread_atfork
# include "pthread_atfork.c"
# undef __pthread_atfork
-compat_symbol (libpthread, __dyn_pthread_atfork, pthread_atfork, GLIBC_2_0);
+compat_symbol (libpthread, __dyn_pthread_atfork, pthread_atfork,
+ PTHREAD_ATFORK_COMPAT_INTRODUCED);
#endif
--
2.30.2
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v4 4/4] posix: Add _Fork [BZ #4737]
2021-06-23 18:43 [PATCH v4 0/4] Add _Fork implementation Adhemerval Zanella
` (2 preceding siblings ...)
2021-06-23 18:43 ` [PATCH v4 3/4] Consolidate pthread_atfork Adhemerval Zanella
@ 2021-06-23 18:43 ` Adhemerval Zanella
2021-06-24 8:47 ` Florian Weimer
3 siblings, 1 reply; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-23 18:43 UTC (permalink / raw)
To: libc-alpha
Austin Group issue 62 [1] dropped the async-signal-safe requirement
for fork and provided a async-signal-safe _Fork replacement that
does not run the atfork handlers. It will be included in the next
POSIX standard.
It allow to close a long standing issue to make fork AS-safe (BZ#4737).
As indicated on the bug, besides the internal lock for the atfork
handlers itself; there is no guarantee that the handlers itself will
not introduce more AS-safe issues.
The idea is synchronize fork with the required internal locks to allow
children in multithread processes to use mostly of standard function
(even though POSIX states only AS-safe function should be used). On
signal handles, _Fork should be used intead and only AS-safe functions
should be used.
For testing, the new tst-_Fork only check basic usage. I also added
a new tst-mallocfork3 which uses the same strategy to check for
deadlock of tst-mallocfork2 but using threads instead of subprocesses
(and it does deadlock if it replaces _Fork with fork).
[1] https://austingroupbugs.net/view.php?id=62
---
NEWS | 8 +
malloc/Makefile | 3 +
malloc/tst-mallocfork3.c | 213 +++++++++++++++++
manual/process.texi | 39 ++--
posix/Makefile | 3 +-
posix/Versions | 1 +
posix/fork.c | 5 +-
posix/tst-_Fork.c | 218 ++++++++++++++++++
posix/unistd.h | 7 +
sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arc/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 +
sysdeps/unix/sysv/linux/csky/libc.abilist | 1 +
sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 1 +
sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 +
.../sysv/linux/m68k/coldfire/libc.abilist | 1 +
.../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 +
.../sysv/linux/microblaze/be/libc.abilist | 1 +
.../sysv/linux/microblaze/le/libc.abilist | 1 +
.../sysv/linux/mips/mips32/fpu/libc.abilist | 1 +
.../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n32/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 +
.../linux/powerpc/powerpc32/fpu/libc.abilist | 1 +
.../powerpc/powerpc32/nofpu/libc.abilist | 1 +
.../linux/powerpc/powerpc64/be/libc.abilist | 1 +
.../linux/powerpc/powerpc64/le/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv32/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv64/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-32/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 +
.../sysv/linux/sparc/sparc32/libc.abilist | 1 +
.../sysv/linux/sparc/sparc64/libc.abilist | 1 +
.../unix/sysv/linux/x86_64/64/libc.abilist | 1 +
.../unix/sysv/linux/x86_64/x32/libc.abilist | 1 +
41 files changed, 512 insertions(+), 17 deletions(-)
create mode 100644 malloc/tst-mallocfork3.c
create mode 100644 posix/tst-_Fork.c
diff --git a/NEWS b/NEWS
index 48d77d706f..fbff6d91c9 100644
--- a/NEWS
+++ b/NEWS
@@ -47,6 +47,14 @@ Major new features:
with names ending with .conf to logically classify the converter modules in
that directory.
+* The function _Fork has been added as an async-signal-safe fork replacement
+ since Austin Group issue 62 droped the async-signal-safe requirement for
+ fork (and it will be included in the future POSIX standard). The new _Fork
+ function does not run any atfork function neither resets any internal state
+ or lock (such as the malloc one), and only sets up a minimal state required
+ to call async-signal-safe functions (such as raise or execve). This function
+ is currently a GNU extension.
+
Deprecated and removed features, and other changes affecting compatibility:
* The function pthread_mutex_consistent_np has been deprecated; programs
diff --git a/malloc/Makefile b/malloc/Makefile
index 3162301fba..9bc2e50a9a 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -31,6 +31,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
tst-malloc-backtrace tst-malloc-thread-exit \
tst-malloc-thread-fail tst-malloc-fork-deadlock \
tst-mallocfork2 \
+ tst-mallocfork3 \
tst-interpose-nothread \
tst-interpose-thread \
tst-alloc_buffer \
@@ -113,6 +114,8 @@ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
$(objpfx)tst-malloc-backtrace: $(shared-thread-library)
$(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
$(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
+$(objpfx)tst-mallocfork3: $(shared-thread-library)
+$(objpfx)tst-mallocfork3-mcheck: $(shared-thread-library)
$(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library)
$(objpfx)tst-malloc-stats-cancellation: $(shared-thread-library)
$(objpfx)tst-malloc-backtrace-malloc-check: $(shared-thread-library)
diff --git a/malloc/tst-mallocfork3.c b/malloc/tst-mallocfork3.c
new file mode 100644
index 0000000000..4ac99eea43
--- /dev/null
+++ b/malloc/tst-mallocfork3.c
@@ -0,0 +1,213 @@
+/* Test case for async-signal-safe _Fork (with respect to malloc).
+ 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
+ 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; see the file COPYING.LIB. If
+ not, see <https://www.gnu.org/licenses/>. */
+
+/* This test is similar to tst-mallocfork2.c, but specifically stress
+ the async-signal-safeness of _Fork on multithread environment. */
+
+#include <array_length.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <sys/wait.h>
+
+/* How many malloc objects to keep arond. */
+enum { malloc_objects = 1009 };
+
+/* The maximum size of an object. */
+enum { malloc_maximum_size = 70000 };
+
+/* How many iterations the test performs before exiting. */
+enum { iterations = 10000 };
+
+/* Barrier for synchronization with the threads sending SIGUSR1
+ signals, to make it more likely that the signals arrive during a
+ fork/free/malloc call. */
+static pthread_barrier_t barrier;
+
+/* Set to 1 if SIGUSR1 is received. Used to detect a signal during
+ fork/free/malloc. */
+static volatile sig_atomic_t sigusr1_received;
+
+/* Periodically set to 1, to indicate that the thread is making
+ progress. Checked by liveness_signal_handler. */
+static volatile sig_atomic_t progress_indicator = 1;
+
+/* Set to 1 if an error occurs in the signal handler. */
+static volatile sig_atomic_t error_indicator = 0;
+
+static void
+sigusr1_handler (int signo)
+{
+ sigusr1_received = 1;
+
+ /* Perform a fork with a trivial subprocess. */
+ pid_t pid = _Fork ();
+ if (pid == -1)
+ {
+ write_message ("error: fork\n");
+ error_indicator = 1;
+ return;
+ }
+ if (pid == 0)
+ _exit (0);
+ int status;
+ int ret = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (ret < 0)
+ {
+ write_message ("error: waitpid\n");
+ error_indicator = 1;
+ return;
+ }
+ if (status != 0)
+ {
+ write_message ("error: unexpected exit status from subprocess\n");
+ error_indicator = 1;
+ return;
+ }
+}
+
+static void
+liveness_signal_handler (int signo)
+{
+ if (progress_indicator)
+ progress_indicator = 0;
+ else
+ write_message ("warning: thread seems to be stuck\n");
+}
+
+struct signal_send_args
+{
+ pthread_t target;
+ int signo;
+ bool sleep;
+};
+#define SIGNAL_SEND_GET_ARG(arg, field) \
+ (((struct signal_send_args *)(arg))->field)
+
+/* Send SIGNO to the parent thread. If SLEEP, wait a second between
+ signals, otherwise use barriers to delay sending signals. */
+static void *
+signal_sender (void *args)
+{
+ int signo = SIGNAL_SEND_GET_ARG (args, signo);
+ bool sleep = SIGNAL_SEND_GET_ARG (args, sleep);
+
+ pthread_t target = SIGNAL_SEND_GET_ARG (args, target);
+ while (true)
+ {
+ if (!sleep)
+ xpthread_barrier_wait (&barrier);
+ xpthread_kill (target, signo);
+ if (sleep)
+ usleep (1 * 1000 * 1000);
+ else
+ xpthread_barrier_wait (&barrier);
+ }
+ return NULL;
+}
+
+static pthread_t sigusr1_sender[5];
+static pthread_t sigusr2_sender;
+
+static int
+do_test (void)
+{
+ xsignal (SIGUSR1, sigusr1_handler);
+ xsignal (SIGUSR2, liveness_signal_handler);
+
+ pthread_t self = pthread_self ();
+
+ struct signal_send_args sigusr2_args = { self, SIGUSR2, true };
+ sigusr2_sender = xpthread_create (NULL, signal_sender, &sigusr2_args);
+
+ /* Send SIGUSR1 signals from several threads. Hopefully, one
+ signal will hit one of the ciritical functions. Use a barrier to
+ avoid sending signals while not running fork/free/malloc. */
+ struct signal_send_args sigusr1_args = { self, SIGUSR1, false };
+ xpthread_barrier_init (&barrier, NULL,
+ array_length (sigusr1_sender) + 1);
+ for (size_t i = 0; i < array_length (sigusr1_sender); ++i)
+ sigusr1_sender[i] = xpthread_create (NULL, signal_sender, &sigusr1_args);
+
+ void *objects[malloc_objects] = {};
+ unsigned int fork_signals = 0;
+ unsigned int free_signals = 0;
+ unsigned int malloc_signals = 0;
+ unsigned int seed = 1;
+ for (int i = 0; i < iterations; ++i)
+ {
+ progress_indicator = 1;
+ int slot = rand_r (&seed) % malloc_objects;
+ size_t size = rand_r (&seed) % malloc_maximum_size;
+
+ /* Occasionally do a fork first, to catch deadlocks there as
+ well (see bug 24161). */
+ bool do_fork = (rand_r (&seed) % 7) == 0;
+
+ xpthread_barrier_wait (&barrier);
+ if (do_fork)
+ {
+ sigusr1_received = 0;
+ pid_t pid = _Fork ();
+ TEST_VERIFY_EXIT (pid != -1);
+ if (sigusr1_received)
+ ++fork_signals;
+ if (pid == 0)
+ _exit (0);
+ int status;
+ int ret = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (ret < 0)
+ FAIL_EXIT1 ("waitpid: %m");
+ TEST_COMPARE (status, 0);
+ }
+ sigusr1_received = 0;
+ free (objects[slot]);
+ if (sigusr1_received)
+ ++free_signals;
+ sigusr1_received = 0;
+ objects[slot] = malloc (size);
+ if (sigusr1_received)
+ ++malloc_signals;
+ xpthread_barrier_wait (&barrier);
+
+ if (objects[slot] == NULL || error_indicator != 0)
+ {
+ printf ("error: malloc: %m\n");
+ return 1;
+ }
+ }
+
+ /* Clean up allocations. */
+ for (int slot = 0; slot < malloc_objects; ++slot)
+ free (objects[slot]);
+
+ printf ("info: signals received during fork: %u\n", fork_signals);
+ printf ("info: signals received during free: %u\n", free_signals);
+ printf ("info: signals received during malloc: %u\n", malloc_signals);
+
+ return 0;
+}
+
+#define TIMEOUT 100
+#include <support/test-driver.c>
diff --git a/manual/process.texi b/manual/process.texi
index 134d5c6143..d362081f85 100644
--- a/manual/process.texi
+++ b/manual/process.texi
@@ -137,8 +137,8 @@ creating a process and making it run another program.
@cindex parent process
@cindex subprocess
A new processes is created when one of the functions
-@code{posix_spawn}, @code{fork}, or @code{vfork} is called. (The
-@code{system} and @code{popen} also create new processes internally.)
+@code{posix_spawn}, @code{fork}, @code{_Fork} or @code{vfork} is called.
+(The @code{system} and @code{popen} also create new processes internally.)
Due to the name of the @code{fork} function, the act of creating a new
process is sometimes called @dfn{forking} a process. Each new process
(the @dfn{child process} or @dfn{subprocess}) is allocated a process
@@ -154,9 +154,10 @@ limited information about why the child terminated---for example, its
exit status code.
A newly forked child process continues to execute the same program as
-its parent process, at the point where the @code{fork} call returns.
-You can use the return value from @code{fork} to tell whether the program
-is running in the parent process or the child.
+its parent process, at the point where the @code{fork} or @code{_Fork}
+call returns. You can use the return value from @code{fork} or
+@code{_Fork} to tell whether the program is running in the parent process
+or the child.
@cindex process image
Having several processes run the same program is only occasionally
@@ -248,16 +249,13 @@ It is declared in the header file @file{unistd.h}.
@deftypefun pid_t fork (void)
@standards{POSIX.1, unistd.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@ascuplugin{}}@acunsafe{@aculock{}}}
-@c The nptl/.../linux implementation safely collects fork_handlers into
-@c an alloca()ed linked list and increments ref counters; it uses atomic
-@c ops and retries, avoiding locking altogether. It then takes the
-@c IO_list lock, resets the thread-local pid, and runs fork. The parent
-@c restores the thread-local pid, releases the lock, and runs parent
-@c handlers, decrementing the ref count and signaling futex wait if
-@c requested by unregister_atfork. The child bumps the fork generation,
-@c sets the thread-local pid, resets cpu clocks, initializes the robust
-@c mutex list, the stream locks, the IO_list lock, the dynamic loader
-@c lock, runs the child handlers, reseting ref counters to 1, and
+@c The posix/fork.c implementation iterates over the fork_handlers
+@c using a lock. It then takes the IO_list lock, resets the thread-local
+@c pid, and runs fork. The parent releases the lock, and runs parent
+@c handlers, and unlocks the internal lock. The child bumps the fork
+@c generation, sets the thread-local pid, resets cpu clocks, initializes
+@c the robust mutex list, the stream locks, the IO_list lock, the dynamic
+@c loader lock, runs the child handlers, reseting ref counters to 1, and
@c initializes the fork lock. These are all safe, unless atfork
@c handlers themselves are unsafe.
The @code{fork} function creates a new process.
@@ -321,6 +319,17 @@ process is cleared. (The child process inherits its mask of blocked
signals and signal actions from the parent process.)
@end itemize
+@deftypefun pid_t _Fork (void)
+@standards{GNU, unistd.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+The @code{_Fork} function is similar to @code{fork} but does not issue
+any atfork callback registered with @code{pthread_atfork} neither reset
+any internal state or locks (such as the malloc one) and only setup a
+minimal state required to call async-signal-safe functions (such as raise
+or execve).
+
+It is an async-signal-safe replacement of @code{fork}.
+@end deftypefun
@deftypefun pid_t vfork (void)
@standards{BSD, unistd.h}
diff --git a/posix/Makefile b/posix/Makefile
index 3bd7d605df..e91ea25ba1 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -130,7 +130,7 @@ test-srcs := globtest
tests += wordexp-test tst-exec tst-spawn tst-spawn2 tst-spawn3
endif
ifeq (yesyes,$(build-shared)$(have-thread-library))
-tests += tst-getopt-cancel
+tests += tst-getopt-cancel tst-_Fork
endif
tests-static = tst-exec-static tst-spawn-static
tests += $(tests-static)
@@ -299,6 +299,7 @@ $(objpfx)ptestcases.h: PTESTS PTESTS2C.sed
$(objpfx)runptests.o: $(objpfx)ptestcases.h
$(objpfx)tst-getopt-cancel: $(shared-thread-library)
+$(objpfx)tst-_Fork: $(shared-thread-library)
test-xfail-annexc = yes
$(objpfx)annexc.out: $(objpfx)annexc
diff --git a/posix/Versions b/posix/Versions
index 5983144d01..ee1f412185 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -152,6 +152,7 @@ libc {
GLIBC_2.30 {
}
GLIBC_2.34 {
+ _Fork;
execveat;
}
GLIBC_PRIVATE {
diff --git a/posix/fork.c b/posix/fork.c
index 9340511198..eab71d496c 100644
--- a/posix/fork.c
+++ b/posix/fork.c
@@ -41,7 +41,10 @@ __libc_fork (void)
{
/* Determine if we are running multiple threads. We skip some fork
handlers in the single-thread case, to make fork safer to use in
- signal handlers. */
+ signal handlers. Although POSIX has dropped async-signal-safe
+ requirement for fork (Austin Group tracker issue #62) this is
+ best effort to make is async-signal-safe at least for single-thread
+ case. */
bool multiple_threads = __libc_single_threaded == 0;
__run_fork_handlers (atfork_run_prepare, multiple_threads);
diff --git a/posix/tst-_Fork.c b/posix/tst-_Fork.c
new file mode 100644
index 0000000000..f14da12d5a
--- /dev/null
+++ b/posix/tst-_Fork.c
@@ -0,0 +1,218 @@
+/* Basic tests for _Fork.
+ 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
+ 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 <array_length.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <support/check.h>
+#include <support/xsignal.h>
+#include <support/temp_file.h>
+#include <support/xunistd.h>
+#include <support/xthread.h>
+
+/* For single-thread, _Fork behaves like fork. */
+static int
+singlethread_test (void)
+{
+ const char testdata1[] = "abcdefghijklmnopqrtuvwxz";
+ enum { testdatalen1 = array_length (testdata1) };
+ const char testdata2[] = "01234567890";
+ enum { testdatalen2 = array_length (testdata2) };
+
+ pid_t ppid = getpid ();
+
+ int tempfd = create_temp_file ("tst-_Fork", NULL);
+
+ /* Check if the opened file is shared between process by read and write
+ some data on parent and child processes. */
+ xwrite (tempfd, testdata1, testdatalen1);
+ off_t off = xlseek (tempfd, 0, SEEK_CUR);
+ TEST_COMPARE (off, testdatalen1);
+
+ pid_t pid = _Fork ();
+ TEST_VERIFY_EXIT (pid != -1);
+ if (pid == 0)
+ {
+ TEST_VERIFY_EXIT (getpid () != ppid);
+ TEST_COMPARE (getppid(), ppid);
+
+ TEST_COMPARE (xlseek (tempfd, 0, SEEK_CUR), testdatalen1);
+
+ xlseek (tempfd, 0, SEEK_SET);
+ char buf[testdatalen1];
+ TEST_COMPARE (read (tempfd, buf, sizeof (buf)), testdatalen1);
+ TEST_COMPARE_BLOB (buf, testdatalen1, testdata1, testdatalen1);
+
+ xlseek (tempfd, 0, SEEK_SET);
+ xwrite (tempfd, testdata2, testdatalen2);
+
+ xclose (tempfd);
+
+ _exit (EXIT_SUCCESS);
+ }
+
+ int status;
+ xwaitpid (pid, &status, 0);
+ TEST_VERIFY (WIFEXITED (status));
+ TEST_COMPARE (WEXITSTATUS (status), EXIT_SUCCESS);
+
+ TEST_COMPARE (xlseek (tempfd, 0, SEEK_CUR), testdatalen2);
+
+ xlseek (tempfd, 0, SEEK_SET);
+ char buf[testdatalen2];
+ TEST_COMPARE (read (tempfd, buf, sizeof (buf)), testdatalen2);
+
+ TEST_COMPARE_BLOB (buf, testdatalen2, testdata2, testdatalen2);
+
+ return 0;
+}
+
+
+static volatile sig_atomic_t sigusr1_handler_ran;
+static pid_t sig_pid = -1;
+#define SIG_PID_EXIT_CODE 20
+
+static void
+sigusr1_handler (int signum)
+{
+ TEST_COMPARE (signum, SIGUSR1);
+
+ pid_t ppid = getpid ();
+
+ sig_pid = _Fork ();
+ TEST_VERIFY_EXIT (sig_pid != -1);
+ if (sig_pid == 0)
+ {
+ TEST_VERIFY_EXIT (getpid () != ppid);
+ TEST_COMPARE (getppid(), ppid);
+
+ _exit (SIG_PID_EXIT_CODE);
+ }
+
+ sigusr1_handler_ran = 1;
+}
+
+/* _Fork is async-signal-safe, so check if it can successfully issue
+ a new process in a signal handler. */
+static int
+singlethread_signal_test (void)
+{
+ xsignal (SIGUSR1, &sigusr1_handler);
+ /* Assume synchronous signal handling. */
+ xraise (SIGUSR1);
+ TEST_COMPARE (sigusr1_handler_ran, 1);
+
+ int status;
+ xwaitpid (sig_pid, &status, 0);
+ TEST_VERIFY (WIFEXITED (status));
+ TEST_COMPARE (WEXITSTATUS (status), SIG_PID_EXIT_CODE);
+
+ xsignal (SIGUSR1, SIG_DFL);
+
+ return 0;
+}
+
+
+static bool atfork_prepare_var;
+static bool atfork_parent_var;
+static bool atfork_child_var;
+
+static void
+atfork_prepare (void)
+{
+ atfork_prepare_var = true;
+}
+
+static void
+atfork_parent (void)
+{
+ atfork_parent_var = true;
+}
+
+static void
+atfork_child (void)
+{
+ atfork_child_var = true;
+}
+
+/* Different than fork, _Fork does not execute any pthread_atfork
+ handlers. */
+static int
+singlethread_atfork_test (void)
+{
+ pthread_atfork (atfork_prepare, atfork_parent, atfork_child);
+ singlethread_test ();
+ TEST_COMPARE (atfork_prepare_var, false);
+ TEST_COMPARE (atfork_parent_var, false);
+ TEST_COMPARE (atfork_child_var, false);
+
+ return 0;
+}
+
+
+static void *
+mt_atfork_test (void *args)
+{
+ singlethread_atfork_test ();
+
+ return NULL;
+}
+
+static int
+multithread_atfork_test (void)
+{
+ pthread_t thr = xpthread_create (NULL, mt_atfork_test, NULL);
+ xpthread_join (thr);
+
+ return 0;
+}
+
+
+static void *
+mt_signal_test (void *args)
+{
+ singlethread_signal_test ();
+
+ return NULL;
+}
+
+static int
+multithread_signal_test (void)
+{
+ pthread_t thr = xpthread_create (NULL, mt_signal_test, NULL);
+ xpthread_join (thr);
+
+ return 0;
+}
+
+
+static int
+do_test (void)
+{
+ singlethread_atfork_test ();
+ singlethread_signal_test ();
+
+ multithread_atfork_test ();
+ multithread_signal_test ();
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/unistd.h b/posix/unistd.h
index d9d8929f71..fa06c890ba 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -781,6 +781,13 @@ extern __pid_t fork (void) __THROWNL;
extern __pid_t vfork (void) __THROW;
#endif /* Use misc or XPG < 7. */
+#ifdef __USE_GNU
+/* This is similar to fork, however it does not run the atfork handlers
+ neither reinitialize any internal locks in multithread case.
+ Different than fork, _Fork is async-signal-safe. */
+extern __pid_t _Fork (void) __THROWNL;
+#endif
+
/* Return the pathname of the terminal FD is open on, or NULL on errors.
The returned storage is good only until the next call to this function. */
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 42e240e284..c569dcefc4 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2336,6 +2336,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index fad54555dc..0f10c40462 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2429,6 +2429,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 907716ec39..b55c896cc1 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2095,6 +2095,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 50f987a429..532ff27b93 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -190,6 +190,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index bf9038af84..989e205231 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -187,6 +187,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index afb91f6f43..a5079d1aa9 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2279,6 +2279,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 125f8a269a..b6508fa4a7 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2233,6 +2233,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 517753bdd1..dfad0e3f6a 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2416,6 +2416,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 23d0928360..ffb9db6c03 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2268,6 +2268,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index dd5fb50b18..1073dafda6 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -191,6 +191,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index cb1d553361..dd858c91e1 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2360,6 +2360,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6a20a6fdf2..8c9be533e3 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2330,6 +2330,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 4c21cbb64d..2711ae61a8 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2327,6 +2327,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index f83ba2f780..7ee7188232 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2325,6 +2325,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 347bbddb94..c6df617aca 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2323,6 +2323,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 26b7ab529b..72706758f5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2331,6 +2331,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index e667b0e553..5cbf324cc1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2325,6 +2325,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 89a1cc7da6..621b5ae2ab 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2369,6 +2369,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index f364c5219e..020544effc 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2387,6 +2387,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index f5bcc78afe..6be20d1955 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2420,6 +2420,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 6032716053..8edcee4bc3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2233,6 +2233,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 8c5494e1dc..bca35138a8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2531,6 +2531,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index d7db279c1e..5825b4eea7 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2097,6 +2097,7 @@ GLIBC_2.33 wprintf F
GLIBC_2.33 write F
GLIBC_2.33 writev F
GLIBC_2.33 wscanf F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index ef03dc0f9e..7072253c70 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2297,6 +2297,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 9118cb68ec..eb0945c141 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2385,6 +2385,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 66c01bd7e7..2ae14ed146 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2270,6 +2270,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index c40eb412c2..27ac687fd7 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2240,6 +2240,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 1412d33835..3f557d227f 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2237,6 +2237,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 7b55d34753..e28c9bff54 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2378,6 +2378,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index cfd5f38864..157a5dec47 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2290,6 +2290,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 17be05f14f..8c9f1ad865 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2247,6 +2247,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index a9db18906b..aeb98e3d5c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2350,6 +2350,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
--
2.30.2
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 1/4] posix: Consolidate fork implementation
2021-06-23 18:43 ` [PATCH v4 1/4] posix: Consolidate fork implementation Adhemerval Zanella
@ 2021-06-24 8:15 ` Florian Weimer
2021-06-24 11:32 ` Adhemerval Zanella
0 siblings, 1 reply; 17+ messages in thread
From: Florian Weimer @ 2021-06-24 8:15 UTC (permalink / raw)
To: Adhemerval Zanella via Libc-alpha
* Adhemerval Zanella via Libc-alpha:
> diff --git a/include/unistd.h b/include/unistd.h
> index 34872d8b41..d554d44edb 100644
> --- a/include/unistd.h
> +++ b/include/unistd.h
> @@ -140,6 +140,10 @@ extern __pid_t __vfork (void);
> libc_hidden_proto (__vfork)
> extern int __ttyname_r (int __fd, char *__buf, size_t __buflen);
> libc_hidden_proto (__ttyname_r)
> +extern int __ttyname_r (int __fd, char *__buf, size_t __buflen)
> + attribute_hidden;
Duplicate declaration of __ttyname_r. Merge error?
Rest looks okay to me.
Thanks,
Florian
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 2/4] posix: Do not clobber errno by atfork handlers
2021-06-23 18:43 ` [PATCH v4 2/4] posix: Do not clobber errno by atfork handlers Adhemerval Zanella
@ 2021-06-24 8:19 ` Florian Weimer
2021-06-24 11:05 ` Adhemerval Zanella
0 siblings, 1 reply; 17+ messages in thread
From: Florian Weimer @ 2021-06-24 8:19 UTC (permalink / raw)
To: Adhemerval Zanella via Libc-alpha
* Adhemerval Zanella via Libc-alpha:
> Checked on x86_64-linux-gnu.
> ---
> posix/fork.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/posix/fork.c b/posix/fork.c
> index 44caf8d166..9340511198 100644
> --- a/posix/fork.c
> +++ b/posix/fork.c
> @@ -103,6 +103,9 @@ __libc_fork (void)
> }
> else
> {
> + /* If _Fork failed, preserve its errno value. */
> + int save_errno = errno;
> +
> /* Release acquired locks in the multi-threaded case. */
> if (multiple_threads)
> {
> @@ -115,6 +118,8 @@ __libc_fork (void)
>
> /* Run the handlers registered for the parent. */
> __run_fork_handlers (atfork_run_parent, multiple_threads);
> +
> + __set_errno (save_errno);
I think you should restrict the __set_errno call to pid < 0, so that
errno is not 0 after a different value has been observed by the fork
handlers.
Thanks,
Florian
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 3/4] Consolidate pthread_atfork
2021-06-23 18:43 ` [PATCH v4 3/4] Consolidate pthread_atfork Adhemerval Zanella
@ 2021-06-24 8:22 ` Florian Weimer
2021-06-24 11:32 ` Adhemerval Zanella
0 siblings, 1 reply; 17+ messages in thread
From: Florian Weimer @ 2021-06-24 8:22 UTC (permalink / raw)
To: Adhemerval Zanella via Libc-alpha
* Adhemerval Zanella via Libc-alpha:
> The pthread_atfork is similar between Linux and Hurd, only the compat
> version bits differs. The generic version is place at sysdeps/pthread
> with a common name.
>
> It also fixes an issue with Hurd license, where the static-only object
> did not use LGPL.
The static-only object should definitely use the exception that is
currently in nptl/pthread_atfork.c. I think your change does that, but
so the commit message should say “LGPL + exception”.
Rest looks okay.
Thanks,
Florian
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 4/4] posix: Add _Fork [BZ #4737]
2021-06-23 18:43 ` [PATCH v4 4/4] posix: Add _Fork [BZ #4737] Adhemerval Zanella
@ 2021-06-24 8:47 ` Florian Weimer
2021-06-24 13:34 ` Adhemerval Zanella
0 siblings, 1 reply; 17+ messages in thread
From: Florian Weimer @ 2021-06-24 8:47 UTC (permalink / raw)
To: Adhemerval Zanella via Libc-alpha
* Adhemerval Zanella via Libc-alpha:
> +@deftypefun pid_t _Fork (void)
> +@standards{GNU, unistd.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +The @code{_Fork} function is similar to @code{fork} but does not issue
> +any atfork callback registered with @code{pthread_atfork} neither reset
> +any internal state or locks (such as the malloc one) and only setup a
> +minimal state required to call async-signal-safe functions (such as raise
> +or execve).
Maybe:
+The @code{_Fork} function is similar to @code{fork}, but it does not invoke
+any callbacks registered with @code{pthread_atfork}, nor does it reset
+any internal state or locks (such as the @code{malloc} locks). In the
+new subprocess, only async-signal-safe functions may be called, such as
+@code{dup2} or @code{execve}.
+
+The @code{_Fork} function is an async-signal-safe replacement of @code{fork}.
+It is a GNU extension.
> diff --git a/posix/tst-_Fork.c b/posix/tst-_Fork.c
> new file mode 100644
> index 0000000000..f14da12d5a
> --- /dev/null
> +++ b/posix/tst-_Fork.c
> +/* _Fork is async-signal-safe, so check if it can successfully issue
> + a new process in a signal handler. */
> +static int
> +singlethread_signal_test (void)
> +{
> + xsignal (SIGUSR1, &sigusr1_handler);
> + /* Assume synchronous signal handling. */
> + xraise (SIGUSR1);
> + TEST_COMPARE (sigusr1_handler_ran, 1);
This test tests using a synchronous signal, so it doesn't add much
value in my opinion.
> +/* Different than fork, _Fork does not execute any pthread_atfork
> + handlers. */
> +static int
> +singlethread_atfork_test (void)
> +{
> + pthread_atfork (atfork_prepare, atfork_parent, atfork_child);
> + singlethread_test ();
> + TEST_COMPARE (atfork_prepare_var, false);
> + TEST_COMPARE (atfork_parent_var, false);
> + TEST_COMPARE (atfork_child_var, false);
Use TEST_VERIFY (!atfork_child_var) etc.?
> diff --git a/posix/unistd.h b/posix/unistd.h
> index d9d8929f71..fa06c890ba 100644
> --- a/posix/unistd.h
> +++ b/posix/unistd.h
> @@ -781,6 +781,13 @@ extern __pid_t fork (void) __THROWNL;
> extern __pid_t vfork (void) __THROW;
> #endif /* Use misc or XPG < 7. */
>
> +#ifdef __USE_GNU
> +/* This is similar to fork, however it does not run the atfork handlers
> + neither reinitialize any internal locks in multithread case.
> + Different than fork, _Fork is async-signal-safe. */
> +extern __pid_t _Fork (void) __THROWNL;
> +#endif
Should this be _THROW (no callbacks)? Do we have to specify the
returns_twice attribute?
Thanks,
Florian
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 2/4] posix: Do not clobber errno by atfork handlers
2021-06-24 8:19 ` Florian Weimer
@ 2021-06-24 11:05 ` Adhemerval Zanella
2021-06-24 11:19 ` Florian Weimer
0 siblings, 1 reply; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-24 11:05 UTC (permalink / raw)
To: Florian Weimer, Adhemerval Zanella via Libc-alpha
On 24/06/2021 05:19, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
>
>> Checked on x86_64-linux-gnu.
>> ---
>> posix/fork.c | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/posix/fork.c b/posix/fork.c
>> index 44caf8d166..9340511198 100644
>> --- a/posix/fork.c
>> +++ b/posix/fork.c
>> @@ -103,6 +103,9 @@ __libc_fork (void)
>> }
>> else
>> {
>> + /* If _Fork failed, preserve its errno value. */
>> + int save_errno = errno;
>> +
>> /* Release acquired locks in the multi-threaded case. */
>> if (multiple_threads)
>> {
>> @@ -115,6 +118,8 @@ __libc_fork (void)
>>
>> /* Run the handlers registered for the parent. */
>> __run_fork_handlers (atfork_run_parent, multiple_threads);
>> +
>> + __set_errno (save_errno);
>
> I think you should restrict the __set_errno call to pid < 0, so that
> errno is not 0 after a different value has been observed by the fork
> handlers.
OK, I can change it back. From the previous review iteration I understood
you were ok with making it unconditional [1].
[1] https://sourceware.org/pipermail/libc-alpha/2021-March/123729.html
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 2/4] posix: Do not clobber errno by atfork handlers
2021-06-24 11:05 ` Adhemerval Zanella
@ 2021-06-24 11:19 ` Florian Weimer
2021-06-24 11:32 ` Adhemerval Zanella
0 siblings, 1 reply; 17+ messages in thread
From: Florian Weimer @ 2021-06-24 11:19 UTC (permalink / raw)
To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha
* Adhemerval Zanella:
> On 24/06/2021 05:19, Florian Weimer wrote:
>> * Adhemerval Zanella via Libc-alpha:
>>
>>> Checked on x86_64-linux-gnu.
>>> ---
>>> posix/fork.c | 5 +++++
>>> 1 file changed, 5 insertions(+)
>>>
>>> diff --git a/posix/fork.c b/posix/fork.c
>>> index 44caf8d166..9340511198 100644
>>> --- a/posix/fork.c
>>> +++ b/posix/fork.c
>>> @@ -103,6 +103,9 @@ __libc_fork (void)
>>> }
>>> else
>>> {
>>> + /* If _Fork failed, preserve its errno value. */
>>> + int save_errno = errno;
>>> +
>>> /* Release acquired locks in the multi-threaded case. */
>>> if (multiple_threads)
>>> {
>>> @@ -115,6 +118,8 @@ __libc_fork (void)
>>>
>>> /* Run the handlers registered for the parent. */
>>> __run_fork_handlers (atfork_run_parent, multiple_threads);
>>> +
>>> + __set_errno (save_errno);
>>
>> I think you should restrict the __set_errno call to pid < 0, so that
>> errno is not 0 after a different value has been observed by the fork
>> handlers.
>
> OK, I can change it back. From the previous review iteration I understood
> you were ok with making it unconditional [1].
>
> [1] https://sourceware.org/pipermail/libc-alpha/2021-March/123729.html
Sorry, I meant making the saving unconditional, not the restoring.
Florian
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 2/4] posix: Do not clobber errno by atfork handlers
2021-06-24 11:19 ` Florian Weimer
@ 2021-06-24 11:32 ` Adhemerval Zanella
0 siblings, 0 replies; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-24 11:32 UTC (permalink / raw)
To: Florian Weimer; +Cc: Adhemerval Zanella via Libc-alpha
On 24/06/2021 08:19, Florian Weimer wrote:
> * Adhemerval Zanella:
>
>> On 24/06/2021 05:19, Florian Weimer wrote:
>>> * Adhemerval Zanella via Libc-alpha:
>>>
>>>> Checked on x86_64-linux-gnu.
>>>> ---
>>>> posix/fork.c | 5 +++++
>>>> 1 file changed, 5 insertions(+)
>>>>
>>>> diff --git a/posix/fork.c b/posix/fork.c
>>>> index 44caf8d166..9340511198 100644
>>>> --- a/posix/fork.c
>>>> +++ b/posix/fork.c
>>>> @@ -103,6 +103,9 @@ __libc_fork (void)
>>>> }
>>>> else
>>>> {
>>>> + /* If _Fork failed, preserve its errno value. */
>>>> + int save_errno = errno;
>>>> +
>>>> /* Release acquired locks in the multi-threaded case. */
>>>> if (multiple_threads)
>>>> {
>>>> @@ -115,6 +118,8 @@ __libc_fork (void)
>>>>
>>>> /* Run the handlers registered for the parent. */
>>>> __run_fork_handlers (atfork_run_parent, multiple_threads);
>>>> +
>>>> + __set_errno (save_errno);
>>>
>>> I think you should restrict the __set_errno call to pid < 0, so that
>>> errno is not 0 after a different value has been observed by the fork
>>> handlers.
>>
>> OK, I can change it back. From the previous review iteration I understood
>> you were ok with making it unconditional [1].
>>
>> [1] https://sourceware.org/pipermail/libc-alpha/2021-March/123729.html
>
> Sorry, I meant making the saving unconditional, not the restoring.
Ok, I will fix it.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 3/4] Consolidate pthread_atfork
2021-06-24 8:22 ` Florian Weimer
@ 2021-06-24 11:32 ` Adhemerval Zanella
0 siblings, 0 replies; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-24 11:32 UTC (permalink / raw)
To: Florian Weimer, Adhemerval Zanella via Libc-alpha
On 24/06/2021 05:22, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
>
>> The pthread_atfork is similar between Linux and Hurd, only the compat
>> version bits differs. The generic version is place at sysdeps/pthread
>> with a common name.
>>
>> It also fixes an issue with Hurd license, where the static-only object
>> did not use LGPL.
>
> The static-only object should definitely use the exception that is
> currently in nptl/pthread_atfork.c. I think your change does that, but
> so the commit message should say “LGPL + exception”.
>
> Rest looks okay.
Ok, I will change it.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 1/4] posix: Consolidate fork implementation
2021-06-24 8:15 ` Florian Weimer
@ 2021-06-24 11:32 ` Adhemerval Zanella
0 siblings, 0 replies; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-24 11:32 UTC (permalink / raw)
To: Florian Weimer, Adhemerval Zanella via Libc-alpha
On 24/06/2021 05:15, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
>
>> diff --git a/include/unistd.h b/include/unistd.h
>> index 34872d8b41..d554d44edb 100644
>> --- a/include/unistd.h
>> +++ b/include/unistd.h
>> @@ -140,6 +140,10 @@ extern __pid_t __vfork (void);
>> libc_hidden_proto (__vfork)
>> extern int __ttyname_r (int __fd, char *__buf, size_t __buflen);
>> libc_hidden_proto (__ttyname_r)
>> +extern int __ttyname_r (int __fd, char *__buf, size_t __buflen)
>> + attribute_hidden;
>
> Duplicate declaration of __ttyname_r. Merge error?
>
> Rest looks okay to me.
Yes, I will fix it.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 4/4] posix: Add _Fork [BZ #4737]
2021-06-24 8:47 ` Florian Weimer
@ 2021-06-24 13:34 ` Adhemerval Zanella
2021-06-28 8:52 ` Florian Weimer
0 siblings, 1 reply; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-24 13:34 UTC (permalink / raw)
To: Florian Weimer, Adhemerval Zanella via Libc-alpha
On 24/06/2021 05:47, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
>
>> +@deftypefun pid_t _Fork (void)
>> +@standards{GNU, unistd.h}
>> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
>> +The @code{_Fork} function is similar to @code{fork} but does not issue
>> +any atfork callback registered with @code{pthread_atfork} neither reset
>> +any internal state or locks (such as the malloc one) and only setup a
>> +minimal state required to call async-signal-safe functions (such as raise
>> +or execve).
>
> Maybe:
>
> +The @code{_Fork} function is similar to @code{fork}, but it does not invoke
> +any callbacks registered with @code{pthread_atfork}, nor does it reset
> +any internal state or locks (such as the @code{malloc} locks). In the
> +new subprocess, only async-signal-safe functions may be called, such as
> +@code{dup2} or @code{execve}.
> +
> +The @code{_Fork} function is an async-signal-safe replacement of @code{fork}.
> +It is a GNU extension.
Alright, it does sounds better. I changed to your suggestion.
>
>> diff --git a/posix/tst-_Fork.c b/posix/tst-_Fork.c
>> new file mode 100644
>> index 0000000000..f14da12d5a
>> --- /dev/null
>> +++ b/posix/tst-_Fork.c
>
>> +/* _Fork is async-signal-safe, so check if it can successfully issue
>> + a new process in a signal handler. */
>> +static int
>> +singlethread_signal_test (void)
>> +{
>> + xsignal (SIGUSR1, &sigusr1_handler);
>> + /* Assume synchronous signal handling. */
>> + xraise (SIGUSR1);
>> + TEST_COMPARE (sigusr1_handler_ran, 1);
>
> This test tests using a synchronous signal, so it doesn't add much
> value in my opinion.
Indeed it does not add much, I removed it along with the
multithread_signal_test.
>
>> +/* Different than fork, _Fork does not execute any pthread_atfork
>> + handlers. */
>> +static int
>> +singlethread_atfork_test (void)
>> +{
>> + pthread_atfork (atfork_prepare, atfork_parent, atfork_child);
>> + singlethread_test ();
>> + TEST_COMPARE (atfork_prepare_var, false);
>> + TEST_COMPARE (atfork_parent_var, false);
>> + TEST_COMPARE (atfork_child_var, false);
>
> Use TEST_VERIFY (!atfork_child_var) etc.?
Ack.
>
>> diff --git a/posix/unistd.h b/posix/unistd.h
>> index d9d8929f71..fa06c890ba 100644
>> --- a/posix/unistd.h
>> +++ b/posix/unistd.h
>> @@ -781,6 +781,13 @@ extern __pid_t fork (void) __THROWNL;
>> extern __pid_t vfork (void) __THROW;
>> #endif /* Use misc or XPG < 7. */
>>
>> +#ifdef __USE_GNU
>> +/* This is similar to fork, however it does not run the atfork handlers
>> + neither reinitialize any internal locks in multithread case.
>> + Different than fork, _Fork is async-signal-safe. */
>> +extern __pid_t _Fork (void) __THROWNL;
>> +#endif
>
> Should this be _THROW (no callbacks)? Do we have to specify the
> returns_twice attribute?
I think _THROW does make sense in this case, I changed it.
For returns_twice we have __attribute_returns_twice__, but I think we might
want to add it on multiple symbols (not only on _Fork). So I haven't it added
for now.
Below it is an updated patch based on your comments, is this one ok to
commit?
---
[PATCH v5] posix: Add _Fork [BZ #4737]
Austin Group issue 62 [1] dropped the async-signal-safe requirement
for fork and provided a async-signal-safe _Fork replacement that
does not run the atfork handlers. It will be included in the next
POSIX standard.
It allow to close a long standing issue to make fork AS-safe (BZ#4737).
As indicated on the bug, besides the internal lock for the atfork
handlers itself; there is no guarantee that the handlers itself will
not introduce more AS-safe issues.
The idea is synchronize fork with the required internal locks to allow
children in multithread processes to use mostly of standard function
(even though POSIX states only AS-safe function should be used). On
signal handles, _Fork should be used intead and only AS-safe functions
should be used.
For testing, the new tst-_Fork only check basic usage. I also added
a new tst-mallocfork3 which uses the same strategy to check for
deadlock of tst-mallocfork2 but using threads instead of subprocesses
(and it does deadlock if it replaces _Fork with fork).
[1] https://austingroupbugs.net/view.php?id=62
---
NEWS | 8 +
malloc/Makefile | 3 +
malloc/tst-mallocfork3.c | 213 ++++++++++++++++++
manual/process.texi | 41 ++--
posix/Makefile | 3 +-
posix/Versions | 1 +
posix/fork.c | 5 +-
posix/tst-_Fork.c | 154 +++++++++++++
posix/unistd.h | 7 +
sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arc/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 +
sysdeps/unix/sysv/linux/csky/libc.abilist | 1 +
sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 1 +
sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 +
.../sysv/linux/m68k/coldfire/libc.abilist | 1 +
.../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 +
.../sysv/linux/microblaze/be/libc.abilist | 1 +
.../sysv/linux/microblaze/le/libc.abilist | 1 +
.../sysv/linux/mips/mips32/fpu/libc.abilist | 1 +
.../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n32/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 +
.../linux/powerpc/powerpc32/fpu/libc.abilist | 1 +
.../powerpc/powerpc32/nofpu/libc.abilist | 1 +
.../linux/powerpc/powerpc64/be/libc.abilist | 1 +
.../linux/powerpc/powerpc64/le/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv32/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv64/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-32/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 +
.../sysv/linux/sparc/sparc32/libc.abilist | 1 +
.../sysv/linux/sparc/sparc64/libc.abilist | 1 +
.../unix/sysv/linux/x86_64/64/libc.abilist | 1 +
.../unix/sysv/linux/x86_64/x32/libc.abilist | 1 +
41 files changed, 450 insertions(+), 17 deletions(-)
create mode 100644 malloc/tst-mallocfork3.c
create mode 100644 posix/tst-_Fork.c
diff --git a/NEWS b/NEWS
index 48d77d706f..fbff6d91c9 100644
--- a/NEWS
+++ b/NEWS
@@ -47,6 +47,14 @@ Major new features:
with names ending with .conf to logically classify the converter modules in
that directory.
+* The function _Fork has been added as an async-signal-safe fork replacement
+ since Austin Group issue 62 droped the async-signal-safe requirement for
+ fork (and it will be included in the future POSIX standard). The new _Fork
+ function does not run any atfork function neither resets any internal state
+ or lock (such as the malloc one), and only sets up a minimal state required
+ to call async-signal-safe functions (such as raise or execve). This function
+ is currently a GNU extension.
+
Deprecated and removed features, and other changes affecting compatibility:
* The function pthread_mutex_consistent_np has been deprecated; programs
diff --git a/malloc/Makefile b/malloc/Makefile
index 3162301fba..9bc2e50a9a 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -31,6 +31,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
tst-malloc-backtrace tst-malloc-thread-exit \
tst-malloc-thread-fail tst-malloc-fork-deadlock \
tst-mallocfork2 \
+ tst-mallocfork3 \
tst-interpose-nothread \
tst-interpose-thread \
tst-alloc_buffer \
@@ -113,6 +114,8 @@ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
$(objpfx)tst-malloc-backtrace: $(shared-thread-library)
$(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
$(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
+$(objpfx)tst-mallocfork3: $(shared-thread-library)
+$(objpfx)tst-mallocfork3-mcheck: $(shared-thread-library)
$(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library)
$(objpfx)tst-malloc-stats-cancellation: $(shared-thread-library)
$(objpfx)tst-malloc-backtrace-malloc-check: $(shared-thread-library)
diff --git a/malloc/tst-mallocfork3.c b/malloc/tst-mallocfork3.c
new file mode 100644
index 0000000000..4ac99eea43
--- /dev/null
+++ b/malloc/tst-mallocfork3.c
@@ -0,0 +1,213 @@
+/* Test case for async-signal-safe _Fork (with respect to malloc).
+ 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
+ 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; see the file COPYING.LIB. If
+ not, see <https://www.gnu.org/licenses/>. */
+
+/* This test is similar to tst-mallocfork2.c, but specifically stress
+ the async-signal-safeness of _Fork on multithread environment. */
+
+#include <array_length.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <sys/wait.h>
+
+/* How many malloc objects to keep arond. */
+enum { malloc_objects = 1009 };
+
+/* The maximum size of an object. */
+enum { malloc_maximum_size = 70000 };
+
+/* How many iterations the test performs before exiting. */
+enum { iterations = 10000 };
+
+/* Barrier for synchronization with the threads sending SIGUSR1
+ signals, to make it more likely that the signals arrive during a
+ fork/free/malloc call. */
+static pthread_barrier_t barrier;
+
+/* Set to 1 if SIGUSR1 is received. Used to detect a signal during
+ fork/free/malloc. */
+static volatile sig_atomic_t sigusr1_received;
+
+/* Periodically set to 1, to indicate that the thread is making
+ progress. Checked by liveness_signal_handler. */
+static volatile sig_atomic_t progress_indicator = 1;
+
+/* Set to 1 if an error occurs in the signal handler. */
+static volatile sig_atomic_t error_indicator = 0;
+
+static void
+sigusr1_handler (int signo)
+{
+ sigusr1_received = 1;
+
+ /* Perform a fork with a trivial subprocess. */
+ pid_t pid = _Fork ();
+ if (pid == -1)
+ {
+ write_message ("error: fork\n");
+ error_indicator = 1;
+ return;
+ }
+ if (pid == 0)
+ _exit (0);
+ int status;
+ int ret = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (ret < 0)
+ {
+ write_message ("error: waitpid\n");
+ error_indicator = 1;
+ return;
+ }
+ if (status != 0)
+ {
+ write_message ("error: unexpected exit status from subprocess\n");
+ error_indicator = 1;
+ return;
+ }
+}
+
+static void
+liveness_signal_handler (int signo)
+{
+ if (progress_indicator)
+ progress_indicator = 0;
+ else
+ write_message ("warning: thread seems to be stuck\n");
+}
+
+struct signal_send_args
+{
+ pthread_t target;
+ int signo;
+ bool sleep;
+};
+#define SIGNAL_SEND_GET_ARG(arg, field) \
+ (((struct signal_send_args *)(arg))->field)
+
+/* Send SIGNO to the parent thread. If SLEEP, wait a second between
+ signals, otherwise use barriers to delay sending signals. */
+static void *
+signal_sender (void *args)
+{
+ int signo = SIGNAL_SEND_GET_ARG (args, signo);
+ bool sleep = SIGNAL_SEND_GET_ARG (args, sleep);
+
+ pthread_t target = SIGNAL_SEND_GET_ARG (args, target);
+ while (true)
+ {
+ if (!sleep)
+ xpthread_barrier_wait (&barrier);
+ xpthread_kill (target, signo);
+ if (sleep)
+ usleep (1 * 1000 * 1000);
+ else
+ xpthread_barrier_wait (&barrier);
+ }
+ return NULL;
+}
+
+static pthread_t sigusr1_sender[5];
+static pthread_t sigusr2_sender;
+
+static int
+do_test (void)
+{
+ xsignal (SIGUSR1, sigusr1_handler);
+ xsignal (SIGUSR2, liveness_signal_handler);
+
+ pthread_t self = pthread_self ();
+
+ struct signal_send_args sigusr2_args = { self, SIGUSR2, true };
+ sigusr2_sender = xpthread_create (NULL, signal_sender, &sigusr2_args);
+
+ /* Send SIGUSR1 signals from several threads. Hopefully, one
+ signal will hit one of the ciritical functions. Use a barrier to
+ avoid sending signals while not running fork/free/malloc. */
+ struct signal_send_args sigusr1_args = { self, SIGUSR1, false };
+ xpthread_barrier_init (&barrier, NULL,
+ array_length (sigusr1_sender) + 1);
+ for (size_t i = 0; i < array_length (sigusr1_sender); ++i)
+ sigusr1_sender[i] = xpthread_create (NULL, signal_sender, &sigusr1_args);
+
+ void *objects[malloc_objects] = {};
+ unsigned int fork_signals = 0;
+ unsigned int free_signals = 0;
+ unsigned int malloc_signals = 0;
+ unsigned int seed = 1;
+ for (int i = 0; i < iterations; ++i)
+ {
+ progress_indicator = 1;
+ int slot = rand_r (&seed) % malloc_objects;
+ size_t size = rand_r (&seed) % malloc_maximum_size;
+
+ /* Occasionally do a fork first, to catch deadlocks there as
+ well (see bug 24161). */
+ bool do_fork = (rand_r (&seed) % 7) == 0;
+
+ xpthread_barrier_wait (&barrier);
+ if (do_fork)
+ {
+ sigusr1_received = 0;
+ pid_t pid = _Fork ();
+ TEST_VERIFY_EXIT (pid != -1);
+ if (sigusr1_received)
+ ++fork_signals;
+ if (pid == 0)
+ _exit (0);
+ int status;
+ int ret = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (ret < 0)
+ FAIL_EXIT1 ("waitpid: %m");
+ TEST_COMPARE (status, 0);
+ }
+ sigusr1_received = 0;
+ free (objects[slot]);
+ if (sigusr1_received)
+ ++free_signals;
+ sigusr1_received = 0;
+ objects[slot] = malloc (size);
+ if (sigusr1_received)
+ ++malloc_signals;
+ xpthread_barrier_wait (&barrier);
+
+ if (objects[slot] == NULL || error_indicator != 0)
+ {
+ printf ("error: malloc: %m\n");
+ return 1;
+ }
+ }
+
+ /* Clean up allocations. */
+ for (int slot = 0; slot < malloc_objects; ++slot)
+ free (objects[slot]);
+
+ printf ("info: signals received during fork: %u\n", fork_signals);
+ printf ("info: signals received during free: %u\n", free_signals);
+ printf ("info: signals received during malloc: %u\n", malloc_signals);
+
+ return 0;
+}
+
+#define TIMEOUT 100
+#include <support/test-driver.c>
diff --git a/manual/process.texi b/manual/process.texi
index 134d5c6143..28c9531f42 100644
--- a/manual/process.texi
+++ b/manual/process.texi
@@ -137,8 +137,8 @@ creating a process and making it run another program.
@cindex parent process
@cindex subprocess
A new processes is created when one of the functions
-@code{posix_spawn}, @code{fork}, or @code{vfork} is called. (The
-@code{system} and @code{popen} also create new processes internally.)
+@code{posix_spawn}, @code{fork}, @code{_Fork} or @code{vfork} is called.
+(The @code{system} and @code{popen} also create new processes internally.)
Due to the name of the @code{fork} function, the act of creating a new
process is sometimes called @dfn{forking} a process. Each new process
(the @dfn{child process} or @dfn{subprocess}) is allocated a process
@@ -154,9 +154,10 @@ limited information about why the child terminated---for example, its
exit status code.
A newly forked child process continues to execute the same program as
-its parent process, at the point where the @code{fork} call returns.
-You can use the return value from @code{fork} to tell whether the program
-is running in the parent process or the child.
+its parent process, at the point where the @code{fork} or @code{_Fork}
+call returns. You can use the return value from @code{fork} or
+@code{_Fork} to tell whether the program is running in the parent process
+or the child.
@cindex process image
Having several processes run the same program is only occasionally
@@ -248,16 +249,13 @@ It is declared in the header file @file{unistd.h}.
@deftypefun pid_t fork (void)
@standards{POSIX.1, unistd.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@ascuplugin{}}@acunsafe{@aculock{}}}
-@c The nptl/.../linux implementation safely collects fork_handlers into
-@c an alloca()ed linked list and increments ref counters; it uses atomic
-@c ops and retries, avoiding locking altogether. It then takes the
-@c IO_list lock, resets the thread-local pid, and runs fork. The parent
-@c restores the thread-local pid, releases the lock, and runs parent
-@c handlers, decrementing the ref count and signaling futex wait if
-@c requested by unregister_atfork. The child bumps the fork generation,
-@c sets the thread-local pid, resets cpu clocks, initializes the robust
-@c mutex list, the stream locks, the IO_list lock, the dynamic loader
-@c lock, runs the child handlers, reseting ref counters to 1, and
+@c The posix/fork.c implementation iterates over the fork_handlers
+@c using a lock. It then takes the IO_list lock, resets the thread-local
+@c pid, and runs fork. The parent releases the lock, and runs parent
+@c handlers, and unlocks the internal lock. The child bumps the fork
+@c generation, sets the thread-local pid, resets cpu clocks, initializes
+@c the robust mutex list, the stream locks, the IO_list lock, the dynamic
+@c loader lock, runs the child handlers, reseting ref counters to 1, and
@c initializes the fork lock. These are all safe, unless atfork
@c handlers themselves are unsafe.
The @code{fork} function creates a new process.
@@ -321,6 +319,19 @@ process is cleared. (The child process inherits its mask of blocked
signals and signal actions from the parent process.)
@end itemize
+@deftypefun pid_t _Fork (void)
+@standards{GNU, unistd.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+The @code{_Fork} function is similar to @code{fork}, but it does not invoke
+any callbacks registered with @code{pthread_atfork}, nor does it reset
+any internal state or locks (such as the @code{malloc} locks). In the
+new subprocess, only async-signal-safe functions may be called, such as
+@code{dup2} or @code{execve}.
+
+The @code{_Fork} function is an async-signal-safe replacement of @code{fork}.
+It is a GNU extension.
+
+@end deftypefun
@deftypefun pid_t vfork (void)
@standards{BSD, unistd.h}
diff --git a/posix/Makefile b/posix/Makefile
index 3bd7d605df..e91ea25ba1 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -130,7 +130,7 @@ test-srcs := globtest
tests += wordexp-test tst-exec tst-spawn tst-spawn2 tst-spawn3
endif
ifeq (yesyes,$(build-shared)$(have-thread-library))
-tests += tst-getopt-cancel
+tests += tst-getopt-cancel tst-_Fork
endif
tests-static = tst-exec-static tst-spawn-static
tests += $(tests-static)
@@ -299,6 +299,7 @@ $(objpfx)ptestcases.h: PTESTS PTESTS2C.sed
$(objpfx)runptests.o: $(objpfx)ptestcases.h
$(objpfx)tst-getopt-cancel: $(shared-thread-library)
+$(objpfx)tst-_Fork: $(shared-thread-library)
test-xfail-annexc = yes
$(objpfx)annexc.out: $(objpfx)annexc
diff --git a/posix/Versions b/posix/Versions
index 5983144d01..ee1f412185 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -152,6 +152,7 @@ libc {
GLIBC_2.30 {
}
GLIBC_2.34 {
+ _Fork;
execveat;
}
GLIBC_PRIVATE {
diff --git a/posix/fork.c b/posix/fork.c
index 940d6a0955..c471f7b15f 100644
--- a/posix/fork.c
+++ b/posix/fork.c
@@ -41,7 +41,10 @@ __libc_fork (void)
{
/* Determine if we are running multiple threads. We skip some fork
handlers in the single-thread case, to make fork safer to use in
- signal handlers. */
+ signal handlers. Although POSIX has dropped async-signal-safe
+ requirement for fork (Austin Group tracker issue #62) this is
+ best effort to make is async-signal-safe at least for single-thread
+ case. */
bool multiple_threads = __libc_single_threaded == 0;
__run_fork_handlers (atfork_run_prepare, multiple_threads);
diff --git a/posix/tst-_Fork.c b/posix/tst-_Fork.c
new file mode 100644
index 0000000000..43a65c0fea
--- /dev/null
+++ b/posix/tst-_Fork.c
@@ -0,0 +1,154 @@
+/* Basic tests for _Fork.
+ 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
+ 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 <array_length.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <support/check.h>
+#include <support/xsignal.h>
+#include <support/temp_file.h>
+#include <support/xunistd.h>
+#include <support/xthread.h>
+
+/* For single-thread, _Fork behaves like fork. */
+static int
+singlethread_test (void)
+{
+ const char testdata1[] = "abcdefghijklmnopqrtuvwxz";
+ enum { testdatalen1 = array_length (testdata1) };
+ const char testdata2[] = "01234567890";
+ enum { testdatalen2 = array_length (testdata2) };
+
+ pid_t ppid = getpid ();
+
+ int tempfd = create_temp_file ("tst-_Fork", NULL);
+
+ /* Check if the opened file is shared between process by read and write
+ some data on parent and child processes. */
+ xwrite (tempfd, testdata1, testdatalen1);
+ off_t off = xlseek (tempfd, 0, SEEK_CUR);
+ TEST_COMPARE (off, testdatalen1);
+
+ pid_t pid = _Fork ();
+ TEST_VERIFY_EXIT (pid != -1);
+ if (pid == 0)
+ {
+ TEST_VERIFY_EXIT (getpid () != ppid);
+ TEST_COMPARE (getppid(), ppid);
+
+ TEST_COMPARE (xlseek (tempfd, 0, SEEK_CUR), testdatalen1);
+
+ xlseek (tempfd, 0, SEEK_SET);
+ char buf[testdatalen1];
+ TEST_COMPARE (read (tempfd, buf, sizeof (buf)), testdatalen1);
+ TEST_COMPARE_BLOB (buf, testdatalen1, testdata1, testdatalen1);
+
+ xlseek (tempfd, 0, SEEK_SET);
+ xwrite (tempfd, testdata2, testdatalen2);
+
+ xclose (tempfd);
+
+ _exit (EXIT_SUCCESS);
+ }
+
+ int status;
+ xwaitpid (pid, &status, 0);
+ TEST_VERIFY (WIFEXITED (status));
+ TEST_COMPARE (WEXITSTATUS (status), EXIT_SUCCESS);
+
+ TEST_COMPARE (xlseek (tempfd, 0, SEEK_CUR), testdatalen2);
+
+ xlseek (tempfd, 0, SEEK_SET);
+ char buf[testdatalen2];
+ TEST_COMPARE (read (tempfd, buf, sizeof (buf)), testdatalen2);
+
+ TEST_COMPARE_BLOB (buf, testdatalen2, testdata2, testdatalen2);
+
+ return 0;
+}
+
+
+static volatile sig_atomic_t sigusr1_handler_ran;
+#define SIG_PID_EXIT_CODE 20
+
+static bool atfork_prepare_var;
+static bool atfork_parent_var;
+static bool atfork_child_var;
+
+static void
+atfork_prepare (void)
+{
+ atfork_prepare_var = true;
+}
+
+static void
+atfork_parent (void)
+{
+ atfork_parent_var = true;
+}
+
+static void
+atfork_child (void)
+{
+ atfork_child_var = true;
+}
+
+/* Different than fork, _Fork does not execute any pthread_atfork
+ handlers. */
+static int
+singlethread_atfork_test (void)
+{
+ pthread_atfork (atfork_prepare, atfork_parent, atfork_child);
+ singlethread_test ();
+ TEST_VERIFY (!atfork_prepare_var);
+ TEST_VERIFY (!atfork_parent_var);
+ TEST_VERIFY (!atfork_child_var);
+
+ return 0;
+}
+
+static void *
+mt_atfork_test (void *args)
+{
+ singlethread_atfork_test ();
+
+ return NULL;
+}
+
+static int
+multithread_atfork_test (void)
+{
+ pthread_t thr = xpthread_create (NULL, mt_atfork_test, NULL);
+ xpthread_join (thr);
+
+ return 0;
+}
+
+
+static int
+do_test (void)
+{
+ singlethread_atfork_test ();
+ multithread_atfork_test ();
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/unistd.h b/posix/unistd.h
index d9d8929f71..217c6c5363 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -781,6 +781,13 @@ extern __pid_t fork (void) __THROWNL;
extern __pid_t vfork (void) __THROW;
#endif /* Use misc or XPG < 7. */
+#ifdef __USE_GNU
+/* This is similar to fork, however it does not run the atfork handlers
+ neither reinitialize any internal locks in multithread case.
+ Different than fork, _Fork is async-signal-safe. */
+extern __pid_t _Fork (void) __THROW;
+#endif
+
/* Return the pathname of the terminal FD is open on, or NULL on errors.
The returned storage is good only until the next call to this function. */
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 42e240e284..c569dcefc4 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2336,6 +2336,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index fad54555dc..0f10c40462 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2429,6 +2429,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 907716ec39..b55c896cc1 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2095,6 +2095,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 50f987a429..532ff27b93 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -190,6 +190,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index bf9038af84..989e205231 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -187,6 +187,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index afb91f6f43..a5079d1aa9 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2279,6 +2279,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 125f8a269a..b6508fa4a7 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2233,6 +2233,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 517753bdd1..dfad0e3f6a 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2416,6 +2416,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 23d0928360..ffb9db6c03 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2268,6 +2268,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index dd5fb50b18..1073dafda6 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -191,6 +191,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index cb1d553361..dd858c91e1 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2360,6 +2360,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6a20a6fdf2..8c9be533e3 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2330,6 +2330,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 4c21cbb64d..2711ae61a8 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2327,6 +2327,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index f83ba2f780..7ee7188232 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2325,6 +2325,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 347bbddb94..c6df617aca 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2323,6 +2323,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 26b7ab529b..72706758f5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2331,6 +2331,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index e667b0e553..5cbf324cc1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2325,6 +2325,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 89a1cc7da6..621b5ae2ab 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2369,6 +2369,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index f364c5219e..020544effc 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2387,6 +2387,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index f5bcc78afe..6be20d1955 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2420,6 +2420,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 6032716053..8edcee4bc3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2233,6 +2233,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 8c5494e1dc..bca35138a8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2531,6 +2531,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index d7db279c1e..5825b4eea7 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2097,6 +2097,7 @@ GLIBC_2.33 wprintf F
GLIBC_2.33 write F
GLIBC_2.33 writev F
GLIBC_2.33 wscanf F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index ef03dc0f9e..7072253c70 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2297,6 +2297,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 9118cb68ec..eb0945c141 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2385,6 +2385,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 66c01bd7e7..2ae14ed146 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2270,6 +2270,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index c40eb412c2..27ac687fd7 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2240,6 +2240,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 1412d33835..3f557d227f 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2237,6 +2237,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 7b55d34753..e28c9bff54 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2378,6 +2378,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 ___adjtimex64 F
GLIBC_2.34 __adjtime64 F
GLIBC_2.34 __clock_adjtime64 F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index cfd5f38864..157a5dec47 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2290,6 +2290,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
GLIBC_2.34 __pthread_key_create F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 17be05f14f..8c9f1ad865 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2247,6 +2247,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index a9db18906b..aeb98e3d5c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2350,6 +2350,7 @@ GLIBC_2.33 mknod F
GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
+GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __pthread_cleanup_routine F
--
2.30.2
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 4/4] posix: Add _Fork [BZ #4737]
2021-06-24 13:34 ` Adhemerval Zanella
@ 2021-06-28 8:52 ` Florian Weimer
2021-06-28 18:10 ` Adhemerval Zanella
0 siblings, 1 reply; 17+ messages in thread
From: Florian Weimer @ 2021-06-28 8:52 UTC (permalink / raw)
To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha
* Adhemerval Zanella:
> For returns_twice we have __attribute_returns_twice__, but I think we might
> want to add it on multiple symbols (not only on _Fork). So I haven't it added
> for now.
I was wondering if gcc knows about these functions. It does actually
for fork, but it uses that only for gcov as far as I can see.
> Below it is an updated patch based on your comments, is this one ok to
> commit?
This patch looks reasonable to me.
Thanks,
Florian
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 4/4] posix: Add _Fork [BZ #4737]
2021-06-28 8:52 ` Florian Weimer
@ 2021-06-28 18:10 ` Adhemerval Zanella
0 siblings, 0 replies; 17+ messages in thread
From: Adhemerval Zanella @ 2021-06-28 18:10 UTC (permalink / raw)
To: Florian Weimer; +Cc: Adhemerval Zanella via Libc-alpha
On 28/06/2021 05:52, Florian Weimer wrote:
> * Adhemerval Zanella:
>
>> For returns_twice we have __attribute_returns_twice__, but I think we might
>> want to add it on multiple symbols (not only on _Fork). So I haven't it added
>> for now.
>
> I was wondering if gcc knows about these functions. It does actually
> for fork, but it uses that only for gcov as far as I can see.
Good question. In any case, I think we would be good to add the
__attribute_returns_twice__ regardless of compiler natively supports the
symbol semantic.
>
>> Below it is an updated patch based on your comments, is this one ok to
>> commit?
>
> This patch looks reasonable to me.
Thanks, I will commit it shortly.
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2021-06-28 18:10 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-23 18:43 [PATCH v4 0/4] Add _Fork implementation Adhemerval Zanella
2021-06-23 18:43 ` [PATCH v4 1/4] posix: Consolidate fork implementation Adhemerval Zanella
2021-06-24 8:15 ` Florian Weimer
2021-06-24 11:32 ` Adhemerval Zanella
2021-06-23 18:43 ` [PATCH v4 2/4] posix: Do not clobber errno by atfork handlers Adhemerval Zanella
2021-06-24 8:19 ` Florian Weimer
2021-06-24 11:05 ` Adhemerval Zanella
2021-06-24 11:19 ` Florian Weimer
2021-06-24 11:32 ` Adhemerval Zanella
2021-06-23 18:43 ` [PATCH v4 3/4] Consolidate pthread_atfork Adhemerval Zanella
2021-06-24 8:22 ` Florian Weimer
2021-06-24 11:32 ` Adhemerval Zanella
2021-06-23 18:43 ` [PATCH v4 4/4] posix: Add _Fork [BZ #4737] Adhemerval Zanella
2021-06-24 8:47 ` Florian Weimer
2021-06-24 13:34 ` Adhemerval Zanella
2021-06-28 8:52 ` Florian Weimer
2021-06-28 18:10 ` Adhemerval Zanella
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).