* [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
* 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 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
* [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
* 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 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
* [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
* 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 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
* [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 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 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).