Get rid of nptl/sysdeps/ entirely!
This commit is contained in:
parent
96baf6ffc5
commit
08192659bb
147
ChangeLog
147
ChangeLog
@ -1,3 +1,150 @@
|
||||
2014-07-07 Roland McGrath <roland@hack.frob.com>
|
||||
|
||||
* nptl/Makefile (routines): Add libc_pthread_init,
|
||||
libc_multiple_threads, register-atfork and unregister-atfork.
|
||||
(libpthread-routines): Add pthread_mutex_cond_lock and pt-fork here.
|
||||
(gen-as-const-headers): Add lowlevelcond.sym, lowlevelrwlock.sym,
|
||||
lowlevelbarrier.sym, unwindbuf.sym, lowlevelrobustlock.sym,
|
||||
pthread-pi-defines.sym, structsem.sym.
|
||||
* sysdeps/unix/sysv/linux/Makefile [$(subdir) = posix]
|
||||
(CFLAGS-fork.c, CFLAGS-getpid.o, CFLAGS-getpid.os): New variables.
|
||||
[$(subdir) = nptl] (tests): Add tst-setgetname.
|
||||
* nptl/sysdeps/unix/sysv/linux/Makefile: File removed.
|
||||
* sysdeps/unix/sysv/linux/sigaction.c: Just include
|
||||
<nptl/sigaction.c> directly here, instead of WRAPPER_INCLUDE.
|
||||
[!LIBC_SIGACTION]: Remove aliases.
|
||||
* sysdeps/unix/sysv/linux/aarch64/sigaction.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/arm/sigaction.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/i386/sigaction.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/ia64/sigaction.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/mips/sigaction.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/x86_64/sigaction.c: Likewise.
|
||||
* nptl/Versions (libc: GLIBC_2.3.2): Add __register_atfork.
|
||||
(libc: GLIBC_PRIVATE): Add __libc_pthread_init,
|
||||
__libc_current_sigrtmin_private, __libc_current_sigrtmax_private,
|
||||
__libc_allocate_rtsig_private.
|
||||
* nptl/sysdeps/unix/sysv/linux/Versions: File removed.
|
||||
* sysdeps/unix/sysv/linux/sigtimedwait.c: Include <nptl/pthreadP.h>.
|
||||
* sysdeps/unix/sysv/linux/sigwait.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/sigwaitinfo.c: Likewise.
|
||||
* sysdeps/unix/sysv/linux/sleep.c: Likewise.
|
||||
* nptl/sysdeps/unix/sysv/linux/sigwait.c: File removed.
|
||||
* nptl/sysdeps/unix/sysv/linux/sigtimedwait.c: File removed.
|
||||
* nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c: File removed.
|
||||
* nptl/sysdeps/unix/sysv/linux/sleep.c: File removed.
|
||||
* nptl/sysdeps/unix/sysv/linux/createthread.c: File removed.
|
||||
* sysdeps/unix/sysv/linux/ia64/fork.S: File removed.
|
||||
* nptl/sysdeps/unix/sysv/linux/internaltypes.h: Moved ...
|
||||
* nptl/internaltypes.h: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/jmp-unwind.c: Moved ...
|
||||
* sysdeps/nptl/jmp-unwind.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c: Moved ...
|
||||
* nptl/libc-lowlevellock.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c: Moved ...
|
||||
* nptl/libc_multiple_threads.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c: Moved ...
|
||||
* nptl/libc_pthread_init.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym: Moved ...
|
||||
* nptl/lowlevelbarrier.sym: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym: Moved ...
|
||||
* nptl/lowlevelcond.sym: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/lowlevellock.c: Moved ...
|
||||
* nptl/lowlevellock.c: ... here.
|
||||
* nptl/lowlevellock.h: Moved ...
|
||||
* sysdeps/nptl/lowlevellock.h: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c: Moved ...
|
||||
* nptl/lowlevelrobustlock.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym: Moved ...
|
||||
* nptl/lowlevelrobustlock.sym: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym: Moved ...
|
||||
* nptl/lowlevelrwlock.sym: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pt-fork.c: Moved ...
|
||||
* nptl/pt-fork.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym: Moved ...
|
||||
* nptl/pthread-pi-defines.sym: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c: Moved ...
|
||||
* nptl/pthread_attr_getaffinity.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: Moved ...
|
||||
* nptl/pthread_attr_setaffinity.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Moved ...
|
||||
* nptl/pthread_mutex_cond_lock.c: ... here.
|
||||
* sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c:
|
||||
Update #include.
|
||||
* sysdeps/unix/sysv/linux/x86/pthread_mutex_cond_lock.c: Likewise.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_once.c: Moved ...
|
||||
* nptl/pthread_once.c: ... here, replacing old file.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_yield.c: Moved ...
|
||||
* nptl/pthread_yield.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/register-atfork.c: Moved ...
|
||||
* nptl/register-atfork.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/sem_post.c: Moved ...
|
||||
* nptl/sem_post.c: ... here.
|
||||
* sysdeps/unix/sysv/linux/alpha/sem_post.c: Update #include.
|
||||
* nptl/sysdeps/unix/sysv/linux/sem_timedwait.c: Moved ...
|
||||
* nptl/sem_timedwait.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/sem_trywait.c: Moved ...
|
||||
* nptl/sem_trywait.c: ... here.
|
||||
* sysdeps/sparc/sparc32/sparcv9/sem_trywait.c: Update #include.
|
||||
* nptl/sysdeps/unix/sysv/linux/sem_wait.c: Moved ...
|
||||
* nptl/sem_wait.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/structsem.sym: Moved ...
|
||||
* nptl/structsem.sym: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/mq_notify.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/mq_notify.c: ... here, replacing old file.
|
||||
* nptl/sysdeps/unix/sysv/linux/unregister-atfork.c: Moved ...
|
||||
* nptl/unregister-atfork.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/unwindbuf.sym: Moved ...
|
||||
* nptl/unwindbuf.sym: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/fork.c: Moved ...
|
||||
* sysdeps/nptl/fork.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/fork.h: Moved ...
|
||||
* sysdeps/nptl/fork.h: ... here.
|
||||
* sysdeps/unix/sysv/linux/syscalls.list: Remove fork.
|
||||
* nptl/sysdeps/unix/sysv/linux/aio_misc.h: Moved ...
|
||||
* sysdeps/unix/sysv/linux/aio_misc.h: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/allocrtsig.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/allocrtsig.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/getpid.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/getpid.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h: Moved ...
|
||||
* sysdeps/unix/sysv/linux/kernel-posix-timers.h: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pt-raise.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/pt-raise.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/pthread_getaffinity.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/pthread_getcpuclockid.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_getname.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/pthread_getname.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_kill.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/pthread_kill.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/pthread_setaffinity.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_setname.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/pthread_setname.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/pthread_sigqueue.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/pthread_sigqueue.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/raise.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/raise.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/timer_create.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/timer_create.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/timer_delete.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/timer_delete.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/timer_getoverr.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/timer_getoverr.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/timer_gettime.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/timer_gettime.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/timer_routines.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/timer_routines.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/timer_settime.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/timer_settime.c: ... here.
|
||||
* nptl/sysdeps/unix/sysv/linux/tst-setgetname.c: Moved ...
|
||||
* sysdeps/unix/sysv/linux/tst-setgetname.c: ... here.
|
||||
* sysdeps/unix/sysv/linux/s390/jmp-unwind.c: Update #include.
|
||||
|
||||
2014-07-04 Siddhesh Poyarekar <siddhesh@redhat.com>
|
||||
|
||||
* sysdeps/generic/memcopy.h: Add comment for
|
||||
|
@ -29,7 +29,8 @@ extra-libs-others := $(extra-libs)
|
||||
install-lib-ldscripts := libpthread.so
|
||||
|
||||
routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
|
||||
libc-cleanup
|
||||
libc-cleanup libc_pthread_init libc_multiple_threads \
|
||||
register-atfork unregister-atfork
|
||||
shared-only-routines = forward
|
||||
|
||||
libpthread-routines = nptl-init vars events version \
|
||||
@ -54,6 +55,7 @@ libpthread-routines = nptl-init vars events version \
|
||||
pthread_mutex_init pthread_mutex_destroy \
|
||||
pthread_mutex_lock pthread_mutex_trylock \
|
||||
pthread_mutex_timedlock pthread_mutex_unlock \
|
||||
pthread_mutex_cond_lock \
|
||||
pthread_mutexattr_init pthread_mutexattr_destroy \
|
||||
pthread_mutexattr_getpshared \
|
||||
pthread_mutexattr_setpshared \
|
||||
@ -103,7 +105,7 @@ libpthread-routines = nptl-init vars events version \
|
||||
pt-longjmp pt-cleanup\
|
||||
cancellation \
|
||||
lowlevellock lowlevelrobustlock \
|
||||
pt-vfork \
|
||||
pt-fork pt-vfork \
|
||||
ptw-write ptw-read ptw-close ptw-fcntl ptw-accept \
|
||||
ptw-connect ptw-recv ptw-recvfrom ptw-recvmsg ptw-send \
|
||||
ptw-sendmsg ptw-sendto ptw-fsync ptw-lseek ptw-llseek \
|
||||
@ -277,7 +279,12 @@ test-srcs = tst-oddstacklimit
|
||||
# Files which must not be linked with libpthread.
|
||||
tests-nolibpthread = tst-unload
|
||||
|
||||
gen-as-const-headers = pthread-errnos.sym
|
||||
gen-as-const-headers = pthread-errnos.sym \
|
||||
lowlevelcond.sym lowlevelrwlock.sym \
|
||||
lowlevelbarrier.sym unwindbuf.sym \
|
||||
lowlevelrobustlock.sym pthread-pi-defines.sym \
|
||||
structsem.sym
|
||||
|
||||
|
||||
LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
|
||||
|
||||
|
@ -21,6 +21,8 @@ libc {
|
||||
pthread_attr_init;
|
||||
}
|
||||
GLIBC_2.3.2 {
|
||||
__register_atfork;
|
||||
|
||||
# Changed pthread_cond_t.
|
||||
pthread_cond_init; pthread_cond_destroy;
|
||||
pthread_cond_wait; pthread_cond_signal;
|
||||
@ -31,6 +33,9 @@ libc {
|
||||
# Internal libc interface to libpthread
|
||||
__libc_dl_error_tsd;
|
||||
__libc_vfork;
|
||||
__libc_pthread_init;
|
||||
__libc_current_sigrtmin_private; __libc_current_sigrtmax_private;
|
||||
__libc_allocate_rtsig_private;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Copyright (C) 2002-2014 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
|
||||
Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
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
|
||||
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
|
||||
@ -18,37 +18,114 @@
|
||||
|
||||
#include "pthreadP.h"
|
||||
#include <lowlevellock.h>
|
||||
#include <atomic.h>
|
||||
|
||||
|
||||
|
||||
static int once_lock = LLL_LOCK_INITIALIZER;
|
||||
unsigned long int __fork_generation attribute_hidden;
|
||||
|
||||
|
||||
static void
|
||||
clear_once_control (void *arg)
|
||||
{
|
||||
pthread_once_t *once_control = (pthread_once_t *) arg;
|
||||
|
||||
/* Reset to the uninitialized state here. We don't need a stronger memory
|
||||
order because we do not need to make any other of our writes visible to
|
||||
other threads that see this value: This function will be called if we
|
||||
get interrupted (see __pthread_once), so all we need to relay to other
|
||||
threads is the state being reset again. */
|
||||
*once_control = 0;
|
||||
lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
|
||||
}
|
||||
|
||||
|
||||
/* This is similar to a lock implementation, but we distinguish between three
|
||||
states: not yet initialized (0), initialization finished (2), and
|
||||
initialization in progress (__fork_generation | 1). If in the first state,
|
||||
threads will try to run the initialization by moving to the second state;
|
||||
the first thread to do so via a CAS on once_control runs init_routine,
|
||||
other threads block.
|
||||
When forking the process, some threads can be interrupted during the second
|
||||
state; they won't be present in the forked child, so we need to restart
|
||||
initialization in the child. To distinguish an in-progress initialization
|
||||
from an interrupted initialization (in which case we need to reclaim the
|
||||
lock), we look at the fork generation that's part of the second state: We
|
||||
can reclaim iff it differs from the current fork generation.
|
||||
XXX: This algorithm has an ABA issue on the fork generation: If an
|
||||
initialization is interrupted, we then fork 2^30 times (30 bits of
|
||||
once_control are used for the fork generation), and try to initialize
|
||||
again, we can deadlock because we can't distinguish the in-progress and
|
||||
interrupted cases anymore. */
|
||||
int
|
||||
__pthread_once (once_control, init_routine)
|
||||
pthread_once_t *once_control;
|
||||
void (*init_routine) (void);
|
||||
{
|
||||
/* XXX Depending on whether the LOCK_IN_ONCE_T is defined use a
|
||||
global lock variable or one which is part of the pthread_once_t
|
||||
object. */
|
||||
if (*once_control == PTHREAD_ONCE_INIT)
|
||||
while (1)
|
||||
{
|
||||
lll_lock (once_lock, LLL_PRIVATE);
|
||||
int oldval, val, newval;
|
||||
|
||||
/* XXX This implementation is not complete. It doesn't take
|
||||
cancelation and fork into account. */
|
||||
if (*once_control == PTHREAD_ONCE_INIT)
|
||||
/* We need acquire memory order for this load because if the value
|
||||
signals that initialization has finished, we need to be see any
|
||||
data modifications done during initialization. */
|
||||
val = *once_control;
|
||||
atomic_read_barrier();
|
||||
do
|
||||
{
|
||||
init_routine ();
|
||||
/* Check if the initialization has already been done. */
|
||||
if (__glibc_likely ((val & 2) != 0))
|
||||
return 0;
|
||||
|
||||
*once_control = !PTHREAD_ONCE_INIT;
|
||||
oldval = val;
|
||||
/* We try to set the state to in-progress and having the current
|
||||
fork generation. We don't need atomic accesses for the fork
|
||||
generation because it's immutable in a particular process, and
|
||||
forked child processes start with a single thread that modified
|
||||
the generation. */
|
||||
newval = __fork_generation | 1;
|
||||
/* We need acquire memory order here for the same reason as for the
|
||||
load from once_control above. */
|
||||
val = atomic_compare_and_exchange_val_acq (once_control, newval,
|
||||
oldval);
|
||||
}
|
||||
while (__glibc_unlikely (val != oldval));
|
||||
|
||||
/* Check if another thread already runs the initializer. */
|
||||
if ((oldval & 1) != 0)
|
||||
{
|
||||
/* Check whether the initializer execution was interrupted by a
|
||||
fork. We know that for both values, bit 0 is set and bit 1 is
|
||||
not. */
|
||||
if (oldval == newval)
|
||||
{
|
||||
/* Same generation, some other thread was faster. Wait. */
|
||||
lll_futex_wait (once_control, newval, LLL_PRIVATE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
lll_unlock (once_lock, LLL_PRIVATE);
|
||||
/* This thread is the first here. Do the initialization.
|
||||
Register a cleanup handler so that in case the thread gets
|
||||
interrupted the initialization can be restarted. */
|
||||
pthread_cleanup_push (clear_once_control, once_control);
|
||||
|
||||
init_routine ();
|
||||
|
||||
pthread_cleanup_pop (0);
|
||||
|
||||
|
||||
/* Mark *once_control as having finished the initialization. We need
|
||||
release memory order here because we need to synchronize with other
|
||||
threads that want to use the initialized data. */
|
||||
atomic_write_barrier();
|
||||
*once_control = 2;
|
||||
|
||||
/* Wake up all other threads. */
|
||||
lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_once, pthread_once)
|
||||
weak_alias (__pthread_once, pthread_once)
|
||||
hidden_def (__pthread_once)
|
||||
|
@ -1,39 +0,0 @@
|
||||
# Copyright (C) 2002-2014 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
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
ifeq ($(subdir),nptl)
|
||||
sysdep_routines += register-atfork unregister-atfork libc_pthread_init \
|
||||
libc_multiple_threads
|
||||
|
||||
libpthread-sysdep_routines += pt-fork pthread_mutex_cond_lock
|
||||
|
||||
gen-as-const-headers += lowlevelcond.sym lowlevelrwlock.sym \
|
||||
lowlevelbarrier.sym unwindbuf.sym \
|
||||
lowlevelrobustlock.sym pthread-pi-defines.sym \
|
||||
structsem.sym
|
||||
tests += tst-setgetname
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),posix)
|
||||
CFLAGS-fork.c = $(libio-mtsafe)
|
||||
CFLAGS-getpid.o = -fomit-frame-pointer
|
||||
CFLAGS-getpid.os = -fomit-frame-pointer
|
||||
endif
|
||||
|
||||
# Needed in both the signal and nptl subdir.
|
||||
CFLAGS-sigaction.c = -DWRAPPER_INCLUDE='<nptl/sigaction.c>'
|
@ -1,15 +0,0 @@
|
||||
libc {
|
||||
GLIBC_2.3.2 {
|
||||
__register_atfork;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
__libc_pthread_init;
|
||||
__libc_current_sigrtmin_private; __libc_current_sigrtmax_private;
|
||||
__libc_allocate_rtsig_private;
|
||||
}
|
||||
}
|
||||
libpthread {
|
||||
GLIBC_2.0 {
|
||||
fork; __fork;
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>.
|
||||
|
||||
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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Value passed to 'clone' for initialization of the thread register. */
|
||||
#define TLS_VALUE pd
|
||||
|
||||
/* Get the real implementation. */
|
||||
#include <nptl/createthread.c>
|
@ -1,282 +0,0 @@
|
||||
/* Copyright (C) 2004-2014 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contribute by Ulrich Drepper <drepper@redhat.com>, 2004.
|
||||
|
||||
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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <mqueue.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysdep.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <not-cancel.h>
|
||||
#include <nptl/pthreadP.h>
|
||||
|
||||
|
||||
#ifdef __NR_mq_notify
|
||||
|
||||
/* Defined in the kernel headers: */
|
||||
#define NOTIFY_COOKIE_LEN 32 /* Length of the cookie used. */
|
||||
#define NOTIFY_WOKENUP 1 /* Code for notifcation. */
|
||||
#define NOTIFY_REMOVED 2 /* Code for closed message queue
|
||||
of de-notifcation. */
|
||||
|
||||
|
||||
/* Data structure for the queued notification requests. */
|
||||
union notify_data
|
||||
{
|
||||
struct
|
||||
{
|
||||
void (*fct) (union sigval); /* The function to run. */
|
||||
union sigval param; /* The parameter to pass. */
|
||||
pthread_attr_t *attr; /* Attributes to create the thread with. */
|
||||
/* NB: on 64-bit machines the struct as a size of 24 bytes. Which means
|
||||
byte 31 can still be used for returning the status. */
|
||||
};
|
||||
char raw[NOTIFY_COOKIE_LEN];
|
||||
};
|
||||
|
||||
|
||||
/* Keep track of the initialization. */
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
|
||||
|
||||
/* The netlink socket. */
|
||||
static int netlink_socket = -1;
|
||||
|
||||
|
||||
/* Barrier used to make sure data passed to the new thread is not
|
||||
resused by the parent. */
|
||||
static pthread_barrier_t notify_barrier;
|
||||
|
||||
|
||||
/* Modify the signal mask. We move this into a separate function so
|
||||
that the stack space needed for sigset_t is not deducted from what
|
||||
the thread can use. */
|
||||
static int
|
||||
__attribute__ ((noinline))
|
||||
change_sigmask (int how, sigset_t *oss)
|
||||
{
|
||||
sigset_t ss;
|
||||
sigfillset (&ss);
|
||||
return pthread_sigmask (how, &ss, oss);
|
||||
}
|
||||
|
||||
|
||||
/* The function used for the notification. */
|
||||
static void *
|
||||
notification_function (void *arg)
|
||||
{
|
||||
/* Copy the function and parameter so that the parent thread can go
|
||||
on with its life. */
|
||||
volatile union notify_data *data = (volatile union notify_data *) arg;
|
||||
void (*fct) (union sigval) = data->fct;
|
||||
union sigval param = data->param;
|
||||
|
||||
/* Let the parent go. */
|
||||
(void) pthread_barrier_wait (¬ify_barrier);
|
||||
|
||||
/* Make the thread detached. */
|
||||
(void) pthread_detach (pthread_self ());
|
||||
|
||||
/* The parent thread has all signals blocked. This is probably a
|
||||
bit surprising for this thread. So we unblock all of them. */
|
||||
(void) change_sigmask (SIG_UNBLOCK, NULL);
|
||||
|
||||
/* Now run the user code. */
|
||||
fct (param);
|
||||
|
||||
/* And we are done. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Helper thread. */
|
||||
static void *
|
||||
helper_thread (void *arg)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
union notify_data data;
|
||||
|
||||
ssize_t n = recv (netlink_socket, &data, sizeof (data),
|
||||
MSG_NOSIGNAL | MSG_WAITALL);
|
||||
if (n < NOTIFY_COOKIE_LEN)
|
||||
continue;
|
||||
|
||||
if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_WOKENUP)
|
||||
{
|
||||
/* Just create the thread as instructed. There is no way to
|
||||
report a problem with creating a thread. */
|
||||
pthread_t th;
|
||||
if (__builtin_expect (pthread_create (&th, data.attr,
|
||||
notification_function, &data)
|
||||
== 0, 0))
|
||||
/* Since we passed a pointer to DATA to the new thread we have
|
||||
to wait until it is done with it. */
|
||||
(void) pthread_barrier_wait (¬ify_barrier);
|
||||
}
|
||||
else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
|
||||
/* The only state we keep is the copy of the thread attributes. */
|
||||
free (data.attr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
reset_once (void)
|
||||
{
|
||||
once = PTHREAD_ONCE_INIT;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_mq_netlink (void)
|
||||
{
|
||||
/* This code might be called a second time after fork(). The file
|
||||
descriptor is inherited from the parent. */
|
||||
if (netlink_socket == -1)
|
||||
{
|
||||
/* Just a normal netlink socket, not bound. */
|
||||
netlink_socket = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, 0);
|
||||
/* No need to do more if we have no socket. */
|
||||
if (netlink_socket == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
int err = 1;
|
||||
|
||||
/* Initialize the barrier. */
|
||||
if (__builtin_expect (pthread_barrier_init (¬ify_barrier, NULL, 2) == 0,
|
||||
0))
|
||||
{
|
||||
/* Create the helper thread. */
|
||||
pthread_attr_t attr;
|
||||
(void) pthread_attr_init (&attr);
|
||||
(void) pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
|
||||
/* We do not need much stack space, the bare minimum will be enough. */
|
||||
(void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr));
|
||||
|
||||
/* Temporarily block all signals so that the newly created
|
||||
thread inherits the mask. */
|
||||
sigset_t oss;
|
||||
int have_no_oss = change_sigmask (SIG_BLOCK, &oss);
|
||||
|
||||
pthread_t th;
|
||||
err = pthread_create (&th, &attr, helper_thread, NULL);
|
||||
|
||||
/* Reset the signal mask. */
|
||||
if (!have_no_oss)
|
||||
pthread_sigmask (SIG_SETMASK, &oss, NULL);
|
||||
|
||||
(void) pthread_attr_destroy (&attr);
|
||||
|
||||
if (err == 0)
|
||||
{
|
||||
static int added_atfork;
|
||||
|
||||
if (added_atfork == 0
|
||||
&& pthread_atfork (NULL, NULL, reset_once) != 0)
|
||||
{
|
||||
/* The child thread will call recv() which is a
|
||||
cancellation point. */
|
||||
(void) pthread_cancel (th);
|
||||
err = 1;
|
||||
}
|
||||
else
|
||||
added_atfork = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
close_not_cancel_no_status (netlink_socket);
|
||||
netlink_socket = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Register notification upon message arrival to an empty message queue
|
||||
MQDES. */
|
||||
int
|
||||
mq_notify (mqd_t mqdes, const struct sigevent *notification)
|
||||
{
|
||||
/* Make sure the type is correctly defined. */
|
||||
assert (sizeof (union notify_data) == NOTIFY_COOKIE_LEN);
|
||||
|
||||
/* Special treatment needed for SIGEV_THREAD. */
|
||||
if (notification == NULL || notification->sigev_notify != SIGEV_THREAD)
|
||||
return INLINE_SYSCALL (mq_notify, 2, mqdes, notification);
|
||||
|
||||
/* The kernel cannot directly start threads. This will have to be
|
||||
done at userlevel. Since we cannot start threads from signal
|
||||
handlers we have to create a dedicated thread which waits for
|
||||
notifications for arriving messages and creates threads in
|
||||
response. */
|
||||
|
||||
/* Initialize only once. */
|
||||
pthread_once (&once, init_mq_netlink);
|
||||
|
||||
/* If we cannot create the netlink socket we cannot provide
|
||||
SIGEV_THREAD support. */
|
||||
if (__glibc_unlikely (netlink_socket == -1))
|
||||
{
|
||||
__set_errno (ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create the cookie. It will hold almost all the state. */
|
||||
union notify_data data;
|
||||
memset (&data, '\0', sizeof (data));
|
||||
data.fct = notification->sigev_notify_function;
|
||||
data.param = notification->sigev_value;
|
||||
|
||||
if (notification->sigev_notify_attributes != NULL)
|
||||
{
|
||||
/* The thread attribute has to be allocated separately. */
|
||||
data.attr = (pthread_attr_t *) malloc (sizeof (pthread_attr_t));
|
||||
if (data.attr == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy (data.attr, notification->sigev_notify_attributes,
|
||||
sizeof (pthread_attr_t));
|
||||
}
|
||||
|
||||
/* Construct the new request. */
|
||||
struct sigevent se;
|
||||
se.sigev_notify = SIGEV_THREAD;
|
||||
se.sigev_signo = netlink_socket;
|
||||
se.sigev_value.sival_ptr = &data;
|
||||
|
||||
/* Tell the kernel. */
|
||||
int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se);
|
||||
|
||||
/* If it failed, free the allocated memory. */
|
||||
if (__glibc_unlikely (retval != 0))
|
||||
free (data.attr);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#else
|
||||
# include <rt/mq_notify.c>
|
||||
#endif
|
@ -1,131 +0,0 @@
|
||||
/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
|
||||
|
||||
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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "pthreadP.h"
|
||||
#include <lowlevellock.h>
|
||||
#include <atomic.h>
|
||||
|
||||
|
||||
unsigned long int __fork_generation attribute_hidden;
|
||||
|
||||
|
||||
static void
|
||||
clear_once_control (void *arg)
|
||||
{
|
||||
pthread_once_t *once_control = (pthread_once_t *) arg;
|
||||
|
||||
/* Reset to the uninitialized state here. We don't need a stronger memory
|
||||
order because we do not need to make any other of our writes visible to
|
||||
other threads that see this value: This function will be called if we
|
||||
get interrupted (see __pthread_once), so all we need to relay to other
|
||||
threads is the state being reset again. */
|
||||
*once_control = 0;
|
||||
lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
|
||||
}
|
||||
|
||||
|
||||
/* This is similar to a lock implementation, but we distinguish between three
|
||||
states: not yet initialized (0), initialization finished (2), and
|
||||
initialization in progress (__fork_generation | 1). If in the first state,
|
||||
threads will try to run the initialization by moving to the second state;
|
||||
the first thread to do so via a CAS on once_control runs init_routine,
|
||||
other threads block.
|
||||
When forking the process, some threads can be interrupted during the second
|
||||
state; they won't be present in the forked child, so we need to restart
|
||||
initialization in the child. To distinguish an in-progress initialization
|
||||
from an interrupted initialization (in which case we need to reclaim the
|
||||
lock), we look at the fork generation that's part of the second state: We
|
||||
can reclaim iff it differs from the current fork generation.
|
||||
XXX: This algorithm has an ABA issue on the fork generation: If an
|
||||
initialization is interrupted, we then fork 2^30 times (30 bits of
|
||||
once_control are used for the fork generation), and try to initialize
|
||||
again, we can deadlock because we can't distinguish the in-progress and
|
||||
interrupted cases anymore. */
|
||||
int
|
||||
__pthread_once (once_control, init_routine)
|
||||
pthread_once_t *once_control;
|
||||
void (*init_routine) (void);
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int oldval, val, newval;
|
||||
|
||||
/* We need acquire memory order for this load because if the value
|
||||
signals that initialization has finished, we need to be see any
|
||||
data modifications done during initialization. */
|
||||
val = *once_control;
|
||||
atomic_read_barrier();
|
||||
do
|
||||
{
|
||||
/* Check if the initialization has already been done. */
|
||||
if (__glibc_likely ((val & 2) != 0))
|
||||
return 0;
|
||||
|
||||
oldval = val;
|
||||
/* We try to set the state to in-progress and having the current
|
||||
fork generation. We don't need atomic accesses for the fork
|
||||
generation because it's immutable in a particular process, and
|
||||
forked child processes start with a single thread that modified
|
||||
the generation. */
|
||||
newval = __fork_generation | 1;
|
||||
/* We need acquire memory order here for the same reason as for the
|
||||
load from once_control above. */
|
||||
val = atomic_compare_and_exchange_val_acq (once_control, newval,
|
||||
oldval);
|
||||
}
|
||||
while (__glibc_unlikely (val != oldval));
|
||||
|
||||
/* Check if another thread already runs the initializer. */
|
||||
if ((oldval & 1) != 0)
|
||||
{
|
||||
/* Check whether the initializer execution was interrupted by a
|
||||
fork. We know that for both values, bit 0 is set and bit 1 is
|
||||
not. */
|
||||
if (oldval == newval)
|
||||
{
|
||||
/* Same generation, some other thread was faster. Wait. */
|
||||
lll_futex_wait (once_control, newval, LLL_PRIVATE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* This thread is the first here. Do the initialization.
|
||||
Register a cleanup handler so that in case the thread gets
|
||||
interrupted the initialization can be restarted. */
|
||||
pthread_cleanup_push (clear_once_control, once_control);
|
||||
|
||||
init_routine ();
|
||||
|
||||
pthread_cleanup_pop (0);
|
||||
|
||||
|
||||
/* Mark *once_control as having finished the initialization. We need
|
||||
release memory order here because we need to synchronize with other
|
||||
threads that want to use the initialized data. */
|
||||
atomic_write_barrier();
|
||||
*once_control = 2;
|
||||
|
||||
/* Wake up all other threads. */
|
||||
lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_once, pthread_once)
|
||||
hidden_def (__pthread_once)
|
@ -1,2 +0,0 @@
|
||||
#include <nptl/pthreadP.h>
|
||||
#include "../../../../../sysdeps/unix/sysv/linux/sigtimedwait.c"
|
@ -1,2 +0,0 @@
|
||||
#include <nptl/pthreadP.h>
|
||||
#include "../../../../../sysdeps/unix/sysv/linux/sigwait.c"
|
@ -1,2 +0,0 @@
|
||||
#include <nptl/pthreadP.h>
|
||||
#include "../../../../../sysdeps/unix/sysv/linux/sigwaitinfo.c"
|
@ -1,10 +0,0 @@
|
||||
/* We want an #include_next, but we are the main source file.
|
||||
So, #include ourselves and in that incarnation we can use #include_next. */
|
||||
#ifndef INCLUDED_SELF
|
||||
# define INCLUDED_SELF
|
||||
# include <sleep.c>
|
||||
#else
|
||||
/* This defines the CANCELLATION_P macro, which sleep.c checks for. */
|
||||
# include <pthreadP.h>
|
||||
# include_next <sleep.c>
|
||||
#endif
|
@ -1 +1 @@
|
||||
#include <sysdeps/unix/sysv/linux/sem_trywait.c>
|
||||
#include <nptl/sem_trywait.c>
|
||||
|
@ -144,6 +144,10 @@ sysdep_headers += bits/initspin.h
|
||||
sysdep_routines += sched_getcpu
|
||||
|
||||
tests += tst-getcpu
|
||||
|
||||
CFLAGS-fork.c = $(libio-mtsafe)
|
||||
CFLAGS-getpid.o = -fomit-frame-pointer
|
||||
CFLAGS-getpid.os = -fomit-frame-pointer
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),inet)
|
||||
@ -190,3 +194,7 @@ ifeq ($(subdir),nscd)
|
||||
sysdep-CFLAGS += -DHAVE_EPOLL -DHAVE_SENDFILE -DHAVE_INOTIFY -DHAVE_NETLINK
|
||||
CFLAGS-gai.c += -DNEED_NETLINK
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),nptl)
|
||||
tests += tst-setgetname
|
||||
endif
|
||||
|
@ -67,12 +67,4 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction)
|
||||
libc_hidden_weak (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction)
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
@ -2,4 +2,4 @@
|
||||
the acquire/release semantics of atomic_exchange_and_add. And even if
|
||||
we don't do this, we should be using atomic_full_barrier or otherwise. */
|
||||
#define __lll_rel_instr "mb"
|
||||
#include <nptl/sysdeps/unix/sysv/linux/sem_post.c>
|
||||
#include <nptl/sem_post.c>
|
||||
|
@ -84,12 +84,4 @@ __libc_sigaction (sig, act, oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction)
|
||||
libc_hidden_weak (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction)
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
@ -84,15 +84,7 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction)
|
||||
libc_hidden_weak (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction)
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
||||
/* NOTE: Please think twice before making any changes to the bits of
|
||||
code below. GDB needs some intimate knowledge about it to
|
||||
|
@ -1,40 +0,0 @@
|
||||
/* Copyright (C) 2000-2014 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#include <sysdep.h>
|
||||
#define _SIGNAL_H
|
||||
#include <bits/signum.h>
|
||||
|
||||
/* pid_t fork(void); */
|
||||
/* Implemented as a clone system call with parameters SIGCHLD and 0 */
|
||||
|
||||
ENTRY(__libc_fork)
|
||||
alloc r2=ar.pfs,0,0,2,0
|
||||
mov out0=SIGCHLD /* Return SIGCHLD when child finishes */
|
||||
/* no other clone flags; nothing shared */
|
||||
mov out1=0 /* Standard sp value. */
|
||||
;;
|
||||
DO_CALL (SYS_ify (clone))
|
||||
cmp.eq p6,p0=-1,r10
|
||||
(p6) br.cond.spnt.few __syscall_error
|
||||
ret
|
||||
PSEUDO_END(__libc_fork)
|
||||
|
||||
weak_alias (__libc_fork, __fork)
|
||||
libc_hidden_def (__fork)
|
||||
weak_alias (__libc_fork, fork)
|
@ -45,12 +45,4 @@ __libc_sigaction (sig, act, oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction)
|
||||
libc_hidden_def (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction)
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
@ -87,15 +87,8 @@ __libc_sigaction (sig, act, oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction)
|
||||
libc_hidden_weak (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction)
|
||||
#endif
|
||||
|
||||
/* NOTE: Please think twice before making any changes to the bits of
|
||||
code below. GDB needs some intimate knowledge about it to
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* Copyright (C) 2004-2014 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contribute by Ulrich Drepper <drepper@redhat.com>, 2004.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
@ -15,27 +16,265 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <mqueue.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysdep.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <not-cancel.h>
|
||||
#include <nptl/pthreadP.h>
|
||||
|
||||
|
||||
#ifdef __NR_mq_notify
|
||||
|
||||
/* Defined in the kernel headers: */
|
||||
#define NOTIFY_COOKIE_LEN 32 /* Length of the cookie used. */
|
||||
#define NOTIFY_WOKENUP 1 /* Code for notifcation. */
|
||||
#define NOTIFY_REMOVED 2 /* Code for closed message queue
|
||||
of de-notifcation. */
|
||||
|
||||
|
||||
/* Data structure for the queued notification requests. */
|
||||
union notify_data
|
||||
{
|
||||
struct
|
||||
{
|
||||
void (*fct) (union sigval); /* The function to run. */
|
||||
union sigval param; /* The parameter to pass. */
|
||||
pthread_attr_t *attr; /* Attributes to create the thread with. */
|
||||
/* NB: on 64-bit machines the struct as a size of 24 bytes. Which means
|
||||
byte 31 can still be used for returning the status. */
|
||||
};
|
||||
char raw[NOTIFY_COOKIE_LEN];
|
||||
};
|
||||
|
||||
|
||||
/* Keep track of the initialization. */
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
|
||||
|
||||
/* The netlink socket. */
|
||||
static int netlink_socket = -1;
|
||||
|
||||
|
||||
/* Barrier used to make sure data passed to the new thread is not
|
||||
resused by the parent. */
|
||||
static pthread_barrier_t notify_barrier;
|
||||
|
||||
|
||||
/* Modify the signal mask. We move this into a separate function so
|
||||
that the stack space needed for sigset_t is not deducted from what
|
||||
the thread can use. */
|
||||
static int
|
||||
__attribute__ ((noinline))
|
||||
change_sigmask (int how, sigset_t *oss)
|
||||
{
|
||||
sigset_t ss;
|
||||
sigfillset (&ss);
|
||||
return pthread_sigmask (how, &ss, oss);
|
||||
}
|
||||
|
||||
|
||||
/* The function used for the notification. */
|
||||
static void *
|
||||
notification_function (void *arg)
|
||||
{
|
||||
/* Copy the function and parameter so that the parent thread can go
|
||||
on with its life. */
|
||||
volatile union notify_data *data = (volatile union notify_data *) arg;
|
||||
void (*fct) (union sigval) = data->fct;
|
||||
union sigval param = data->param;
|
||||
|
||||
/* Let the parent go. */
|
||||
(void) pthread_barrier_wait (¬ify_barrier);
|
||||
|
||||
/* Make the thread detached. */
|
||||
(void) pthread_detach (pthread_self ());
|
||||
|
||||
/* The parent thread has all signals blocked. This is probably a
|
||||
bit surprising for this thread. So we unblock all of them. */
|
||||
(void) change_sigmask (SIG_UNBLOCK, NULL);
|
||||
|
||||
/* Now run the user code. */
|
||||
fct (param);
|
||||
|
||||
/* And we are done. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Helper thread. */
|
||||
static void *
|
||||
helper_thread (void *arg)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
union notify_data data;
|
||||
|
||||
ssize_t n = recv (netlink_socket, &data, sizeof (data),
|
||||
MSG_NOSIGNAL | MSG_WAITALL);
|
||||
if (n < NOTIFY_COOKIE_LEN)
|
||||
continue;
|
||||
|
||||
if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_WOKENUP)
|
||||
{
|
||||
/* Just create the thread as instructed. There is no way to
|
||||
report a problem with creating a thread. */
|
||||
pthread_t th;
|
||||
if (__builtin_expect (pthread_create (&th, data.attr,
|
||||
notification_function, &data)
|
||||
== 0, 0))
|
||||
/* Since we passed a pointer to DATA to the new thread we have
|
||||
to wait until it is done with it. */
|
||||
(void) pthread_barrier_wait (¬ify_barrier);
|
||||
}
|
||||
else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
|
||||
/* The only state we keep is the copy of the thread attributes. */
|
||||
free (data.attr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
reset_once (void)
|
||||
{
|
||||
once = PTHREAD_ONCE_INIT;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_mq_netlink (void)
|
||||
{
|
||||
/* This code might be called a second time after fork(). The file
|
||||
descriptor is inherited from the parent. */
|
||||
if (netlink_socket == -1)
|
||||
{
|
||||
/* Just a normal netlink socket, not bound. */
|
||||
netlink_socket = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, 0);
|
||||
/* No need to do more if we have no socket. */
|
||||
if (netlink_socket == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
int err = 1;
|
||||
|
||||
/* Initialize the barrier. */
|
||||
if (__builtin_expect (pthread_barrier_init (¬ify_barrier, NULL, 2) == 0,
|
||||
0))
|
||||
{
|
||||
/* Create the helper thread. */
|
||||
pthread_attr_t attr;
|
||||
(void) pthread_attr_init (&attr);
|
||||
(void) pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
|
||||
/* We do not need much stack space, the bare minimum will be enough. */
|
||||
(void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr));
|
||||
|
||||
/* Temporarily block all signals so that the newly created
|
||||
thread inherits the mask. */
|
||||
sigset_t oss;
|
||||
int have_no_oss = change_sigmask (SIG_BLOCK, &oss);
|
||||
|
||||
pthread_t th;
|
||||
err = pthread_create (&th, &attr, helper_thread, NULL);
|
||||
|
||||
/* Reset the signal mask. */
|
||||
if (!have_no_oss)
|
||||
pthread_sigmask (SIG_SETMASK, &oss, NULL);
|
||||
|
||||
(void) pthread_attr_destroy (&attr);
|
||||
|
||||
if (err == 0)
|
||||
{
|
||||
static int added_atfork;
|
||||
|
||||
if (added_atfork == 0
|
||||
&& pthread_atfork (NULL, NULL, reset_once) != 0)
|
||||
{
|
||||
/* The child thread will call recv() which is a
|
||||
cancellation point. */
|
||||
(void) pthread_cancel (th);
|
||||
err = 1;
|
||||
}
|
||||
else
|
||||
added_atfork = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
close_not_cancel_no_status (netlink_socket);
|
||||
netlink_socket = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Register notification upon message arrival to an empty message queue
|
||||
MQDES. */
|
||||
int
|
||||
mq_notify (mqd_t mqdes, const struct sigevent *notification)
|
||||
{
|
||||
/* mq_notify which handles SIGEV_THREAD is included in the thread
|
||||
add-on. */
|
||||
if (notification != NULL
|
||||
&& notification->sigev_notify == SIGEV_THREAD)
|
||||
/* Make sure the type is correctly defined. */
|
||||
assert (sizeof (union notify_data) == NOTIFY_COOKIE_LEN);
|
||||
|
||||
/* Special treatment needed for SIGEV_THREAD. */
|
||||
if (notification == NULL || notification->sigev_notify != SIGEV_THREAD)
|
||||
return INLINE_SYSCALL (mq_notify, 2, mqdes, notification);
|
||||
|
||||
/* The kernel cannot directly start threads. This will have to be
|
||||
done at userlevel. Since we cannot start threads from signal
|
||||
handlers we have to create a dedicated thread which waits for
|
||||
notifications for arriving messages and creates threads in
|
||||
response. */
|
||||
|
||||
/* Initialize only once. */
|
||||
pthread_once (&once, init_mq_netlink);
|
||||
|
||||
/* If we cannot create the netlink socket we cannot provide
|
||||
SIGEV_THREAD support. */
|
||||
if (__glibc_unlikely (netlink_socket == -1))
|
||||
{
|
||||
__set_errno (ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
return INLINE_SYSCALL (mq_notify, 2, mqdes, notification);
|
||||
|
||||
/* Create the cookie. It will hold almost all the state. */
|
||||
union notify_data data;
|
||||
memset (&data, '\0', sizeof (data));
|
||||
data.fct = notification->sigev_notify_function;
|
||||
data.param = notification->sigev_value;
|
||||
|
||||
if (notification->sigev_notify_attributes != NULL)
|
||||
{
|
||||
/* The thread attribute has to be allocated separately. */
|
||||
data.attr = (pthread_attr_t *) malloc (sizeof (pthread_attr_t));
|
||||
if (data.attr == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy (data.attr, notification->sigev_notify_attributes,
|
||||
sizeof (pthread_attr_t));
|
||||
}
|
||||
|
||||
/* Construct the new request. */
|
||||
struct sigevent se;
|
||||
se.sigev_notify = SIGEV_THREAD;
|
||||
se.sigev_signo = netlink_socket;
|
||||
se.sigev_value.sival_ptr = &data;
|
||||
|
||||
/* Tell the kernel. */
|
||||
int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se);
|
||||
|
||||
/* If it failed, free the allocated memory. */
|
||||
if (__glibc_unlikely (retval != 0))
|
||||
free (data.attr);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stddef.h>
|
||||
#include <pthreadP.h>
|
||||
#include <nptl/pthreadP.h>
|
||||
|
||||
extern void __pthread_cleanup_upto (__jmp_buf env, char *targetframe);
|
||||
#pragma weak __pthread_cleanup_upto
|
||||
|
@ -19,4 +19,4 @@
|
||||
already elided locks. */
|
||||
#include <elision-conf.h>
|
||||
|
||||
#include <nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c>
|
||||
#include <nptl/pthread_mutex_cond_lock.c>
|
||||
|
@ -43,12 +43,4 @@ __libc_sigaction (sig, act, oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction)
|
||||
libc_hidden_weak (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction)
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
@ -69,12 +69,4 @@ __libc_sigaction (sig, act, oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction)
|
||||
libc_hidden_weak (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction)
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nptl/pthreadP.h>
|
||||
#include <sysdep-cancel.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nptl/pthreadP.h>
|
||||
#include <sysdep-cancel.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nptl/pthreadP.h>
|
||||
#include <sysdep-cancel.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <string.h> /* For the real memset prototype. */
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <nptl/pthreadP.h>
|
||||
|
||||
|
||||
#if 0
|
||||
|
@ -62,15 +62,8 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction);
|
||||
libc_hidden_weak (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction);
|
||||
#endif
|
||||
|
||||
static void
|
||||
__rt_sigreturn_stub (void)
|
||||
|
@ -63,15 +63,8 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction);
|
||||
libc_hidden_weak (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction);
|
||||
#endif
|
||||
|
||||
static void
|
||||
__rt_sigreturn_stub (void)
|
||||
|
@ -15,7 +15,6 @@ epoll_ctl EXTRA epoll_ctl i:iiip epoll_ctl
|
||||
epoll_wait EXTRA epoll_wait Ci:ipii epoll_wait
|
||||
fdatasync - fdatasync Ci:i fdatasync
|
||||
flock - flock i:ii __flock flock
|
||||
fork - fork i: __libc_fork __fork fork
|
||||
get_kernel_syms EXTRA get_kernel_syms i:p get_kernel_syms
|
||||
getegid - getegid Ei: __getegid getegid
|
||||
geteuid - geteuid Ei: __geteuid geteuid
|
||||
|
@ -19,4 +19,4 @@
|
||||
already elided locks. */
|
||||
#include <elision-conf.h>
|
||||
|
||||
#include "sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c"
|
||||
#include <nptl/pthread_mutex_cond_lock.c>
|
||||
|
@ -73,15 +73,8 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
|
||||
}
|
||||
libc_hidden_def (__libc_sigaction)
|
||||
|
||||
#ifdef WRAPPER_INCLUDE
|
||||
# include WRAPPER_INCLUDE
|
||||
#endif
|
||||
#include <nptl/sigaction.c>
|
||||
|
||||
#ifndef LIBC_SIGACTION
|
||||
weak_alias (__libc_sigaction, __sigaction)
|
||||
libc_hidden_weak (__sigaction)
|
||||
weak_alias (__libc_sigaction, sigaction)
|
||||
#endif
|
||||
|
||||
/* NOTE: Please think twice before making any changes to the bits of
|
||||
code below. GDB needs some intimate knowledge about it to
|
||||
|
Loading…
x
Reference in New Issue
Block a user