diff options
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv')
19 files changed, 1327 insertions, 259 deletions
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/unix/sysv/linux/hp-timing.h b/libpthread/nptl/sysdeps/unix/sysv/linux/hp-timing.h deleted file mode 100644 index 099342db8..000000000 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/hp-timing.h +++ /dev/null @@ -1,83 +0,0 @@ -/* High precision, low overhead timing functions. Generic version. - Copyright (C) 1998, 2000 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. - - 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. */ - -#ifndef _HP_TIMING_H -#define _HP_TIMING_H 1 - - -/* There are no generic definitions for the times. We could write something - using the `gettimeofday' system call where available but the overhead of - the system call might be too high. - - In case a platform supports timers in the hardware the following macros - and types must be defined: - - - HP_TIMING_AVAIL: test for availability. - - - HP_TIMING_INLINE: this macro is non-zero if the functionality is not - implemented using function calls but instead uses some inlined code - which might simply consist of a few assembler instructions. We have to - know this since we might want to use the macros here in places where we - cannot make function calls. - - - hp_timing_t: This is the type for variables used to store the time - values. - - - HP_TIMING_ZERO: clear `hp_timing_t' object. - - - HP_TIMING_NOW: place timestamp for current time in variable given as - parameter. - - - HP_TIMING_DIFF_INIT: do whatever is necessary to be able to use the - HP_TIMING_DIFF macro. - - - HP_TIMING_DIFF: compute difference between two times and store it - in a third. Source and destination might overlap. - - - HP_TIMING_ACCUM: add time difference to another variable. This might - be a bit more complicated to implement for some platforms as the - operation should be thread-safe and 64bit arithmetic on 32bit platforms - is not. - - - HP_TIMING_ACCUM_NT: this is the variant for situations where we know - there are no threads involved. - - - HP_TIMING_PRINT: write decimal representation of the timing value into - the given string. This operation need not be inline even though - HP_TIMING_INLINE is specified. - -*/ - -/* Provide dummy definitions. */ -#define HP_TIMING_AVAIL (0) -#define HP_TIMING_INLINE (0) -typedef int hp_timing_t; -#define HP_TIMING_ZERO(Var) -#define HP_TIMING_NOW(var) -#define HP_TIMING_DIFF_INIT() -#define HP_TIMING_DIFF(Diff, Start, End) -#define HP_TIMING_ACCUM(Sum, Diff) -#define HP_TIMING_ACCUM_NT(Sum, Diff) -#define HP_TIMING_PRINT(Buf, Len, Val) - -/* Since this implementation is not available we tell the user about it. */ -#define HP_TIMING_NONAVAIL 1 - -#endif /* hp-timing.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c index 3a5c1cde2..c435eff30 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/libc-lowlevellock.c +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c @@ -1,6 +1,6 @@ -/* Copyright (C) 2003 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 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 @@ -9,7 +9,7 @@ The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public @@ -17,5 +17,23 @@ 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" +#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 +# 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); +} 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/linux_fsinfo.h b/libpthread/nptl/sysdeps/unix/sysv/linux/linux_fsinfo.h deleted file mode 100644 index 13c385626..000000000 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/linux_fsinfo.h +++ /dev/null @@ -1,153 +0,0 @@ -/* Constants from kernel header for various FSes. - Copyright (C) 1998,1999,2000,2001,2002,2003 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. */ - -#ifndef _LINUX_FSINFO_H -#define _LINUX_FSINFO_H 1 - -/* These definitions come from the kernel headers. But we cannot - include the headers here because of type clashes. If new - filesystem types will become available we have to add the - appropriate definitions here.*/ - -/* Constants that identify the `adfs' filesystem. */ -#define ADFS_SUPER_MAGIC 0xadf5 - -/* Constants that identify the `affs' filesystem. */ -#define AFFS_SUPER_MAGIC 0xadff - -/* Constants that identify the `autofs' filesystem. */ -#define AUTOFS_SUPER_MAGIC 0x187 - -/* Constants that identify the `bfs' filesystem. */ -#define BFS_MAGIC 0x1BADFACE - -/* Constants that identify the `coda' filesystem. */ -#define CODA_SUPER_MAGIC 0x73757245 - -/* Constants that identify the `coherent' filesystem. */ -#define COH_SUPER_MAGIC 0x012ff7b7 - -/* Constant that identifies the `ramfs' filesystem. */ -#define CRAMFS_MAGIC 0x28cd3d45 - -/* Constant that identifies the `devfs' filesystem. */ -#define DEVFS_SUPER_MAGIC 0x1373 - -/* Constant that identifies the `devpts' filesystem. */ -#define DEVPTS_SUPER_MAGIC 0x1cd1 - -/* Constant that identifies the `efs' filesystem. */ -#define EFS_SUPER_MAGIC 0x414A53 -#define EFS_MAGIC 0x072959 - -/* Constant that identifies the `ext2' and `ext3' filesystems. */ -#define EXT2_SUPER_MAGIC 0xef53 - -/* Constant that identifies the `hpfs' filesystem. */ -#define HPFS_SUPER_MAGIC 0xf995e849 - -/* Constant that identifies the `iso9660' filesystem. */ -#define ISOFS_SUPER_MAGIC 0x9660 - -/* Constant that identifies the `jffs' filesystem. */ -#define JFFS_SUPER_MAGIC 0x07c0 - -/* Constant that identifies the `jffs2' filesystem. */ -#define JFFS2_SUPER_MAGIC 0x72b6 - -/* Constant that identifies the `jfs' filesystem. */ -#define JFS_SUPER_MAGIC 0x3153464a - -/* Constants that identify the `minix2' filesystem. */ -#define MINIX2_SUPER_MAGIC 0x2468 -#define MINIX2_SUPER_MAGIC2 0x2478 - -/* Constants that identify the `minix' filesystem. */ -#define MINIX_SUPER_MAGIC 0x137f -#define MINIX_SUPER_MAGIC2 0x138F - -/* Constants that identify the `msdos' filesystem. */ -#define MSDOS_SUPER_MAGIC 0x4d44 - -/* Constants that identify the `ncp' filesystem. */ -#define NCP_SUPER_MAGIC 0x564c - -/* Constants that identify the `nfs' filesystem. */ -#define NFS_SUPER_MAGIC 0x6969 - -/* Constants that identify the `ntfs' filesystem. */ -#define NTFS_SUPER_MAGIC 0x5346544e - -/* Constants that identify the `proc' filesystem. */ -#define PROC_SUPER_MAGIC 0x9fa0 - -/* Constant that identifies the `usbdevfs' filesystem. */ -#define USBDEVFS_SUPER_MAGIC 0x9fa2 - -/* Constants that identify the `qnx4' filesystem. */ -#define QNX4_SUPER_MAGIC 0x002f - -/* Constants that identify the `reiser' filesystem. */ -#define REISERFS_SUPER_MAGIC 0x52654973 - -/* Constant that identifies the `romfs' filesystem. */ -#define ROMFS_SUPER_MAGIC 0x7275 - -/* Constants that identify the `smb' filesystem. */ -#define SMB_SUPER_MAGIC 0x517b - -/* Constants that identify the `sysV' filesystem. */ -#define SYSV2_SUPER_MAGIC 0x012ff7b6 -#define SYSV4_SUPER_MAGIC 0x012ff7b5 - -/* Constants that identify the `udf' filesystem. */ -#define UDF_SUPER_MAGIC 0x15013346 - -/* Constants that identify the `ufs' filesystem. */ -#define UFS_MAGIC 0x00011954 -#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */ - -/* Constants that identify the `xenix' filesystem. */ -#define XENIX_SUPER_MAGIC 0x012ff7b4 - -/* Constant that identifies the `shm' filesystem. */ -#define SHMFS_SUPER_MAGIC 0x01021994 - -/* Constants that identify the `xfs' filesystem. */ -#define XFS_SUPER_MAGIC 0x58465342 - -/* Constants that identify the `vxfs' filesystem. */ -#define VXFS_SUPER_MAGIC 0xa501fcf5 - -/* Maximum link counts. */ -#define COH_LINK_MAX 10000 -#define EXT2_LINK_MAX 32000 -#define MINIX2_LINK_MAX 65530 -#define MINIX_LINK_MAX 250 -#define REISERFS_LINK_MAX 64535 -#define SYSV_LINK_MAX 126 /* 127? 251? */ -#define UFS_LINK_MAX EXT2_LINK_MAX -#define XENIX_LINK_MAX 126 /* ?? */ -#define XFS_LINK_MAX 2147483647 - -/* The Linux kernel header mentioned this as a kind of generic value. */ -#define LINUX_LINK_MAX 127 - - -#endif /* linux_fsinfo.h */ 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/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 |