diff options
Diffstat (limited to 'sysdeps')
46 files changed, 2408 insertions, 122 deletions
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c new file mode 100644 index 0000000000..70201a294c --- /dev/null +++ b/sysdeps/nptl/fork.c @@ -0,0 +1,238 @@ +/* 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/>. */ + +#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 <bits/stdio-lock.h> +#include <atomic.h> +#include <pthreadP.h> +#include <fork.h> +#include <arch-fork.h> + + +unsigned long int *__fork_generation_pointer; + + + +/* The single linked list of all currently registered fork handlers. */ +struct fork_handler *__fork_handlers; + + +static void +fresetlockfiles (void) +{ + _IO_ITER i; + + for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i)) + _IO_lock_init (*((_IO_lock_t *) _IO_iter_file(i)->_lock)); +} + + +pid_t +__libc_fork (void) +{ + pid_t pid; + struct used_handler + { + struct fork_handler *handler; + struct used_handler *next; + } *allp = NULL; + + /* Run all the registered preparation handlers. In reverse order. + While doing this we build up a list of all the entries. */ + struct fork_handler *runp; + while ((runp = __fork_handlers) != NULL) + { + /* Make sure we read from the current RUNP pointer. */ + atomic_full_barrier (); + + unsigned int oldval = runp->refcntr; + + if (oldval == 0) + /* This means some other thread removed the list just after + the pointer has been loaded. Try again. Either the list + is empty or we can retry it. */ + continue; + + /* Bump the reference counter. */ + if (atomic_compare_and_exchange_bool_acq (&__fork_handlers->refcntr, + oldval + 1, oldval)) + /* The value changed, try again. */ + continue; + + /* We bumped the reference counter for the first entry in the + list. That means that none of the following entries will + just go away. The unloading code works in the order of the + list. + + While executing the registered handlers we are building a + list of all the entries so that we can go backward later on. */ + while (1) + { + /* Execute the handler if there is one. */ + if (runp->prepare_handler != NULL) + runp->prepare_handler (); + + /* Create a new element for the list. */ + struct used_handler *newp + = (struct used_handler *) alloca (sizeof (*newp)); + newp->handler = runp; + newp->next = allp; + allp = newp; + + /* Advance to the next handler. */ + runp = runp->next; + if (runp == NULL) + break; + + /* Bump the reference counter for the next entry. */ + atomic_increment (&runp->refcntr); + } + + /* We are done. */ + break; + } + + _IO_list_lock (); + +#ifndef NDEBUG + pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); +#endif + + /* We need to prevent the getpid() code to update the PID field so + that, if a signal arrives in the child very early and the signal + handler uses getpid(), the value returned is correct. */ + pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid); + THREAD_SETMEM (THREAD_SELF, pid, -parentpid); + +#ifdef ARCH_FORK + pid = ARCH_FORK (); +#else +# error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used" + pid = INLINE_SYSCALL (fork, 0); +#endif + + + if (pid == 0) + { + struct pthread *self = THREAD_SELF; + + assert (THREAD_GETMEM (self, tid) != ppid); + + if (__fork_generation_pointer != NULL) + *__fork_generation_pointer += 4; + + /* Adjust the PID field for the new process. */ + THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); + +#if HP_TIMING_AVAIL + /* The CPU clock of the thread and process have to be set to zero. */ + hp_timing_t now; + HP_TIMING_NOW (now); + THREAD_SETMEM (self, cpuclock_offset, now); + GL(dl_cpuclock_offset) = now; +#endif + +#ifdef __NR_set_robust_list + /* Initialize the robust mutex list which has been reset during + the fork. We do not check for errors since if it fails here + it failed at process start as well and noone could have used + robust mutexes. We also do not have to set + self->robust_head.futex_offset since we inherit the correct + value from the parent. */ +# ifdef SHARED + if (__builtin_expect (__libc_pthread_functions_init, 0)) + PTHFCT_CALL (ptr_set_robust, (self)); +# else + extern __typeof (__nptl_set_robust) __nptl_set_robust + __attribute__((weak)); + if (__builtin_expect (__nptl_set_robust != NULL, 0)) + __nptl_set_robust (self); +# endif +#endif + + /* Reset the file list. These are recursive mutexes. */ + fresetlockfiles (); + + /* Reset locks in the I/O code. */ + _IO_list_resetlock (); + + /* Reset the lock the dynamic loader uses to protect its data. */ + __rtld_lock_initialize (GL(dl_load_lock)); + + /* Run the handlers registered for the child. */ + while (allp != NULL) + { + if (allp->handler->child_handler != NULL) + allp->handler->child_handler (); + + /* Note that we do not have to wake any possible waiter. + This is the only thread in the new process. The count + may have been bumped up by other threads doing a fork. + We reset it to 1, to avoid waiting for non-existing + thread(s) to release the count. */ + allp->handler->refcntr = 1; + + /* XXX We could at this point look through the object pool + and mark all objects not on the __fork_handlers list as + unused. This is necessary in case the fork() happened + while another thread called dlclose() and that call had + to create a new list. */ + + allp = allp->next; + } + + /* Initialize the fork lock. */ + __fork_lock = LLL_LOCK_INITIALIZER; + } + else + { + assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); + + /* Restore the PID value. */ + THREAD_SETMEM (THREAD_SELF, pid, parentpid); + + /* We execute this even if the 'fork' call failed. */ + _IO_list_unlock (); + + /* Run the handlers registered for the parent. */ + while (allp != NULL) + { + if (allp->handler->parent_handler != NULL) + allp->handler->parent_handler (); + + if (atomic_decrement_and_test (&allp->handler->refcntr) + && allp->handler->need_signal) + lll_futex_wake (allp->handler->refcntr, 1, LLL_PRIVATE); + + allp = allp->next; + } + } + + 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..8e28a76098 --- /dev/null +++ b/sysdeps/nptl/fork.h @@ -0,0 +1,59 @@ +/* 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/>. */ + +#include <lowlevellock.h> + +/* The fork generation counter, defined in libpthread. */ +extern unsigned long int __fork_generation attribute_hidden; + +/* Pointer to the fork generation counter in the thread library. */ +extern unsigned long int *__fork_generation_pointer attribute_hidden; + +/* Lock to protect allocation and deallocation of fork handlers. */ +extern int __fork_lock attribute_hidden; + +/* Elements of the fork handler lists. */ +struct fork_handler +{ + struct fork_handler *next; + void (*prepare_handler) (void); + void (*parent_handler) (void); + void (*child_handler) (void); + void *dso_handle; + unsigned int refcntr; + int need_signal; +}; + +/* The single linked list of all currently registered for handlers. */ +extern struct fork_handler *__fork_handlers attribute_hidden; + + +/* Function to call to unregister fork handlers. */ +extern void __unregister_atfork (void *dso_handle) attribute_hidden; +#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle) + + +/* C library side function to register new fork handlers. */ +extern int __register_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void), + void *dso_handle); +libc_hidden_proto (__register_atfork) + +/* Add a new element to the fork list. */ +extern void __linkin_atfork (struct fork_handler *newp) attribute_hidden; diff --git a/sysdeps/nptl/jmp-unwind.c b/sysdeps/nptl/jmp-unwind.c new file mode 100644 index 0000000000..b3a960c980 --- /dev/null +++ b/sysdeps/nptl/jmp-unwind.c @@ -0,0 +1,38 @@ +/* Clean up stack frames unwound by longjmp. Linux version. + Copyright (C) 1995-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 <setjmp.h> +#include <stddef.h> +#include <pthreadP.h> + +extern void __pthread_cleanup_upto (__jmp_buf env, char *targetframe); +#pragma weak __pthread_cleanup_upto + + +void +_longjmp_unwind (jmp_buf env, int val) +{ +#ifdef SHARED + if (__libc_pthread_functions_init) + PTHFCT_CALL (ptr___pthread_cleanup_upto, (env->__jmpbuf, + CURRENT_STACK_FRAME)); +#else + if (__pthread_cleanup_upto != NULL) + __pthread_cleanup_upto (env->__jmpbuf, CURRENT_STACK_FRAME); +#endif +} diff --git a/sysdeps/nptl/lowlevellock.h b/sysdeps/nptl/lowlevellock.h new file mode 100644 index 0000000000..7d1913a58d --- /dev/null +++ b/sysdeps/nptl/lowlevellock.h @@ -0,0 +1,83 @@ +/* Low level locking macros used in NPTL implementation. Stub version. + 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/>. */ + +#include <atomic.h> + + +/* Mutex lock counter: + bit 31 clear means unlocked; + bit 31 set means locked. + + All code that looks at bit 31 first increases the 'number of + interested threads' usage counter, which is in bits 0-30. + + All negative mutex values indicate that the mutex is still locked. */ + + +static inline void +__generic_mutex_lock (int *mutex) +{ + unsigned int v; + + /* Bit 31 was clear, we got the mutex. (this is the fastpath). */ + if (atomic_bit_test_set (mutex, 31) == 0) + return; + + atomic_increment (mutex); + + while (1) + { + if (atomic_bit_test_set (mutex, 31) == 0) + { + atomic_decrement (mutex); + return; + } + + /* We have to wait now. First make sure the futex value we are + monitoring is truly negative (i.e. locked). */ + v = *mutex; + if (v >= 0) + continue; + + lll_futex_wait (mutex, v, + // XYZ check mutex flag + LLL_SHARED); + } +} + + +static inline void +__generic_mutex_unlock (int *mutex) +{ + /* Adding 0x80000000 to the counter results in 0 if and only if + there are not other interested threads - we can return (this is + the fastpath). */ + if (atomic_add_zero (mutex, 0x80000000)) + return; + + /* There are other threads waiting for this mutex, wake one of them + up. */ + lll_futex_wake (mutex, 1, + // XYZ check mutex flag + LLL_SHARED); +} + + +#define lll_mutex_lock(futex) __generic_mutex_lock (&(futex)) +#define lll_mutex_unlock(futex) __generic_mutex_unlock (&(futex)) diff --git a/sysdeps/sparc/sparc32/sparcv9/sem_trywait.c b/sysdeps/sparc/sparc32/sparcv9/sem_trywait.c index 80157c5d2a..a8d4acc3f0 100644 --- a/sysdeps/sparc/sparc32/sparcv9/sem_trywait.c +++ b/sysdeps/sparc/sparc32/sparcv9/sem_trywait.c @@ -1 +1 @@ -#include <sysdeps/unix/sysv/linux/sem_trywait.c> +#include <nptl/sem_trywait.c> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 02eda45067..9ad6d2252b 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -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 diff --git a/sysdeps/unix/sysv/linux/aarch64/sigaction.c b/sysdeps/unix/sysv/linux/aarch64/sigaction.c index 7dabe4689b..ae6c3fde25 100644 --- a/sysdeps/unix/sysv/linux/aarch64/sigaction.c +++ b/sysdeps/unix/sysv/linux/aarch64/sigaction.c @@ -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> diff --git a/sysdeps/unix/sysv/linux/aio_misc.h b/sysdeps/unix/sysv/linux/aio_misc.h new file mode 100644 index 0000000000..58ac45153f --- /dev/null +++ b/sysdeps/unix/sysv/linux/aio_misc.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2004-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _AIO_MISC_H +# include_next <aio_misc.h> +# include <limits.h> +# include <pthread.h> +# include <signal.h> +# include <sysdep.h> + +# define aio_start_notify_thread __aio_start_notify_thread +# define aio_create_helper_thread __aio_create_helper_thread + +extern inline void +__aio_start_notify_thread (void) +{ + sigset_t ss; + sigemptyset (&ss); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8); +} + +extern inline int +__aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *), + void *arg) +{ + pthread_attr_t attr; + + /* Make sure the thread is created detached. */ + pthread_attr_init (&attr); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + /* The helper thread needs only very little resources. */ + (void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr)); + + /* Block all signals in the helper thread. To do this thoroughly we + temporarily have to block all signals here. */ + sigset_t ss; + sigset_t oss; + sigfillset (&ss); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8); + + int ret = pthread_create (threadp, &attr, tf, arg); + + /* Restore the signal mask. */ + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL, + _NSIG / 8); + + (void) pthread_attr_destroy (&attr); + return ret; +} +#endif diff --git a/sysdeps/unix/sysv/linux/allocrtsig.c b/sysdeps/unix/sysv/linux/allocrtsig.c new file mode 100644 index 0000000000..0ed7d089c6 --- /dev/null +++ b/sysdeps/unix/sysv/linux/allocrtsig.c @@ -0,0 +1,55 @@ +/* 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/>. */ + +#include <signal.h> + + +static int current_rtmin = __SIGRTMIN + 2; +static int current_rtmax = __SIGRTMAX; + + +/* We reserve __SIGRTMIN for use as the cancelation signal. This + signal is used internally. */ +int +__libc_current_sigrtmin (void) +{ + return current_rtmin; +} +libc_hidden_def (__libc_current_sigrtmin) +strong_alias (__libc_current_sigrtmin, __libc_current_sigrtmin_private) + + +int +__libc_current_sigrtmax (void) +{ + return current_rtmax; +} +libc_hidden_def (__libc_current_sigrtmax) +strong_alias (__libc_current_sigrtmax, __libc_current_sigrtmax_private) + + +int +__libc_allocate_rtsig (int high) +{ + if (current_rtmin == -1 || current_rtmin > current_rtmax) + /* We don't have anymore signal available. */ + return -1; + + return high ? current_rtmin++ : current_rtmax--; +} +strong_alias (__libc_allocate_rtsig, __libc_allocate_rtsig_private) diff --git a/sysdeps/unix/sysv/linux/alpha/sem_post.c b/sysdeps/unix/sysv/linux/alpha/sem_post.c index befa49723b..9d4495312e 100644 --- a/sysdeps/unix/sysv/linux/alpha/sem_post.c +++ b/sysdeps/unix/sysv/linux/alpha/sem_post.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> diff --git a/sysdeps/unix/sysv/linux/arm/sigaction.c b/sysdeps/unix/sysv/linux/arm/sigaction.c index 24a2774f8b..8bd2adf7d5 100644 --- a/sysdeps/unix/sysv/linux/arm/sigaction.c +++ b/sysdeps/unix/sysv/linux/arm/sigaction.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> diff --git a/sysdeps/unix/sysv/linux/getpid.c b/sysdeps/unix/sysv/linux/getpid.c new file mode 100644 index 0000000000..937b1d4e11 --- /dev/null +++ b/sysdeps/unix/sysv/linux/getpid.c @@ -0,0 +1,64 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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 <unistd.h> +#include <tls.h> +#include <sysdep.h> + + +#ifndef NOT_IN_libc +static inline __attribute__((always_inline)) pid_t really_getpid (pid_t oldval); + +static inline __attribute__((always_inline)) pid_t +really_getpid (pid_t oldval) +{ + if (__glibc_likely (oldval == 0)) + { + pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid); + if (__glibc_likely (selftid != 0)) + return selftid; + } + + INTERNAL_SYSCALL_DECL (err); + pid_t result = INTERNAL_SYSCALL (getpid, err, 0); + + /* We do not set the PID field in the TID here since we might be + called from a signal handler while the thread executes fork. */ + if (oldval == 0) + THREAD_SETMEM (THREAD_SELF, tid, result); + return result; +} +#endif + +pid_t +__getpid (void) +{ +#ifdef NOT_IN_libc + INTERNAL_SYSCALL_DECL (err); + pid_t result = INTERNAL_SYSCALL (getpid, err, 0); +#else + pid_t result = THREAD_GETMEM (THREAD_SELF, pid); + if (__glibc_unlikely (result <= 0)) + result = really_getpid (result); +#endif + return result; +} + +libc_hidden_def (__getpid) +weak_alias (__getpid, getpid) +libc_hidden_def (getpid) diff --git a/sysdeps/unix/sysv/linux/i386/sigaction.c b/sysdeps/unix/sysv/linux/i386/sigaction.c index 778037aee8..b0e71057ad 100644 --- a/sysdeps/unix/sysv/linux/i386/sigaction.c +++ b/sysdeps/unix/sysv/linux/i386/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 diff --git a/sysdeps/unix/sysv/linux/ia64/sigaction.c b/sysdeps/unix/sysv/linux/ia64/sigaction.c index 97f7f499be..2033f11a45 100644 --- a/sysdeps/unix/sysv/linux/ia64/sigaction.c +++ b/sysdeps/unix/sysv/linux/ia64/sigaction.c @@ -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> diff --git a/sysdeps/unix/sysv/linux/kernel-posix-timers.h b/sysdeps/unix/sysv/linux/kernel-posix-timers.h new file mode 100644 index 0000000000..532da55e14 --- /dev/null +++ b/sysdeps/unix/sysv/linux/kernel-posix-timers.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <setjmp.h> +#include <signal.h> +#include <sys/types.h> + + +/* Nonzero if the system calls are not available. */ +extern int __no_posix_timers attribute_hidden; + +/* Callback to start helper thread. */ +extern void __start_helper_thread (void) attribute_hidden; + +/* Control variable for helper thread creation. */ +extern pthread_once_t __helper_once attribute_hidden; + +/* TID of the helper thread. */ +extern pid_t __helper_tid attribute_hidden; + +/* List of active SIGEV_THREAD timers. */ +extern struct timer *__active_timer_sigev_thread attribute_hidden; +/* Lock for the __active_timer_sigev_thread. */ +extern pthread_mutex_t __active_timer_sigev_thread_lock attribute_hidden; + + +/* Type of timers in the kernel. */ +typedef int kernel_timer_t; + + +/* Internal representation of timer. */ +struct timer +{ + /* Notification mechanism. */ + int sigev_notify; + + /* Timer ID returned by the kernel. */ + kernel_timer_t ktimerid; + + /* All new elements must be added after ktimerid. And if the thrfunc + element is not the third element anymore the memory allocation in + timer_create needs to be changed. */ + + /* Parameters for the thread to be started for SIGEV_THREAD. */ + void (*thrfunc) (sigval_t); + sigval_t sival; + pthread_attr_t attr; + + /* Next element in list of active SIGEV_THREAD timers. */ + struct timer *next; +}; diff --git a/sysdeps/unix/sysv/linux/mips/sigaction.c b/sysdeps/unix/sysv/linux/mips/sigaction.c index 6b808a6cdf..90b1a3b13d 100644 --- a/sysdeps/unix/sysv/linux/mips/sigaction.c +++ b/sysdeps/unix/sysv/linux/mips/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 diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c index a61839f507..d50a9f2d57 100644 --- a/sysdeps/unix/sysv/linux/mq_notify.c +++ b/sysdeps/unix/sysv/linux/mq_notify.c @@ -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 diff --git a/sysdeps/unix/sysv/linux/ia64/fork.S b/sysdeps/unix/sysv/linux/pt-raise.c index 496d0b7eff..fc26e858b3 100644 --- a/sysdeps/unix/sysv/linux/ia64/fork.S +++ b/sysdeps/unix/sysv/linux/pt-raise.c @@ -1,5 +1,6 @@ -/* Copyright (C) 2000-2014 Free Software Foundation, Inc. +/* 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 @@ -15,26 +16,23 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ - +#include <errno.h> +#include <signal.h> #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) +#include <tls.h> + + +int +raise (sig) + int sig; +{ + /* raise is an async-safe function. It could be called while the + fork function temporarily invalidated the PID field. Adjust for + that. */ + pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); + if (__glibc_unlikely (pid < 0)) + pid = -pid; + + return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid), + sig); +} diff --git a/sysdeps/unix/sysv/linux/pthread_getaffinity.c b/sysdeps/unix/sysv/linux/pthread_getaffinity.c new file mode 100644 index 0000000000..f58e9cc3e9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pthread_getaffinity.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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 <errno.h> +#include <limits.h> +#include <pthreadP.h> +#include <string.h> +#include <sysdep.h> +#include <sys/param.h> +#include <sys/types.h> +#include <shlib-compat.h> + + +int +__pthread_getaffinity_new (pthread_t th, size_t cpusetsize, cpu_set_t *cpuset) +{ + const struct pthread *pd = (const struct pthread *) th; + + INTERNAL_SYSCALL_DECL (err); + int res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, pd->tid, + MIN (INT_MAX, cpusetsize), cpuset); + if (INTERNAL_SYSCALL_ERROR_P (res, err)) + return INTERNAL_SYSCALL_ERRNO (res, err); + + /* Clean the rest of the memory the kernel didn't do. */ + memset ((char *) cpuset + res, '\0', cpusetsize - res); + + return 0; +} +strong_alias (__pthread_getaffinity_new, __pthread_getaffinity_np) +versioned_symbol (libpthread, __pthread_getaffinity_new, + pthread_getaffinity_np, GLIBC_2_3_4); + + +#if SHLIB_COMPAT (libpthread, GLIBC_2_3_3, GLIBC_2_3_4) +int +__pthread_getaffinity_old (pthread_t th, cpu_set_t *cpuset) +{ + /* The old interface by default assumed a 1024 processor bitmap. */ + return __pthread_getaffinity_new (th, 128, cpuset); +} +compat_symbol (libpthread, __pthread_getaffinity_old, pthread_getaffinity_np, + GLIBC_2_3_3); +#endif diff --git a/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c b/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c new file mode 100644 index 0000000000..3e634a03c8 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c @@ -0,0 +1,44 @@ +/* pthread_getcpuclockid -- Get POSIX clockid_t for a pthread_t. Linux version + 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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthreadP.h> +#include <sys/time.h> +#include <tls.h> +#include <kernel-posix-cpu-timers.h> + + +int +pthread_getcpuclockid (threadid, clockid) + pthread_t threadid; + clockid_t *clockid; +{ + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + /* The clockid_t value is a simple computation from the TID. */ + + const clockid_t tidclock = MAKE_THREAD_CPUCLOCK (pd->tid, CPUCLOCK_SCHED); + + *clockid = tidclock; + return 0; +} diff --git a/sysdeps/unix/sysv/linux/pthread_getname.c b/sysdeps/unix/sysv/linux/pthread_getname.c new file mode 100644 index 0000000000..e5a319a3e1 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pthread_getname.c @@ -0,0 +1,72 @@ +/* pthread_getname_np -- Get thread name. Linux version + Copyright (C) 2010-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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <pthreadP.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/prctl.h> + +#include <not-cancel.h> + + +int +pthread_getname_np (th, buf, len) + pthread_t th; + char *buf; + size_t len; +{ + const struct pthread *pd = (const struct pthread *) th; + + /* Unfortunately the kernel headers do not export the TASK_COMM_LEN + macro. So we have to define it here. */ +#define TASK_COMM_LEN 16 + if (len < TASK_COMM_LEN) + return ERANGE; + + if (pd == THREAD_SELF) + return prctl (PR_GET_NAME, buf) ? errno : 0; + +#define FMT "/proc/self/task/%u/comm" + char fname[sizeof (FMT) + 8]; + sprintf (fname, FMT, (unsigned int) pd->tid); + + int fd = open_not_cancel_2 (fname, O_RDONLY); + if (fd == -1) + return errno; + + int res = 0; + ssize_t n = TEMP_FAILURE_RETRY (read_not_cancel (fd, buf, len)); + if (n < 0) + res = errno; + else + { + if (buf[n - 1] == '\n') + buf[n - 1] = '\0'; + else if (n == len) + res = ERANGE; + else + buf[n] = '\0'; + } + + close_not_cancel_no_status (fd); + + return res; +} diff --git a/sysdeps/unix/sysv/linux/pthread_kill.c b/sysdeps/unix/sysv/linux/pthread_kill.c new file mode 100644 index 0000000000..0a4d8627a9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pthread_kill.c @@ -0,0 +1,66 @@ +/* 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/>. */ + +#include <errno.h> +#include <signal.h> +#include <pthreadP.h> +#include <tls.h> +#include <sysdep.h> + + +int +__pthread_kill (threadid, signo) + pthread_t threadid; + int signo; +{ + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (DEBUGGING_P && INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Force load of pd->tid into local variable or register. Otherwise + if a thread exits between ESRCH test and tgkill, we might return + EINVAL, because pd->tid would be cleared by the kernel. */ + pid_t tid = atomic_forced_read (pd->tid); + if (__glibc_unlikely (tid <= 0)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Disallow sending the signal we use for cancellation, timers, + for the setxid implementation. */ + if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) + return EINVAL; + + /* We have a special syscall to do the work. */ + INTERNAL_SYSCALL_DECL (err); + + /* One comment: The PID field in the TCB can temporarily be changed + (in fork). But this must not affect this code here. Since this + function would have to be called while the thread is executing + fork, it would have to happen in a signal handler. But this is + no allowed, pthread_kill is not guaranteed to be async-safe. */ + int val; + val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), + tid, signo); + + return (INTERNAL_SYSCALL_ERROR_P (val, err) + ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); +} +strong_alias (__pthread_kill, pthread_kill) diff --git a/sysdeps/unix/sysv/linux/pthread_setaffinity.c b/sysdeps/unix/sysv/linux/pthread_setaffinity.c new file mode 100644 index 0000000000..874cf4b578 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pthread_setaffinity.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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 <alloca.h> +#include <errno.h> +#include <pthreadP.h> +#include <sysdep.h> +#include <sys/types.h> +#include <shlib-compat.h> + + +size_t __kernel_cpumask_size attribute_hidden; + + +/* Determine the current affinity. As a side affect we learn + about the size of the cpumask_t in the kernel. */ +int +__determine_cpumask_size (pid_t tid) +{ + INTERNAL_SYSCALL_DECL (err); + int res; + + size_t psize = 128; + void *p = alloca (psize); + + while (res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, tid, psize, p), + INTERNAL_SYSCALL_ERROR_P (res, err) + && INTERNAL_SYSCALL_ERRNO (res, err) == EINVAL) + p = extend_alloca (p, psize, 2 * psize); + + if (res == 0 || INTERNAL_SYSCALL_ERROR_P (res, err)) + return INTERNAL_SYSCALL_ERRNO (res, err); + + __kernel_cpumask_size = res; + + return 0; +} + + +int +__pthread_setaffinity_new (pthread_t th, size_t cpusetsize, + const cpu_set_t *cpuset) +{ + const struct pthread *pd = (const struct pthread *) th; + + INTERNAL_SYSCALL_DECL (err); + int res; + + if (__glibc_unlikely (__kernel_cpumask_size == 0)) + { + res = __determine_cpumask_size (pd->tid); + if (res != 0) + return res; + } + + /* We now know the size of the kernel cpumask_t. Make sure the user + does not request to set a bit beyond that. */ + for (size_t cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt) + if (((char *) cpuset)[cnt] != '\0') + /* Found a nonzero byte. This means the user request cannot be + fulfilled. */ + return EINVAL; + + res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, cpusetsize, + cpuset); + +#ifdef RESET_VGETCPU_CACHE + if (!INTERNAL_SYSCALL_ERROR_P (res, err)) + RESET_VGETCPU_CACHE (); +#endif + + return (INTERNAL_SYSCALL_ERROR_P (res, err) + ? INTERNAL_SYSCALL_ERRNO (res, err) + : 0); +} +versioned_symbol (libpthread, __pthread_setaffinity_new, + pthread_setaffinity_np, GLIBC_2_3_4); + + +#if SHLIB_COMPAT (libpthread, GLIBC_2_3_3, GLIBC_2_3_4) +int +__pthread_setaffinity_old (pthread_t th, cpu_set_t *cpuset) +{ + /* The old interface by default assumed a 1024 processor bitmap. */ + return __pthread_setaffinity_new (th, 128, cpuset); +} +compat_symbol (libpthread, __pthread_setaffinity_old, pthread_setaffinity_np, + GLIBC_2_3_3); +#endif diff --git a/sysdeps/unix/sysv/linux/pthread_setname.c b/sysdeps/unix/sysv/linux/pthread_setname.c new file mode 100644 index 0000000000..409560e586 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pthread_setname.c @@ -0,0 +1,65 @@ +/* pthread_setname_np -- Set thread name. Linux version + Copyright (C) 2010-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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <pthreadP.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/prctl.h> + +#include <not-cancel.h> + + +int +pthread_setname_np (th, name) + pthread_t th; + const char *name; +{ + const struct pthread *pd = (const struct pthread *) th; + + /* Unfortunately the kernel headers do not export the TASK_COMM_LEN + macro. So we have to define it here. */ +#define TASK_COMM_LEN 16 + size_t name_len = strlen (name); + if (name_len >= TASK_COMM_LEN) + return ERANGE; + + if (pd == THREAD_SELF) + return prctl (PR_SET_NAME, name) ? errno : 0; + +#define FMT "/proc/self/task/%u/comm" + char fname[sizeof (FMT) + 8]; + sprintf (fname, FMT, (unsigned int) pd->tid); + + int fd = open_not_cancel_2 (fname, O_RDWR); + if (fd == -1) + return errno; + + int res = 0; + ssize_t n = TEMP_FAILURE_RETRY (write_not_cancel (fd, name, name_len)); + if (n < 0) + res = errno; + else if (n != name_len) + res = EIO; + + close_not_cancel_no_status (fd); + + return res; +} diff --git a/sysdeps/unix/sysv/linux/pthread_sigqueue.c b/sysdeps/unix/sysv/linux/pthread_sigqueue.c new file mode 100644 index 0000000000..1e66815416 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pthread_sigqueue.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2009-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. + + 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 <errno.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <pthreadP.h> +#include <tls.h> +#include <sysdep.h> + + +int +pthread_sigqueue (threadid, signo, value) + pthread_t threadid; + int signo; + const union sigval value; +{ +#ifdef __NR_rt_tgsigqueueinfo + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (DEBUGGING_P && INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Force load of pd->tid into local variable or register. Otherwise + if a thread exits between ESRCH test and tgkill, we might return + EINVAL, because pd->tid would be cleared by the kernel. */ + pid_t tid = atomic_forced_read (pd->tid); + if (__glibc_unlikely (tid <= 0)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Disallow sending the signal we use for cancellation, timers, + for the setxid implementation. */ + if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) + return EINVAL; + + /* Set up the siginfo_t structure. */ + siginfo_t info; + memset (&info, '\0', sizeof (siginfo_t)); + info.si_signo = signo; + info.si_code = SI_QUEUE; + info.si_pid = THREAD_GETMEM (THREAD_SELF, pid); + info.si_uid = getuid (); + info.si_value = value; + + /* We have a special syscall to do the work. */ + INTERNAL_SYSCALL_DECL (err); + + /* One comment: The PID field in the TCB can temporarily be changed + (in fork). But this must not affect this code here. Since this + function would have to be called while the thread is executing + fork, it would have to happen in a signal handler. But this is + no allowed, pthread_sigqueue is not guaranteed to be async-safe. */ + int val = INTERNAL_SYSCALL (rt_tgsigqueueinfo, err, 4, + THREAD_GETMEM (THREAD_SELF, pid), + tid, signo, &info); + + return (INTERNAL_SYSCALL_ERROR_P (val, err) + ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); +#else + return ENOSYS; +#endif +} diff --git a/sysdeps/unix/sysv/linux/raise.c b/sysdeps/unix/sysv/linux/raise.c new file mode 100644 index 0000000000..4106e8c458 --- /dev/null +++ b/sysdeps/unix/sysv/linux/raise.c @@ -0,0 +1,58 @@ +/* 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/>. */ + +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <sysdep.h> +#include <nptl/pthreadP.h> + + +int +raise (sig) + int sig; +{ + struct pthread *pd = THREAD_SELF; + pid_t pid = THREAD_GETMEM (pd, pid); + pid_t selftid = THREAD_GETMEM (pd, tid); + if (selftid == 0) + { + /* This system call is not supposed to fail. */ +#ifdef INTERNAL_SYSCALL + INTERNAL_SYSCALL_DECL (err); + selftid = INTERNAL_SYSCALL (gettid, err, 0); +#else + selftid = INLINE_SYSCALL (gettid, 0); +#endif + THREAD_SETMEM (pd, tid, selftid); + + /* We do not set the PID field in the TID here since we might be + called from a signal handler while the thread executes fork. */ + pid = selftid; + } + else + /* raise is an async-safe function. It could be called while the + fork/vfork function temporarily invalidated the PID field. Adjust for + that. */ + if (__glibc_unlikely (pid <= 0)) + pid = (pid & INT_MAX) == 0 ? selftid : -pid; + + return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); +} +libc_hidden_def (raise) +weak_alias (raise, gsignal) diff --git a/sysdeps/unix/sysv/linux/s390/jmp-unwind.c b/sysdeps/unix/sysv/linux/s390/jmp-unwind.c index f35eab5ac1..32226bc593 100644 --- a/sysdeps/unix/sysv/linux/s390/jmp-unwind.c +++ b/sysdeps/unix/sysv/linux/s390/jmp-unwind.c @@ -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 diff --git a/sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c b/sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c index 6fc0f969ef..aa6cf9a79e 100644 --- a/sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c +++ b/sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c @@ -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> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c b/sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c index e9a984b5af..995afbc2fc 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c +++ b/sysdeps/unix/sysv/linux/s390/s390-64/sigaction.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> diff --git a/sysdeps/unix/sysv/linux/sigaction.c b/sysdeps/unix/sysv/linux/sigaction.c index eaa517577f..c8694c17e3 100644 --- a/sysdeps/unix/sysv/linux/sigaction.c +++ b/sysdeps/unix/sysv/linux/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> diff --git a/sysdeps/unix/sysv/linux/sigtimedwait.c b/sysdeps/unix/sysv/linux/sigtimedwait.c index 5491b480ea..c7727cf4c6 100644 --- a/sysdeps/unix/sysv/linux/sigtimedwait.c +++ b/sysdeps/unix/sysv/linux/sigtimedwait.c @@ -19,6 +19,7 @@ #include <signal.h> #include <string.h> +#include <nptl/pthreadP.h> #include <sysdep-cancel.h> #include <sys/syscall.h> diff --git a/sysdeps/unix/sysv/linux/sigwait.c b/sysdeps/unix/sysv/linux/sigwait.c index 26528227e6..b7ac868bb5 100644 --- a/sysdeps/unix/sysv/linux/sigwait.c +++ b/sysdeps/unix/sysv/linux/sigwait.c @@ -21,6 +21,7 @@ #include <stddef.h> #include <string.h> +#include <nptl/pthreadP.h> #include <sysdep-cancel.h> #include <sys/syscall.h> diff --git a/sysdeps/unix/sysv/linux/sigwaitinfo.c b/sysdeps/unix/sysv/linux/sigwaitinfo.c index 9218afc551..fa9b0b73db 100644 --- a/sysdeps/unix/sysv/linux/sigwaitinfo.c +++ b/sysdeps/unix/sysv/linux/sigwaitinfo.c @@ -21,6 +21,7 @@ #include <stddef.h> #include <string.h> +#include <nptl/pthreadP.h> #include <sysdep-cancel.h> #include <sys/syscall.h> diff --git a/sysdeps/unix/sysv/linux/sleep.c b/sysdeps/unix/sysv/linux/sleep.c index 3b352c68bc..5411fd5e98 100644 --- a/sysdeps/unix/sysv/linux/sleep.c +++ b/sysdeps/unix/sysv/linux/sleep.c @@ -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 diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c b/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c index 5e8cf69800..a54d532c85 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c @@ -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) diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c b/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c index 665e658cf9..514dabfe50 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c @@ -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) diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list index 2e6cf9c60d..d639d63cf9 100644 --- a/sysdeps/unix/sysv/linux/syscalls.list +++ b/sysdeps/unix/sysv/linux/syscalls.list @@ -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 diff --git a/sysdeps/unix/sysv/linux/timer_create.c b/sysdeps/unix/sysv/linux/timer_create.c new file mode 100644 index 0000000000..e5c056bf2c --- /dev/null +++ b/sysdeps/unix/sysv/linux/timer_create.c @@ -0,0 +1,179 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sysdep.h> +#include <internaltypes.h> +#include <nptl/pthreadP.h> +#include "kernel-posix-timers.h" +#include "kernel-posix-cpu-timers.h" + + +#ifdef timer_create_alias +# define timer_create timer_create_alias +#endif + + +int +timer_create (clock_id, evp, timerid) + clockid_t clock_id; + struct sigevent *evp; + timer_t *timerid; +{ +#undef timer_create + { + clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID + ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED) + : clock_id == CLOCK_THREAD_CPUTIME_ID + ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED) + : clock_id); + + /* If the user wants notification via a thread we need to handle + this special. */ + if (evp == NULL + || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1)) + { + struct sigevent local_evp; + + /* We avoid allocating too much memory by basically + using struct timer as a derived class with the + first two elements being in the superclass. We only + need these two elements here. */ + struct timer *newp = (struct timer *) malloc (offsetof (struct timer, + thrfunc)); + if (newp == NULL) + /* No more memory. */ + return -1; + + if (evp == NULL) + { + /* The kernel has to pass up the timer ID which is a + userlevel object. Therefore we cannot leave it up to + the kernel to determine it. */ + local_evp.sigev_notify = SIGEV_SIGNAL; + local_evp.sigev_signo = SIGALRM; + local_evp.sigev_value.sival_ptr = newp; + + evp = &local_evp; + } + + kernel_timer_t ktimerid; + int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp, + &ktimerid); + + if (retval != -1) + { + newp->sigev_notify = (evp != NULL + ? evp->sigev_notify : SIGEV_SIGNAL); + newp->ktimerid = ktimerid; + + *timerid = (timer_t) newp; + } + else + { + /* Cannot allocate the timer, fail. */ + free (newp); + retval = -1; + } + + return retval; + } + else + { + /* Create the helper thread. */ + pthread_once (&__helper_once, __start_helper_thread); + if (__helper_tid == 0) + { + /* No resources to start the helper thread. */ + __set_errno (EAGAIN); + return -1; + } + + struct timer *newp; + newp = (struct timer *) malloc (sizeof (struct timer)); + if (newp == NULL) + return -1; + + /* Copy the thread parameters the user provided. */ + newp->sival = evp->sigev_value; + newp->thrfunc = evp->sigev_notify_function; + newp->sigev_notify = SIGEV_THREAD; + + /* We cannot simply copy the thread attributes since the + implementation might keep internal information for + each instance. */ + (void) pthread_attr_init (&newp->attr); + if (evp->sigev_notify_attributes != NULL) + { + struct pthread_attr *nattr; + struct pthread_attr *oattr; + + nattr = (struct pthread_attr *) &newp->attr; + oattr = (struct pthread_attr *) evp->sigev_notify_attributes; + + nattr->schedparam = oattr->schedparam; + nattr->schedpolicy = oattr->schedpolicy; + nattr->flags = oattr->flags; + nattr->guardsize = oattr->guardsize; + nattr->stackaddr = oattr->stackaddr; + nattr->stacksize = oattr->stacksize; + } + + /* In any case set the detach flag. */ + (void) pthread_attr_setdetachstate (&newp->attr, + PTHREAD_CREATE_DETACHED); + + /* Create the event structure for the kernel timer. */ + struct sigevent sev = + { .sigev_value.sival_ptr = newp, + .sigev_signo = SIGTIMER, + .sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID, + ._sigev_un = { ._pad = { [0] = __helper_tid } } }; + + /* Create the timer. */ + INTERNAL_SYSCALL_DECL (err); + int res; + res = INTERNAL_SYSCALL (timer_create, err, 3, + syscall_clockid, &sev, &newp->ktimerid); + if (! INTERNAL_SYSCALL_ERROR_P (res, err)) + { + /* Add to the queue of active timers with thread + delivery. */ + pthread_mutex_lock (&__active_timer_sigev_thread_lock); + newp->next = __active_timer_sigev_thread; + __active_timer_sigev_thread = newp; + pthread_mutex_unlock (&__active_timer_sigev_thread_lock); + + *timerid = (timer_t) newp; + return 0; + } + + /* Free the resources. */ + free (newp); + + __set_errno (INTERNAL_SYSCALL_ERRNO (res, err)); + + return -1; + } + } +} diff --git a/sysdeps/unix/sysv/linux/timer_delete.c b/sysdeps/unix/sysv/linux/timer_delete.c new file mode 100644 index 0000000000..1de81236e2 --- /dev/null +++ b/sysdeps/unix/sysv/linux/timer_delete.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include "kernel-posix-timers.h" + + +#ifdef timer_delete_alias +# define timer_delete timer_delete_alias +#endif + + +int +timer_delete (timerid) + timer_t timerid; +{ +#undef timer_delete + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_delete, 1, kt->ktimerid); + + if (res == 0) + { + if (kt->sigev_notify == SIGEV_THREAD) + { + /* Remove the timer from the list. */ + pthread_mutex_lock (&__active_timer_sigev_thread_lock); + if (__active_timer_sigev_thread == kt) + __active_timer_sigev_thread = kt->next; + else + { + struct timer *prevp = __active_timer_sigev_thread; + while (prevp->next != NULL) + if (prevp->next == kt) + { + prevp->next = kt->next; + break; + } + else + prevp = prevp->next; + } + pthread_mutex_unlock (&__active_timer_sigev_thread_lock); + } + + /* Free the memory. */ + (void) free (kt); + + return 0; + } + + /* The kernel timer is not known or something else bad happened. + Return the error. */ + return -1; +} diff --git a/sysdeps/unix/sysv/linux/timer_getoverr.c b/sysdeps/unix/sysv/linux/timer_getoverr.c new file mode 100644 index 0000000000..0ac394114e --- /dev/null +++ b/sysdeps/unix/sysv/linux/timer_getoverr.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <time.h> +#include <sysdep.h> +#include "kernel-posix-timers.h" + + +#ifdef timer_getoverrun_alias +# define timer_getoverrun timer_getoverrun_alias +#endif + + +int +timer_getoverrun (timerid) + timer_t timerid; +{ +#undef timer_getoverrun + struct timer *kt = (struct timer *) timerid; + + /* Get the information from the kernel. */ + int res = INLINE_SYSCALL (timer_getoverrun, 1, kt->ktimerid); + + return res; +} diff --git a/sysdeps/unix/sysv/linux/timer_gettime.c b/sysdeps/unix/sysv/linux/timer_gettime.c new file mode 100644 index 0000000000..7783034a76 --- /dev/null +++ b/sysdeps/unix/sysv/linux/timer_gettime.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include "kernel-posix-timers.h" + + +#ifdef timer_gettime_alias +# define timer_gettime timer_gettime_alias +#endif + + +int +timer_gettime (timerid, value) + timer_t timerid; + struct itimerspec *value; +{ +#undef timer_gettime + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, value); + + return res; +} diff --git a/sysdeps/unix/sysv/linux/timer_routines.c b/sysdeps/unix/sysv/linux/timer_routines.c new file mode 100644 index 0000000000..4ac9bbe896 --- /dev/null +++ b/sysdeps/unix/sysv/linux/timer_routines.c @@ -0,0 +1,196 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <setjmp.h> +#include <signal.h> +#include <stdbool.h> +#include <sysdep.h> +#include <nptl/pthreadP.h> +#include "kernel-posix-timers.h" + + +/* List of active SIGEV_THREAD timers. */ +struct timer *__active_timer_sigev_thread; +/* Lock for the __active_timer_sigev_thread. */ +pthread_mutex_t __active_timer_sigev_thread_lock = PTHREAD_MUTEX_INITIALIZER; + + +struct thread_start_data +{ + void (*thrfunc) (sigval_t); + sigval_t sival; +}; + + +/* Helper thread to call the user-provided function. */ +static void * +timer_sigev_thread (void *arg) +{ + /* The parent thread has all signals blocked. This is a bit + surprising for user code, although valid. We unblock all + signals. */ + sigset_t ss; + sigemptyset (&ss); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8); + + struct thread_start_data *td = (struct thread_start_data *) arg; + + void (*thrfunc) (sigval_t) = td->thrfunc; + sigval_t sival = td->sival; + + /* The TD object was allocated in timer_helper_thread. */ + free (td); + + /* Call the user-provided function. */ + thrfunc (sival); + + return NULL; +} + + +/* Helper function to support starting threads for SIGEV_THREAD. */ +static void * +timer_helper_thread (void *arg) +{ + /* Wait for the SIGTIMER signal, allowing the setXid signal, and + none else. */ + sigset_t ss; + sigemptyset (&ss); + __sigaddset (&ss, SIGTIMER); + + /* Endless loop of waiting for signals. The loop is only ended when + the thread is canceled. */ + while (1) + { + siginfo_t si; + + /* sigwaitinfo cannot be used here, since it deletes + SIGCANCEL == SIGTIMER from the set. */ + + int oldtype = LIBC_CANCEL_ASYNC (); + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = INLINE_SYSCALL (rt_sigtimedwait, 4, &ss, &si, NULL, + _NSIG / 8); + + LIBC_CANCEL_RESET (oldtype); + + if (result > 0) + { + if (si.si_code == SI_TIMER) + { + struct timer *tk = (struct timer *) si.si_ptr; + + /* Check the timer is still used and will not go away + while we are reading the values here. */ + pthread_mutex_lock (&__active_timer_sigev_thread_lock); + + struct timer *runp = __active_timer_sigev_thread; + while (runp != NULL) + if (runp == tk) + break; + else + runp = runp->next; + + if (runp != NULL) + { + struct thread_start_data *td = malloc (sizeof (*td)); + + /* There is not much we can do if the allocation fails. */ + if (td != NULL) + { + /* This is the signal we are waiting for. */ + td->thrfunc = tk->thrfunc; + td->sival = tk->sival; + + pthread_t th; + (void) pthread_create (&th, &tk->attr, + timer_sigev_thread, td); + } + } + + pthread_mutex_unlock (&__active_timer_sigev_thread_lock); + } + else if (si.si_code == SI_TKILL) + /* The thread is canceled. */ + pthread_exit (NULL); + } + } +} + + +/* Control variable for helper thread creation. */ +pthread_once_t __helper_once attribute_hidden; + + +/* TID of the helper thread. */ +pid_t __helper_tid attribute_hidden; + + +/* Reset variables so that after a fork a new helper thread gets started. */ +static void +reset_helper_control (void) +{ + __helper_once = PTHREAD_ONCE_INIT; + __helper_tid = 0; +} + + +void +attribute_hidden +__start_helper_thread (void) +{ + /* The helper thread needs only very little resources + and should go away automatically when canceled. */ + pthread_attr_t attr; + (void) pthread_attr_init (&attr); + (void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr)); + + /* Block all signals in the helper thread but SIGSETXID. To do this + thoroughly we temporarily have to block all signals here. The + helper can lose wakeups if SIGCANCEL is not blocked throughout, + but sigfillset omits it SIGSETXID. So, we add SIGCANCEL back + explicitly here. */ + sigset_t ss; + sigset_t oss; + sigfillset (&ss); + __sigaddset (&ss, SIGCANCEL); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8); + + /* Create the helper thread for this timer. */ + pthread_t th; + int res = pthread_create (&th, &attr, timer_helper_thread, NULL); + if (res == 0) + /* We managed to start the helper thread. */ + __helper_tid = ((struct pthread *) th)->tid; + + /* Restore the signal mask. */ + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL, + _NSIG / 8); + + /* No need for the attribute anymore. */ + (void) pthread_attr_destroy (&attr); + + /* We have to make sure that after fork()ing a new helper thread can + be created. */ + pthread_atfork (NULL, NULL, reset_helper_control); +} diff --git a/sysdeps/unix/sysv/linux/timer_settime.c b/sysdeps/unix/sysv/linux/timer_settime.c new file mode 100644 index 0000000000..f7f7c91c51 --- /dev/null +++ b/sysdeps/unix/sysv/linux/timer_settime.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include "kernel-posix-timers.h" + + +#ifdef timer_settime_alias +# define timer_settime timer_settime_alias +#endif + + +int +timer_settime (timerid, flags, value, ovalue) + timer_t timerid; + int flags; + const struct itimerspec *value; + struct itimerspec *ovalue; +{ +#undef timer_settime + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_settime, 4, kt->ktimerid, flags, + value, ovalue); + + return res; +} diff --git a/sysdeps/unix/sysv/linux/tst-setgetname.c b/sysdeps/unix/sysv/linux/tst-setgetname.c new file mode 100644 index 0000000000..f5693e26c4 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-setgetname.c @@ -0,0 +1,315 @@ +/* Test pthread_setname_np and pthread_getname_np. + Copyright (C) 2013-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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <string.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <kernel-features.h> + +/* New name of process. */ +#define NEW_NAME "setname" + +/* Name of process which is one byte too big + e.g. 17 bytes including null-terminator */ +#define BIG_NAME "....V....X....XV" + +/* Longest name of a process + e.g. 16 bytes including null-terminator. */ +#define LONGEST_NAME "....V....X....X" + +/* One less than longest name with unique + characters to detect modification. */ +#define CANARY_NAME "abcdefghijklmn" + +/* On Linux the maximum length of the name of a task *including* the null + terminator. */ +#define TASK_COMM_LEN 16 + +long +gettid (void) +{ + return syscall(__NR_gettid); +} + +/* On Linux we can read this task's name from /proc. */ +int +get_self_comm (long tid, char *buf, size_t len) +{ + int res = 0; +#define FMT "/proc/self/task/%lu/comm" + char fname[sizeof (FMT) + 8]; + sprintf (fname, FMT, (unsigned long) tid); + + int fd = open (fname, O_RDONLY); + if (fd == -1) + return errno; + + ssize_t n = read (fd, (void *) buf, len); + if (n < 0) + res = errno; + else + { + if (buf[n - 1] == '\n') + buf[n - 1] = '\0'; + else if (n == len) + res = ERANGE; + else + buf[n] = '\0'; + } + + close (fd); + return res; +} + +int +do_test (int argc, char **argv) +{ + pthread_t self; + int res; + int ret = 0; + char name[TASK_COMM_LEN]; + char name_check[TASK_COMM_LEN]; + + memset (name, '\0', TASK_COMM_LEN); + memset (name_check, '\0', TASK_COMM_LEN); + + /* Test 1: Get the name of the task via pthread_getname_np and /proc + and verify that they both match. */ + self = pthread_self (); + res = pthread_getname_np (self, name, TASK_COMM_LEN); + + if (res == 0) + { + res = get_self_comm (gettid (), name_check, TASK_COMM_LEN); + +#if !__ASSUME_PROC_PID_TASK_COMM + /* On this first test we look for ENOENT to be returned from + get_self_comm to indicate that the kernel is older than + 2.6.33 and doesn't contain comm within the proc structure. + In that case we skip the entire test. */ + if (res == ENOENT) + { + printf ("SKIP: The kernel does not have /proc/self/task/%%lu/comm.\n"); + return 0; + } +#endif + + if (res == 0) + { + if (strncmp (name, name_check, strlen (BIG_NAME)) == 0) + printf ("PASS: Test 1 - pthread_getname_np and /proc agree.\n"); + else + { + printf ("FAIL: Test 1 - pthread_getname_np and /proc differ" + " i.e. %s != %s\n", name, name_check); + ret++; + } + } + else + { + printf ("FAIL: Test 1 - unable read task name via proc.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 1 - pthread_getname_np failed with error %d\n", res); + ret++; + } + + /* Test 2: Test setting the name and then independently verify it + was set. */ + res = pthread_setname_np (self, NEW_NAME); + + if (res == 0) + { + res = get_self_comm (gettid (), name_check, TASK_COMM_LEN); + if (res == 0) + { + if (strncmp (NEW_NAME, name_check, strlen (BIG_NAME)) == 0) + printf ("PASS: Test 2 - Value used in pthread_setname_np and" + " /proc agree.\n"); + else + { + printf ("FAIL: Test 2 - Value used in pthread_setname_np" + " and /proc differ i.e. %s != %s\n", + NEW_NAME, name_check); + ret++; + } + } + else + { + printf ("FAIL: Test 2 - unable to read task name via proc.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 2 - pthread_setname_np failed with error %d\n", res); + ret++; + } + + /* Test 3: Test setting a name that is one-byte too big. */ + res = pthread_getname_np (self, name, TASK_COMM_LEN); + + if (res == 0) + { + res = pthread_setname_np (self, BIG_NAME); + if (res != 0) + { + if (res == ERANGE) + { + printf ("PASS: Test 3 - pthread_setname_np returned ERANGE" + " for a process name that was too long.\n"); + + /* Verify the old name didn't change. */ + res = get_self_comm (gettid (), name_check, TASK_COMM_LEN); + if (res == 0) + { + if (strncmp (name, name_check, strlen (BIG_NAME)) == 0) + printf ("PASS: Test 3 - Original name unchanged after" + " pthread_setname_np returned ERANGE.\n"); + else + { + printf ("FAIL: Test 3 - Original name changed after" + " pthread_setname_np returned ERANGE" + " i.e. %s != %s\n", + name, name_check); + ret++; + } + } + else + { + printf ("FAIL: Test 3 - unable to read task name.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 3 - Wrong error returned" + " i.e. ERANGE != %d\n", res); + ret++; + } + } + else + { + printf ("FAIL: Test 3 - Too-long name accepted by" + " pthread_setname_np.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 3 - Unable to get original name.\n"); + ret++; + } + + /* Test 4: Verify that setting the longest name works. */ + res = pthread_setname_np (self, LONGEST_NAME); + + if (res == 0) + { + res = get_self_comm (gettid (), name_check, TASK_COMM_LEN); + if (res == 0) + { + if (strncmp (LONGEST_NAME, name_check, strlen (BIG_NAME)) == 0) + printf ("PASS: Test 4 - Longest name set via pthread_setname_np" + " agrees with /proc.\n"); + else + { + printf ("FAIL: Test 4 - Value used in pthread_setname_np and /proc" + " differ i.e. %s != %s\n", LONGEST_NAME, name_check); + ret++; + } + } + else + { + printf ("FAIL: Test 4 - unable to read task name via proc.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 4 - pthread_setname_np failed with error %d\n", res); + ret++; + } + + /* Test 5: Verify that getting a long name into a small buffer fails. */ + strncpy (name, CANARY_NAME, strlen (CANARY_NAME) + 1); + + /* Claim the buffer length is strlen (LONGEST_NAME). This is one character + too small to hold LONGEST_NAME *and* the null terminator. We should get + back ERANGE and name should be unmodified. */ + res = pthread_getname_np (self, name, strlen (LONGEST_NAME)); + + if (res != 0) + { + if (res == ERANGE) + { + if (strncmp (CANARY_NAME, name, strlen (BIG_NAME)) == 0) + { + printf ("PASS: Test 5 - ERANGE and buffer unmodified.\n"); + } + else + { + printf ("FAIL: Test 5 - Original buffer modified.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 5 - Did not return ERANGE for small buffer.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 5 - Returned name longer than buffer.\n"); + ret++; + } + + /* Test 6: Lastly make sure we can read back the longest name. */ + res = pthread_getname_np (self, name, strlen (LONGEST_NAME) + 1); + + if (res == 0) + { + if (strncmp (LONGEST_NAME, name, strlen (BIG_NAME)) == 0) + { + printf ("PASS: Test 6 - Read back longest name correctly.\n"); + } + else + { + printf ("FAIL: Test 6 - Read \"%s\" instead of longest name.\n", + name); + ret++; + } + } + else + { + printf ("FAIL: Test 6 - pthread_getname_np failed with error %d\n", res); + ret++; + } + + return ret; +} + +#include <test-skeleton.c> diff --git a/sysdeps/unix/sysv/linux/x86/pthread_mutex_cond_lock.c b/sysdeps/unix/sysv/linux/x86/pthread_mutex_cond_lock.c index 34c705235a..8d215915df 100644 --- a/sysdeps/unix/sysv/linux/x86/pthread_mutex_cond_lock.c +++ b/sysdeps/unix/sysv/linux/x86/pthread_mutex_cond_lock.c @@ -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> diff --git a/sysdeps/unix/sysv/linux/x86_64/sigaction.c b/sysdeps/unix/sysv/linux/x86_64/sigaction.c index 6735b70c10..53a8134b6a 100644 --- a/sysdeps/unix/sysv/linux/x86_64/sigaction.c +++ b/sysdeps/unix/sysv/linux/x86_64/sigaction.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 - -#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 |