diff options
Diffstat (limited to 'libpthread')
26 files changed, 1501 insertions, 199 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/linux_fsinfo.h b/libpthread/nptl/linux_fsinfo.h index 13c385626..13c385626 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/linux_fsinfo.h +++ b/libpthread/nptl/linux_fsinfo.h diff --git a/libpthread/nptl/sysdeps/pthread/funlockfile.c b/libpthread/nptl/pthread_kill_other_threads.c index f941fc985..09401aab5 100644 --- a/libpthread/nptl/sysdeps/pthread/funlockfile.c +++ b/libpthread/nptl/pthread_kill_other_threads.c @@ -17,17 +17,16 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <pthread.h> -#include <stdio.h> -#include <libio.h> -#include <bits/stdio-lock.h> - +#ifdef SHARED +/* This function does not serve a useful purpose in the thread library + implementation anymore. It used to be necessary when then kernel + could not shut down "processes" but this is not the case anymore. + We could theoretically provide an equivalent implementation but + this is not necessary since the kernel already does a much better + job than we ever could. */ void -__funlockfile (stream) - FILE *stream; +__pthread_kill_other_threads_np (void) { - _IO_lock_unlock (*stream->_lock); } -strong_alias (__funlockfile, _IO_funlockfile) -weak_alias (__funlockfile, funlockfile) +#endif diff --git a/libpthread/nptl/sysdeps/generic/dl-minimal.c b/libpthread/nptl/sysdeps/generic/dl-minimal.c deleted file mode 100644 index 02968a91c..000000000 --- a/libpthread/nptl/sysdeps/generic/dl-minimal.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Minimal replacements for basic facilities used in the dynamic linker. - Copyright (C) 1995-1998,2000-2002,2004 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, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -//#include <errno.h> -#include <limits.h> -#include <string.h> -#include <tls.h> -//#include <unistd.h> -#include <sys/param.h> -#include <sys/types.h> -#include <ldsodefs.h> - -/* Minimal `malloc' allocator for use while loading shared libraries. - No block is ever freed. */ - -static void *alloc_ptr, *alloc_end, *alloc_last_block; - -/* Declarations of global functions. */ -extern void weak_function free (void *ptr); -extern void * weak_function realloc (void *ptr, size_t n); - -/* Allocate an aligned memory block. */ -void * weak_function -memalign (size_t align, size_t n) -{ -#ifdef MAP_ANON -#define _dl_zerofd (-1) -#else - extern int _dl_zerofd; - - if (_dl_zerofd == -1) - _dl_zerofd = _dl_sysdep_open_zero_fill (); -#define MAP_ANON 0 -#endif - - if (alloc_end == 0) - { - /* Consume any unused space in the last page of our data segment. */ - extern int _end attribute_hidden; - alloc_ptr = &_end; - alloc_end = (void *) 0 + (((alloc_ptr - (void *) 0) - + GLRO(dl_pagesize) - 1) - & ~(GLRO(dl_pagesize) - 1)); - } - - /* Make sure the allocation pointer is ideally aligned. */ - alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + align - 1) - & ~(align - 1)); - - if (alloc_ptr + n >= alloc_end) - { - /* Insufficient space left; allocate another page. */ - caddr_t page; - size_t nup = (n + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1); - page = _dl_mmap (0, nup, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0); - if (_dl_mmap_check_error(page)) - return -1; - if (page != alloc_end) - alloc_ptr = page; - alloc_end = page + nup; - } - - alloc_last_block = (void *) alloc_ptr; - alloc_ptr += n; - return alloc_last_block; -} - -void * weak_function -malloc (size_t n) -{ - return memalign (sizeof (double), n); -} - -/* We use this function occasionally since the real implementation may - be optimized when it can assume the memory it returns already is - set to NUL. */ -void * weak_function -calloc (size_t nmemb, size_t size) -{ - /* New memory from the trivial malloc above is always already cleared. - (We make sure that's true in the rare occasion it might not be, - by clearing memory in free, below.) */ - return malloc (nmemb * size); -} - -/* This will rarely be called. */ -void weak_function -free (void *ptr) -{ - /* We can free only the last block allocated. */ - if (ptr == alloc_last_block) - { - /* Since this is rare, we clear the freed block here - so that calloc can presume malloc returns cleared memory. */ - _dl_memset (alloc_last_block, '\0', alloc_ptr - alloc_last_block); - alloc_ptr = alloc_last_block; - } -} - -/* This is only called with the most recent block returned by malloc. */ -void * weak_function -realloc (void *ptr, size_t n) -{ - void *new; - if (ptr == NULL) - return malloc (n); - assert (ptr == alloc_last_block); - alloc_ptr = alloc_last_block; - new = malloc (n); - assert (new == ptr); - return new; -} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/hp-timing.h b/libpthread/nptl/sysdeps/generic/hp-timing.h index 099342db8..099342db8 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/hp-timing.h +++ b/libpthread/nptl/sysdeps/generic/hp-timing.h diff --git a/libpthread/nptl/sysdeps/pthread/flockfile.c b/libpthread/nptl/sysdeps/generic/pt-raise.c index 918cb84f6..59d9590e6 100644 --- a/libpthread/nptl/sysdeps/pthread/flockfile.c +++ b/libpthread/nptl/sysdeps/generic/pt-raise.c @@ -18,16 +18,13 @@ 02111-1307 USA. */ #include <pthread.h> -#include <stdio.h> -#include <libio.h> -#include <bits/stdio-lock.h> +#include <signal.h> -void -__flockfile (stream) - FILE *stream; +int +raise (sig) + int sig; { - _IO_lock_lock (*stream->_lock); + /* This is what POSIX says must happen. */ + return pthread_kill (pthread_self (), sig); } -strong_alias (__flockfile, _IO_flockfile) -weak_alias (__flockfile, flockfile) diff --git a/libpthread/nptl/sysdeps/mips/pt-raise.c b/libpthread/nptl/sysdeps/mips/pt-raise.c new file mode 100644 index 000000000..251067fd1 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pt-raise.c @@ -0,0 +1 @@ +#include <../generic/pt-raise.c> diff --git a/libpthread/nptl/sysdeps/pthread/defs.awk b/libpthread/nptl/sysdeps/pthread/defs.awk new file mode 100644 index 000000000..763c2e57d --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/defs.awk @@ -0,0 +1,26 @@ +/^[ ]*\.endp/ { need_endp = 1 } +/^[ ]*\.end/ { need_end = 1 } +/^[ ]*\.align/ { if($2 > max) max = $2; } + +END { + if(need_endp) + { + print "#define END_INIT .endp _init"; + print "#define END_FINI .endp _fini"; + } else if(need_end) + { + print "#define END_INIT .end _init"; + print "#define END_FINI .end _fini"; + } + else + { + print "#define END_INIT"; + print "#define END_FINI"; + } + if(max) + print "#define ALIGN .align", max; + else + print "#define ALIGN"; + + print "#include <libc-symbols.h>"; +} diff --git a/libpthread/nptl/sysdeps/pthread/pt-initfini.s b/libpthread/nptl/sysdeps/pthread/pt-initfini.s new file mode 100644 index 000000000..d8e3a7316 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pt-initfini.s @@ -0,0 +1,137 @@ + .file 1 "pt-initfini.c" + .section .mdebug.abi32 + .previous + .abicalls +#APP + +#include "defs.h" + +/*@HEADER_ENDS*/ + +/*@TESTS_BEGIN*/ +#NO_APP + .text + .align 2 + .globl dummy + .type dummy, @function +dummy: + .set noreorder + .set nomacro + + beq $4,$0,$L6 + move $25,$4 + + jr $25 + nop + +$L6: + j $31 + nop + + .set macro + .set reorder +#APP + +/*@TESTS_END*/ + +/*@_init_PROLOG_BEGINS*/ +#NO_APP + .align 2 + .type call_initialize_minimal, @function +call_initialize_minimal: + .set noreorder + .cpload $25 + .set nomacro + + lw $25,%call16(__pthread_initialize_minimal_internal)($28) + nop + jr $25 + nop + + .set macro + .set reorder +#APP + .section .init +#NO_APP + .align 2 + .globl _init + .type _init, @function +_init: + .set noreorder + .cpload $25 + .set reorder + addiu $sp,$sp,-32 + sw $31,24($sp) + .cprestore 16 + lw $25,%got(call_initialize_minimal)($28) + #nop + addiu $25,$25,%lo(call_initialize_minimal) + jalr $25 + lw $28,16($sp) +#APP + ALIGN + END_INIT + +/*@_init_PROLOG_ENDS*/ + +/*@_init_EPILOG_BEGINS*/ + .section .init +#NO_APP + lw $31,24($sp) + #nop + .set noreorder + .set nomacro + j $31 + addiu $sp,$sp,32 + .set macro + .set reorder + +#APP + END_INIT + +/*@_init_EPILOG_ENDS*/ + +/*@_fini_PROLOG_BEGINS*/ + .section .fini +#NO_APP + .align 2 + .globl _fini + .type _fini, @function +_fini: + .set noreorder + .cpload $25 + .set reorder + addiu $sp,$sp,-32 + sw $31,24($sp) + .cprestore 16 +#APP + ALIGN + END_FINI + +/*@_fini_PROLOG_ENDS*/ +#NO_APP + lw $25,%call16(i_am_not_a_leaf)($28) + #nop + jalr $25 + lw $28,16($sp) +#APP + +/*@_fini_EPILOG_BEGINS*/ + .section .fini +#NO_APP + lw $31,24($sp) + #nop + .set noreorder + .set nomacro + j $31 + addiu $sp,$sp,32 + .set macro + .set reorder + +#APP + END_FINI + +/*@_fini_EPILOG_ENDS*/ + +/*@TRAILER_BEGINS*/ + .ident "GCC: (GNU) 4.1.0 20050604 (experimental)" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/aio_misc.h b/libpthread/nptl/sysdeps/unix/sysv/linux/aio_misc.h new file mode 100644 index 000000000..7b0bac75f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/aio_misc.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2004 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, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _AIO_MISC_H +# include_next <aio_misc.h> +# include <signal.h> +# include <sysdep.h> +# include <pthread.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_STACK_MIN); + + /* 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/libpthread/nptl/sysdeps/unix/sysv/linux/allocrtsig.c b/libpthread/nptl/sysdeps/unix/sysv/linux/allocrtsig.c new file mode 100644 index 000000000..b37d54d65 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/allocrtsig.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2002, 2003, 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#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/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c new file mode 100644 index 000000000..98307ff21 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c @@ -0,0 +1,65 @@ +/* Copyright (C) 2003, 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#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 (__builtin_expect (oldval == 0, 1)) + { + pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid); + if (__builtin_expect (selftid != 0, 1)) + 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 (__builtin_expect (result <= 0, 0)) + result = really_getpid (result); +#endif + return result; +} + +libc_hidden_def (__getpid) +weak_alias (__getpid, getpid) +libc_hidden_def (getpid) diff --git a/libpthread/nptl/sysdeps/pthread/ftrylockfile.c b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c index 21c1ea01e..c435eff30 100644 --- a/libpthread/nptl/sysdeps/pthread/ftrylockfile.c +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c @@ -1,6 +1,6 @@ -/* Copyright (C) 2002 Free Software Foundation, Inc. +/* Clean up stack frames unwound by longjmp. Linux version. + Copyright (C) 1995, 1997, 2002, 2003 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 @@ -17,17 +17,23 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <errno.h> -#include <pthread.h> -#include <stdio.h> -#include <bits/stdio-lock.h> +#include <setjmp.h> +#include <stddef.h> +#include <pthreadP.h> +extern void __pthread_cleanup_upto (__jmp_buf env, char *targetframe); +#pragma weak __pthread_cleanup_upto -int -__ftrylockfile (stream) - FILE *stream; + +void +_longjmp_unwind (jmp_buf env, int val) { - return _IO_lock_trylock (*stream->_lock); +#ifdef SHARED +# define fptr __libc_pthread_functions.ptr___pthread_cleanup_upto +#else +# define fptr __pthread_cleanup_upto +#endif + + if (fptr != NULL) + fptr (env->__jmpbuf, CURRENT_STACK_FRAME); } -strong_alias (__ftrylockfile, _IO_ftrylockfile) -weak_alias (__ftrylockfile, ftrylockfile) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-cpu-timers.h b/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-cpu-timers.h deleted file mode 100644 index 164a90dde..000000000 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-cpu-timers.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Parameters for the Linux kernel ABI for CPU clocks. */ - -#define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3)) -#define CPUCLOCK_PERTHREAD(clock) \ - (((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0) -#define CPUCLOCK_PID_MASK 7 -#define CPUCLOCK_PERTHREAD_MASK 4 -#define CPUCLOCK_WHICH(clock) ((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK) -#define CPUCLOCK_CLOCK_MASK 3 -#define CPUCLOCK_PROF 0 -#define CPUCLOCK_VIRT 1 -#define CPUCLOCK_SCHED 2 -#define CPUCLOCK_MAX 3 - -#define MAKE_PROCESS_CPUCLOCK(pid, clock) \ - ((~(clockid_t) (pid) << 3) | (clockid_t) (clock)) -#define MAKE_THREAD_CPUCLOCK(tid, clock) \ - MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c new file mode 100644 index 000000000..e9c2b6e79 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c @@ -0,0 +1,287 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#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> + + +#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, 0); + /* No need to do more if we have no socket. */ + if (netlink_socket == -1) + return; + + /* Make sure the descriptor is closed on exec. */ + if (fcntl (netlink_socket, F_SETFD, FD_CLOEXEC) != 0) + goto errout; + } + + 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_STACK_MIN); + + /* 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) + { + errout: + 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 (__builtin_expect (netlink_socket == -1, 0)) + { + __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 (__builtin_expect (retval != 0, 0)) + free (data.attr); + + return retval; +} + +#else +# include <sysdeps/generic/mq_notify.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/libc-lowlevellock.c deleted file mode 100644 index 3a5c1cde2..000000000 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/libc-lowlevellock.c +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright (C) 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Paul Mackerras <paulus@au.ibm.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, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -/* No difference to lowlevellock.c, except we lose a couple of functions. */ -#include "../lowlevellock.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c new file mode 100644 index 000000000..28d03c383 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2002, 2003, 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <sysdep.h> +#include <nptl/pthreadP.h> +#include <kernel-features.h> + + +int +raise (sig) + int sig; +{ + struct pthread *pd = THREAD_SELF; +#if __ASSUME_TGKILL || defined __NR_tgkill + pid_t pid = THREAD_GETMEM (pd, pid); +#endif + 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); + +#if __ASSUME_TGKILL || defined __NR_tgkill + /* 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; +#endif + } +#if __ASSUME_TGKILL || defined __NR_tgkill + 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 (__builtin_expect (pid <= 0, 0)) + pid = (pid & INT_MAX) == 0 ? selftid : -pid; +#endif + +#if __ASSUME_TGKILL + return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); +#else +# ifdef __NR_tgkill + int res = INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); + if (res != -1 || errno != ENOSYS) + return res; +# endif + return INLINE_SYSCALL (tkill, 2, selftid, sig); +#endif +} +libc_hidden_def (raise) +weak_alias (raise, gsignal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c new file mode 100644 index 000000000..8560e8b40 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c @@ -0,0 +1,2 @@ +#include <nptl/pthreadP.h> +#include "../../../../../sysdeps/unix/sysv/linux/sigtimedwait.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c new file mode 100644 index 000000000..c358bfbee --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c @@ -0,0 +1,2 @@ +#include <nptl/pthreadP.h> +#include "../../../../../sysdeps/unix/sysv/linux/sigwait.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c new file mode 100644 index 000000000..a4f9fe8f5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c @@ -0,0 +1,2 @@ +#include <nptl/pthreadP.h> +#include "../../../../../sysdeps/unix/sysv/linux/sigwaitinfo.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c new file mode 100644 index 000000000..c56b49b39 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c @@ -0,0 +1,2 @@ +#include <nptl/pthreadP.h> +#include <sysdeps/unix/sysv/linux/sleep.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c new file mode 100644 index 000000000..5e9951395 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c @@ -0,0 +1,236 @@ +/* Copyright (C) 2003,2004 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, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sysdep.h> +#include <kernel-features.h> +#include <internaltypes.h> +#include <nptl/pthreadP.h> +#include "kernel-posix-timers.h" +#include "kernel-posix-cpu-timers.h" + + +#ifdef __NR_timer_create +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_create (clockid_t clock_id, struct sigevent *evp, + timer_t *timerid); +# define timer_create static compat_timer_create +# include <nptl/sysdeps/pthread/timer_create.c> +# undef timer_create + +/* Nonzero if the system calls are not available. */ +int __no_posix_timers attribute_hidden; +# endif + +# 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 +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + 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); + +# ifndef __ASSUME_POSIX_TIMERS + if (retval != -1 || errno != ENOSYS) +# endif + { +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = 1; +# endif + + 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; + } + + free (newp); + +# ifndef __ASSUME_POSIX_TIMERS + /* When we come here the syscall does not exist. Make sure we + do not try to use it again. */ + __no_posix_timers = -1; +# endif + } + else + { +# ifndef __ASSUME_POSIX_TIMERS + /* Make sure we have the necessary kernel support. */ + if (__no_posix_timers == 0) + { + INTERNAL_SYSCALL_DECL (err); + struct timespec ts; + int res; + res = INTERNAL_SYSCALL (clock_getres, err, 2, + CLOCK_REALTIME, &ts); + __no_posix_timers = (INTERNAL_SYSCALL_ERROR_P (res, err) + ? -1 : 1); + } + + if (__no_posix_timers > 0) +# endif + { + /* 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; + + /* 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; + sev.sigev_value.sival_ptr = newp; + sev.sigev_signo = SIGTIMER; + sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; + /* This is the thread ID of the helper thread. */ + sev._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)) + { + *timerid = (timer_t) newp; + return 0; + } + + /* Free the resources. */ + free (newp); + + __set_errno (INTERNAL_SYSCALL_ERRNO (res, err)); + + return -1; + } + } + } + +# ifndef __ASSUME_POSIX_TIMERS + /* Compatibility code. */ + return compat_timer_create (clock_id, evp, timerid); +# endif +} +#else +# ifdef timer_create_alias +# define timer_create timer_create_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_create.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c new file mode 100644 index 000000000..35055212a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003 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, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_delete +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_delete (timer_t timerid); +# define timer_delete static compat_timer_delete +# include <nptl/sysdeps/pthread/timer_delete.c> +# undef timer_delete +# endif + +# ifdef timer_delete_alias +# define timer_delete timer_delete_alias +# endif + + +int +timer_delete (timerid) + timer_t timerid; +{ +# undef timer_delete +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_delete, 1, kt->ktimerid); + + if (res == 0) + { +# ifndef __ASSUME_POSIX_TIMERS + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + + /* Free the memory. */ + (void) free (kt); + + return 0; + } + + /* The kernel timer is not known or something else bad happened. + Return the error. */ +# ifndef __ASSUME_POSIX_TIMERS + if (errno != ENOSYS) + { + __no_posix_timers = 1; +# endif + return -1; +# ifndef __ASSUME_POSIX_TIMERS + } + + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_delete (timerid); +# endif +} +#else +# ifdef timer_delete_alias +# define timer_delete timer_delete_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_delete.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c new file mode 100644 index 000000000..fdbdaa7c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 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, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <time.h> +#include <sysdep.h> +#include <kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_getoverrun +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_getoverrun (timer_t timerid); +# define timer_getoverrun static compat_timer_getoverrun +# include <nptl/sysdeps/pthread/timer_getoverr.c> +# undef timer_getoverrun +# endif + +# ifdef timer_getoverrun_alias +# define timer_getoverrun timer_getoverrun_alias +# endif + + +int +timer_getoverrun (timerid) + timer_t timerid; +{ +# undef timer_getoverrun +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Get the information from the kernel. */ + int res = INLINE_SYSCALL (timer_getoverrun, 1, kt->ktimerid); + +# ifndef __ASSUME_POSIX_TIMERS + if (res != -1 || errno != ENOSYS) + { + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + return res; +# ifndef __ASSUME_POSIX_TIMERS + } +# endif + +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_getoverrun (timerid); +# endif +} +#else +# ifdef timer_getoverrun_alias +# define timer_getoverrun timer_getoverrun_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_getoverr.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c new file mode 100644 index 000000000..a2fcfd1b5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2003 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, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_gettime +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_gettime (timer_t timerid, struct itimerspec *value); +# define timer_gettime static compat_timer_gettime +# include <nptl/sysdeps/pthread/timer_gettime.c> +# undef timer_gettime +# endif + +# 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 +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, value); + +# ifndef __ASSUME_POSIX_TIMERS + if (res != -1 || errno != ENOSYS) + { + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + return res; +# ifndef __ASSUME_POSIX_TIMERS + } +# endif + +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_gettime (timerid, value); +# endif +} +#else +# ifdef timer_gettime_alias +# define timer_gettime timer_gettime_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_gettime.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c new file mode 100644 index 000000000..e5214e605 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c @@ -0,0 +1,164 @@ +/* Copyright (C) 2003, 2004, 2005 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, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <setjmp.h> +#include <signal.h> +#include <stdbool.h> +#include <sysdep.h> +#include <kernel-features.h> +#include <nptl/pthreadP.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_create +/* 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 timer *tk = (struct timer *) arg; + + /* Call the user-provided function. */ + tk->thrfunc (tk->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); +#ifdef SIGSETXID + __sigaddset (&ss, SIGSETXID); +#endif + + /* 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; + + /* That the signal we are waiting for. */ + pthread_t th; + (void) pthread_create (&th, &tk->attr, timer_sigev_thread, tk); + } + 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_STACK_MIN); + + /* 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. So, we add it back explicitly here. */ + sigset_t ss; + sigset_t oss; + sigfillset (&ss); + __sigaddset (&ss, SIGCANCEL); +#ifdef SIGSETXID + __sigdelset (&ss, SIGSETXID); +#endif + 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); +} +#endif + +#ifndef __ASSUME_POSIX_TIMERS +# include <nptl/sysdeps/pthread/timer_routines.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c new file mode 100644 index 000000000..fe08080a1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2003 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, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_settime +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_settime (timer_t timerid, int flags, + const struct itimerspec *value, + struct itimerspec *ovalue); +# define timer_settime static compat_timer_settime +# include <nptl/sysdeps/pthread/timer_settime.c> +# undef timer_settime +# endif + +# 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 +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_settime, 4, kt->ktimerid, flags, + value, ovalue); + +# ifndef __ASSUME_POSIX_TIMERS + if (res != -1 || errno != ENOSYS) + { + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + return res; +# ifndef __ASSUME_POSIX_TIMERS + } +# endif + +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_settime (timerid, flags, value, ovalue); +# endif +} +#else +# ifdef timer_settime_alias +# define timer_settime timer_settime_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_settime.c> +#endif |