summaryrefslogtreecommitdiffstats
path: root/libpthread/nptl/sysdeps/unix/sysv/linux
diff options
context:
space:
mode:
author"Steven J. Hill" <sjhill@realitydiluted.com>2005-12-08 05:06:40 +0000
committer"Steven J. Hill" <sjhill@realitydiluted.com>2005-12-08 05:06:40 +0000
commit5a8bec270e2da338c8dbc1786a7cdaa3077cb5ff (patch)
tree79ad89ebad4b2e4c1dcd61603217cfd77c5f8b24 /libpthread/nptl/sysdeps/unix/sysv/linux
parent99aa495ff35864383680f9773b3cb44040acca08 (diff)
downloaduClibc-alpine-5a8bec270e2da338c8dbc1786a7cdaa3077cb5ff.tar.bz2
uClibc-alpine-5a8bec270e2da338c8dbc1786a7cdaa3077cb5ff.tar.xz
Bring in new functions for NPTL. These are actually from glibc out of
the 'sysdeps/unix/sysv/linux' directory, but including the 'pthreadP.h' header to activate NPTL-specific code.
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux')
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c90
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c107
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c90
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c152
4 files changed, 431 insertions, 8 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c
index 8560e8b40..5159bf9b8 100644
--- a/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c
@@ -1,2 +1,88 @@
-#include <nptl/pthreadP.h>
-#include "../../../../../sysdeps/unix/sysv/linux/sigtimedwait.c"
+/* Copyright (C) 1997,1998,2000,2002,2003,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 <pthreadP.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+#include <sysdep-cancel.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_rt_sigtimedwait
+
+static int
+do_sigtimedwait (const sigset_t *set, siginfo_t *info,
+ const struct timespec *timeout)
+{
+#ifdef SIGCANCEL
+ sigset_t tmpset;
+ if (set != NULL
+ && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+ || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+ ))
+ {
+ /* Create a temporary mask without the bit for SIGCANCEL set. */
+ // We are not copying more than we have to.
+ memcpy (&tmpset, set, _NSIG / 8);
+ __sigdelset (&tmpset, SIGCANCEL);
+# ifdef SIGSETXID
+ __sigdelset (&tmpset, SIGSETXID);
+# endif
+ set = &tmpset;
+ }
+#endif
+
+ /* 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, set,
+ info, timeout, _NSIG / 8);
+
+ /* The kernel generates a SI_TKILL code in si_code in case tkill is
+ used. tkill is transparently used in raise(). Since having
+ SI_TKILL as a code is useful in general we fold the results
+ here. */
+ if (result != -1 && info != NULL && info->si_code == SI_TKILL)
+ info->si_code = SI_USER;
+
+ return result;
+}
+
+
+/* Return any pending signal or wait for one for the given time. */
+int attribute_hidden
+__sigtimedwait (const sigset_t *set, siginfo_t *info,
+ const struct timespec *timeout)
+{
+ if (SINGLE_THREAD_P)
+ return do_sigtimedwait (set, info, timeout);
+
+ 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 = do_sigtimedwait (set, info, timeout);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+}
+weak_alias (__sigtimedwait, sigtimedwait)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c
index c358bfbee..51d1829c3 100644
--- a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c
@@ -1,2 +1,105 @@
-#include <nptl/pthreadP.h>
-#include "../../../../../sysdeps/unix/sysv/linux/sigwait.c"
+/* Copyright (C) 1997,1998,2000,2002-2004,2005 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 <pthreadP.h>
+#include <errno.h>
+#include <signal.h>
+#define __need_NULL
+#include <stddef.h>
+#include <string.h>
+
+#include <sysdep-cancel.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_rt_sigtimedwait
+
+/* Return any pending signal or wait for one for the given time. */
+static int
+do_sigwait (const sigset_t *set, int *sig)
+{
+ int ret;
+
+#ifdef SIGCANCEL
+ sigset_t tmpset;
+ if (set != NULL
+ && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+ || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+ ))
+ {
+ /* Create a temporary mask without the bit for SIGCANCEL set. */
+ // We are not copying more than we have to.
+ memcpy (&tmpset, set, _NSIG / 8);
+ __sigdelset (&tmpset, SIGCANCEL);
+# ifdef SIGSETXID
+ __sigdelset (&tmpset, SIGSETXID);
+# endif
+ set = &tmpset;
+ }
+#endif
+
+ /* XXX The size argument hopefully will have to be changed to the
+ real size of the user-level sigset_t. */
+#ifdef INTERNAL_SYSCALL
+ INTERNAL_SYSCALL_DECL (err);
+ do
+ ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, set,
+ NULL, NULL, _NSIG / 8);
+ while (INTERNAL_SYSCALL_ERROR_P (ret, err)
+ && INTERNAL_SYSCALL_ERRNO (ret, err) == EINTR);
+ if (! INTERNAL_SYSCALL_ERROR_P (ret, err))
+ {
+ *sig = ret;
+ ret = 0;
+ }
+ else
+ ret = INTERNAL_SYSCALL_ERRNO (ret, err);
+#else
+ do
+ ret = INLINE_SYSCALL (rt_sigtimedwait, 4, set,
+ NULL, NULL, _NSIG / 8);
+ while (ret == -1 && errno == EINTR);
+ if (ret != -1)
+ {
+ *sig = ret;
+ ret = 0;
+ }
+ else
+ ret = errno;
+#endif
+
+ return ret;
+}
+
+int attribute_hidden
+__sigwait (const sigset_t *set, int *sig)
+{
+ if (SINGLE_THREAD_P)
+ return do_sigwait (set, sig);
+
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+ int result = do_sigwait (set, sig);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+}
+weak_alias (__sigwait, sigwait)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c
index a4f9fe8f5..4342cedf1 100644
--- a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c
@@ -1,2 +1,88 @@
-#include <nptl/pthreadP.h>
-#include "../../../../../sysdeps/unix/sysv/linux/sigwaitinfo.c"
+/* Copyright (C) 1997,1998,2000,2002,2003,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 <pthreadP.h>
+#include <errno.h>
+#include <signal.h>
+#define __need_NULL
+#include <stddef.h>
+#include <string.h>
+
+#include <sysdep-cancel.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_rt_sigtimedwait
+
+static int
+do_sigwaitinfo (const sigset_t *set, siginfo_t *info)
+{
+#ifdef SIGCANCEL
+ sigset_t tmpset;
+ if (set != NULL
+ && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+ || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+ ))
+ {
+ /* Create a temporary mask without the bit for SIGCANCEL set. */
+ // We are not copying more than we have to.
+ memcpy (&tmpset, set, _NSIG / 8);
+ __sigdelset (&tmpset, SIGCANCEL);
+# ifdef SIGSETXID
+ __sigdelset (&tmpset, SIGSETXID);
+# endif
+ set = &tmpset;
+ }
+#endif
+
+ /* 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, set,
+ info, NULL, _NSIG / 8);
+
+ /* The kernel generates a SI_TKILL code in si_code in case tkill is
+ used. tkill is transparently used in raise(). Since having
+ SI_TKILL as a code is useful in general we fold the results
+ here. */
+ if (result != -1 && info != NULL && info->si_code == SI_TKILL)
+ info->si_code = SI_USER;
+
+ return result;
+}
+
+
+/* Return any pending signal or wait for one for the given time. */
+int attribute_hidden
+__sigwaitinfo (const sigset_t *set, siginfo_t *info)
+{
+ if (SINGLE_THREAD_P)
+ return do_sigwaitinfo (set, info);
+
+ 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 = do_sigwaitinfo (set, info);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+}
+weak_alias (__sigwaitinfo, sigwaitinfo)
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c
index c56b49b39..579b00be3 100644
--- a/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c
@@ -1,2 +1,150 @@
-#include <nptl/pthreadP.h>
-#include <sysdeps/unix/sysv/linux/sleep.c>
+/* Implementation of the POSIX sleep function using nanosleep.
+ Copyright (C) 1996,1997,1998,1999,2003,2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+ 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 <pthreadP.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <string.h> /* For the real memset prototype. */
+#include <unistd.h>
+#include <sys/param.h>
+
+
+#if 0
+static void
+cl (void *arg)
+{
+ (void) __sigprocmask (SIG_SETMASK, arg, (sigset_t *) NULL);
+}
+#endif
+
+
+/* We are going to use the `nanosleep' syscall of the kernel. But the
+ kernel does not implement the stupid SysV SIGCHLD vs. SIG_IGN
+ behaviour for this syscall. Therefore we have to emulate it here. */
+unsigned int
+__sleep (unsigned int seconds)
+{
+ const unsigned int max
+ = (unsigned int) (((unsigned long int) (~((time_t) 0))) >> 1);
+ struct timespec ts;
+ sigset_t set, oset;
+ unsigned int result;
+
+ /* This is not necessary but some buggy programs depend on this. */
+ if (__builtin_expect (seconds == 0, 0))
+ {
+#ifdef CANCELLATION_P
+ CANCELLATION_P (THREAD_SELF);
+#endif
+ return 0;
+ }
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ again:
+ if (sizeof (ts.tv_sec) <= sizeof (seconds))
+ {
+ /* Since SECONDS is unsigned assigning the value to .tv_sec can
+ overflow it. In this case we have to wait in steps. */
+ ts.tv_sec += MIN (seconds, max);
+ seconds -= (unsigned int) ts.tv_sec;
+ }
+ else
+ {
+ ts.tv_sec = (time_t) seconds;
+ seconds = 0;
+ }
+
+ /* Linux will wake up the system call, nanosleep, when SIGCHLD
+ arrives even if SIGCHLD is ignored. We have to deal with it
+ in libc. We block SIGCHLD first. */
+ __sigemptyset (&set);
+ __sigaddset (&set, SIGCHLD);
+ if (__sigprocmask (SIG_BLOCK, &set, &oset))
+ return -1;
+
+ /* If SIGCHLD is already blocked, we don't have to do anything. */
+ if (!__sigismember (&oset, SIGCHLD))
+ {
+ int saved_errno;
+ struct sigaction oact;
+
+ __sigemptyset (&set);
+ __sigaddset (&set, SIGCHLD);
+
+ /* We get the signal handler for SIGCHLD. */
+ if (sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0)
+ {
+ saved_errno = errno;
+ /* Restore the original signal mask. */
+ (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
+ __set_errno (saved_errno);
+ return -1;
+ }
+
+ /* Note the sleep() is a cancellation point. But since we call
+ nanosleep() which itself is a cancellation point we do not
+ have to do anything here. */
+ if (oact.sa_handler == SIG_IGN)
+ {
+ //__libc_cleanup_push (cl, &oset);
+
+ /* We should leave SIGCHLD blocked. */
+ while (1)
+ {
+ result = nanosleep (&ts, &ts);
+
+ if (result != 0 || seconds == 0)
+ break;
+
+ if (sizeof (ts.tv_sec) <= sizeof (seconds))
+ {
+ ts.tv_sec = MIN (seconds, max);
+ seconds -= (unsigned int) ts.tv_nsec;
+ }
+ }
+
+ //__libc_cleanup_pop (0);
+
+ saved_errno = errno;
+ /* Restore the original signal mask. */
+ (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
+ __set_errno (saved_errno);
+
+ goto out;
+ }
+
+ /* We should unblock SIGCHLD. Restore the original signal mask. */
+ (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
+ }
+
+ result = nanosleep (&ts, &ts);
+ if (result == 0 && seconds != 0)
+ goto again;
+
+ out:
+ if (result != 0)
+ /* Round remaining time. */
+ result = seconds + (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);
+
+ return result;
+}
+weak_alias (__sleep, sleep)