From 57e8823548ad6e65d33b2153edeb18fb0edc20e6 Mon Sep 17 00:00:00 2001
From: Austin Foxley <austinf@cetoncorp.com>
Date: Sat, 17 Oct 2009 14:32:36 -0700
Subject: cancellation support for a large amount of the required syscalls

Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
---
 libc/sysdeps/linux/common/__rt_sigtimedwait.c      | 100 ++++++++++++++++-----
 libc/sysdeps/linux/common/__syscall_fcntl.c        |  90 ++++++++++++++-----
 libc/sysdeps/linux/common/__syscall_rt_sigaction.c |   4 +-
 libc/sysdeps/linux/common/bits/kernel_sigaction.h  |   4 +-
 libc/sysdeps/linux/common/fsync.c                  |  27 +++++-
 libc/sysdeps/linux/common/ioctl.c                  |  30 +++++--
 libc/sysdeps/linux/common/msync.c                  |  29 ++++--
 libc/sysdeps/linux/common/nanosleep.c              |  33 +++++--
 libc/sysdeps/linux/common/open64.c                 |  19 +++-
 libc/sysdeps/linux/common/pause.c                  |  30 +++++--
 libc/sysdeps/linux/common/poll.c                   |  48 +++++-----
 libc/sysdeps/linux/common/pselect.c                |  35 +++++++-
 libc/sysdeps/linux/common/readv.c                  |  38 +++++++-
 libc/sysdeps/linux/common/select.c                 |  57 +++++++++---
 libc/sysdeps/linux/common/sigprocmask.c            |  65 +++++++++-----
 libc/sysdeps/linux/common/sigsuspend.c             |  34 +++++--
 libc/sysdeps/linux/common/wait.c                   |  34 +++++--
 libc/sysdeps/linux/common/waitpid.c                |  29 ++++--
 libc/sysdeps/linux/common/writev.c                 |  36 ++++++++
 19 files changed, 570 insertions(+), 172 deletions(-)

(limited to 'libc/sysdeps')

diff --git a/libc/sysdeps/linux/common/__rt_sigtimedwait.c b/libc/sysdeps/linux/common/__rt_sigtimedwait.c
index f9ec0eabf..554c6b9cb 100644
--- a/libc/sysdeps/linux/common/__rt_sigtimedwait.c
+++ b/libc/sysdeps/linux/common/__rt_sigtimedwait.c
@@ -2,44 +2,97 @@
 /*
  * __rt_sigtimedwait() for uClibc
  *
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
  *
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ * GNU Library General Public License (LGPL) version 2 or later.
  */
 
 #include <sys/syscall.h>
 #include <signal.h>
-#define __need_NULL
-#include <stddef.h>
+#include <string.h>
 
+libc_hidden_proto(memcpy)
 
 #ifdef __NR_rt_sigtimedwait
-#define __NR___rt_sigtimedwait __NR_rt_sigtimedwait
-static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set, siginfo_t *, info,
-		  const struct timespec *, timeout, size_t, setsize)
+#include <string.h>
+libc_hidden_proto(memcpy)
 
-int sigwaitinfo(const sigset_t * set, siginfo_t * info)
+# ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#  include <sysdep-cancel.h>
+
+static int do_sigtimedwait(const sigset_t *set, siginfo_t *info,
+						   const struct timespec *timeout)
 {
-	return __rt_sigtimedwait(set, info, NULL, _NSIG / 8);
+#  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;
 }
 
-int sigtimedwait(const sigset_t * set, siginfo_t * info,
-				 const struct timespec *timeout)
+/* Return any pending signal or wait for one for the given time.  */
+int __sigtimedwait(const sigset_t *set, siginfo_t *info,
+				   const struct timespec *timeout)
 {
-	return __rt_sigtimedwait(set, info, timeout, _NSIG / 8);
+	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;
 }
-#else
-int sigwaitinfo(const sigset_t * set, siginfo_t * info)
+# else
+#  define __need_NULL
+#  include <stddef.h>
+#  define __NR___rt_sigtimedwait __NR_rt_sigtimedwait
+static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set,
+				 siginfo_t *, info, const struct timespec *, timeout,
+				 size_t, setsize);
+
+int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info,
+									const struct timespec *timeout)
 {
-	if (set == NULL)
-		__set_errno(EINVAL);
-	else
-		__set_errno(ENOSYS);
-	return -1;
+	return __rt_sigtimedwait(set, info, timeout, _NSIG / 8);
 }
-
-int sigtimedwait(const sigset_t * set, siginfo_t * info,
-				 const struct timespec *timeout)
+# endif /* !__UCLIBC_HAS_THREADS_NATIVE__ */
+#else
+int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info,
+									const struct timespec *timeout)
 {
 	if (set == NULL)
 		__set_errno(EINVAL);
@@ -48,5 +101,4 @@ int sigtimedwait(const sigset_t * set, siginfo_t * info,
 	return -1;
 }
 #endif
-libc_hidden_def(sigwaitinfo)
-libc_hidden_def(sigtimedwait)
+weak_alias(__sigtimedwait,sigtimedwait)
diff --git a/libc/sysdeps/linux/common/__syscall_fcntl.c b/libc/sysdeps/linux/common/__syscall_fcntl.c
index 355b22b00..6a966d7df 100644
--- a/libc/sysdeps/linux/common/__syscall_fcntl.c
+++ b/libc/sysdeps/linux/common/__syscall_fcntl.c
@@ -2,6 +2,7 @@
 /*
  * __syscall_fcntl() for uClibc
  *
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
@@ -9,42 +10,83 @@
 
 #include <sys/syscall.h>
 #include <stdarg.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>	/* Must come before <fcntl.h>.  */
+#endif
 #include <fcntl.h>
 #include <bits/wordsize.h>
 
-#define __NR___syscall_fcntl __NR_fcntl
-static __always_inline
-_syscall3(int, __syscall_fcntl, int, fd, int, cmd, long, arg)
+extern __typeof(fcntl) __libc_fcntl;
+libc_hidden_proto(__libc_fcntl) 
 
-int fcntl(int fd, int cmd, ...)
-{
-	long arg;
-	va_list list;
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+int __fcntl_nocancel (int fd, int cmd, ...)
+{   
+	va_list ap;
+	void *arg;
 
-	va_start(list, cmd);
-	arg = va_arg(list, long);
-	va_end(list);
+	va_start (ap, cmd);
+	arg = va_arg (ap, void *);
+	va_end (ap);
 
-#if __WORDSIZE == 32
+# if __WORDSIZE == 32
 	if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) {
-#if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
-		return fcntl64(fd, cmd, arg);
-#else
+#  if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
+		return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+#  else
 		__set_errno(ENOSYS);
 		return -1;
-#endif
+#  endif
 	}
+# endif
+	return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+}
 #endif
 
-	return (__syscall_fcntl(fd, cmd, arg));
-}
-#ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(fcntl)
+int __libc_fcntl (int fd, int cmd, ...)
+{
+	va_list ap;
+	void *arg;
+
+	va_start (ap, cmd);
+	arg = va_arg (ap, void *);
+	va_end (ap);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	if (SINGLE_THREAD_P || (cmd != F_SETLKW && cmd != F_SETLKW64))
+# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
+		return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+# else
+		return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+# endif
+
+	int oldtype = LIBC_CANCEL_ASYNC ();
+
+# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
+	int result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+# else
+	int result = INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+# endif
+
+	LIBC_CANCEL_RESET (oldtype);
+
+	return result;
 #else
-libc_hidden_weak(fcntl)
-strong_alias(fcntl,__libc_fcntl)
+# if __WORDSIZE == 32
+	if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) {
+#  if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
+		return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+#  else
+		__set_errno(ENOSYS);
+		return -1;
+#  endif
+	}
+# endif
+	return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
 #endif
+}
+libc_hidden_def(__libc_fcntl)
 
-#if ! defined __NR_fcntl64 && defined __UCLIBC_HAS_LFS__
-strong_alias(fcntl,fcntl64)
-#endif
+libc_hidden_proto(fcntl)
+weak_alias(__libc_fcntl,fcntl)
+libc_hidden_weak(fcntl)
diff --git a/libc/sysdeps/linux/common/__syscall_rt_sigaction.c b/libc/sysdeps/linux/common/__syscall_rt_sigaction.c
index b4b007d02..006b38a2a 100644
--- a/libc/sysdeps/linux/common/__syscall_rt_sigaction.c
+++ b/libc/sysdeps/linux/common/__syscall_rt_sigaction.c
@@ -12,7 +12,9 @@
 #ifdef __NR_rt_sigaction
 #include <signal.h>
 
-int __syscall_rt_sigaction (int __signum, const struct sigaction *__act, struct sigaction *__oldact, size_t __size) attribute_hidden;
+int __syscall_rt_sigaction (int __signum, const struct sigaction *__act,
+							struct sigaction *__oldact, size_t __size);
+
 #define __NR___syscall_rt_sigaction __NR_rt_sigaction
 _syscall4(int, __syscall_rt_sigaction, int, signum,
 		  const struct sigaction *, act, struct sigaction *, oldact,
diff --git a/libc/sysdeps/linux/common/bits/kernel_sigaction.h b/libc/sysdeps/linux/common/bits/kernel_sigaction.h
index f74e0a28a..0a35ac8cb 100644
--- a/libc/sysdeps/linux/common/bits/kernel_sigaction.h
+++ b/libc/sysdeps/linux/common/bits/kernel_sigaction.h
@@ -25,12 +25,12 @@ struct old_kernel_sigaction {
  */
 
 extern int __syscall_sigaction(int, const struct old_kernel_sigaction *,
-	struct old_kernel_sigaction *) attribute_hidden;
+	struct old_kernel_sigaction *);
 
 #endif
 
 
 extern int __syscall_rt_sigaction(int, const struct sigaction *,
-	struct sigaction *, size_t) attribute_hidden;
+	struct sigaction *, size_t);
 
 #endif /* _BITS_SIGACTION_STRUCT_H */
diff --git a/libc/sysdeps/linux/common/fsync.c b/libc/sysdeps/linux/common/fsync.c
index 774efc9ce..711811f23 100644
--- a/libc/sysdeps/linux/common/fsync.c
+++ b/libc/sysdeps/linux/common/fsync.c
@@ -10,9 +10,28 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(fsync) weak_function fsync;
-strong_alias(fsync,__libc_fsync)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include "sysdep-cancel.h"
+#else
+#define SINGLE_THREAD_P 1
 #endif
 
-_syscall1(int, fsync, int, fd)
+#define __NR___syscall_fsync __NR_fsync
+static inline _syscall1(int, __syscall_fsync, int, fd)
+
+extern __typeof(fsync) __libc_fsync;
+
+int __libc_fsync(int fd)
+{
+	if (SINGLE_THREAD_P)
+		return __syscall_fsync(fd);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __syscall_fsync(fd);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif
+}
+
+weak_alias(__libc_fsync, fsync)
diff --git a/libc/sysdeps/linux/common/ioctl.c b/libc/sysdeps/linux/common/ioctl.c
index 7ac8f16c2..f2f0f539a 100644
--- a/libc/sysdeps/linux/common/ioctl.c
+++ b/libc/sysdeps/linux/common/ioctl.c
@@ -11,20 +11,36 @@
 #include <stdarg.h>
 #include <sys/ioctl.h>
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
+
+libc_hidden_proto(ioctl)
 
 #define __NR___syscall_ioctl __NR_ioctl
 static __always_inline
-_syscall3(int, __syscall_ioctl, int, fd, int, request, void *, arg)
+_syscall3(int, __syscall_ioctl, int, fd, unsigned long int, request, void *, arg)
 
 int ioctl(int fd, unsigned long int request, ...)
 {
-    void *arg;
-    va_list list;
+	void *arg;
+	va_list list;
+
+	va_start(list, request);
+	arg = va_arg(list, void *);
+
+	va_end(list);
 
-    va_start(list, request);
-    arg = va_arg(list, void *);
-    va_end(list);
+	if (SINGLE_THREAD_P)
+		return __syscall_ioctl(fd, request, arg);
 
-    return __syscall_ioctl(fd, request, arg);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __syscall_ioctl(fd, request, arg);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif
 }
 libc_hidden_def(ioctl)
diff --git a/libc/sysdeps/linux/common/msync.c b/libc/sysdeps/linux/common/msync.c
index 7a46f0c32..2629bd4aa 100644
--- a/libc/sysdeps/linux/common/msync.c
+++ b/libc/sysdeps/linux/common/msync.c
@@ -9,16 +9,33 @@
 
 #include <sys/syscall.h>
 #include <unistd.h>
+#include <sys/mman.h>
 
-#if defined __NR_msync && defined __ARCH_USE_MMU__
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
-#include <sys/mman.h>
+#define __NR___syscall_msync __NR_msync
+static __always_inline _syscall3(int, __syscall_msync, void *, addr, size_t, length,
+						int, flags)
 
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(msync) weak_function msync;
-strong_alias(msync,__libc_msync)
+extern __typeof(msync) __libc_msync;
+int __libc_msync(void * addr, size_t length, int flags)
+{
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype, result;
 #endif
 
-_syscall3(int, msync, void *, addr, size_t, length, int, flags)
+	if (SINGLE_THREAD_P)
+		return __syscall_msync(addr, length, flags);
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	oldtype = LIBC_CANCEL_ASYNC ();
+	result = __syscall_msync(addr, length, flags);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
 #endif
+}
+weak_alias(__libc_msync,msync)
diff --git a/libc/sysdeps/linux/common/nanosleep.c b/libc/sysdeps/linux/common/nanosleep.c
index 0849127db..7e3349117 100644
--- a/libc/sysdeps/linux/common/nanosleep.c
+++ b/libc/sysdeps/linux/common/nanosleep.c
@@ -10,13 +10,32 @@
 #include <sys/syscall.h>
 #include <time.h>
 
-#if defined __USE_POSIX199309 && defined __NR_nanosleep
-_syscall2(int, nanosleep, const struct timespec *, req,
-		  struct timespec *, rem)
-#ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(nanosleep)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__ 
+#include <sysdep-cancel.h>
+#include <pthreadP.h>
 #else
-libc_hidden_weak(nanosleep)
-strong_alias(nanosleep,__libc_nanosleep)
+#define SINGLE_THREAD_P 1
 #endif
+
+#define __NR___syscall_nanosleep __NR_nanosleep
+static inline _syscall2(int, __syscall_nanosleep, const struct timespec *, req,
+						struct timespec *, rem);
+
+extern __typeof(nanosleep) __libc_nanosleep;
+
+int __libc_nanosleep(const struct timespec *req, struct timespec *rem)
+{
+	if (SINGLE_THREAD_P)
+		return __syscall_nanosleep(req, rem);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __syscall_nanosleep(req, rem);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
 #endif
+}
+
+libc_hidden_proto(nanosleep)
+weak_alias(__libc_nanosleep,nanosleep)
+libc_hidden_weak(nanosleep)
diff --git a/libc/sysdeps/linux/common/open64.c b/libc/sysdeps/linux/common/open64.c
index cfe471c64..c1f5400b8 100644
--- a/libc/sysdeps/linux/common/open64.c
+++ b/libc/sysdeps/linux/common/open64.c
@@ -7,6 +7,10 @@
 #include <features.h>
 #include <fcntl.h>
 #include <stdarg.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+#endif
 
 #ifdef __UCLIBC_HAS_LFS__
 
@@ -28,7 +32,20 @@ int open64 (const char *file, int oflag, ...)
 	va_end (arg);
     }
 
-    return open(file, oflag | O_LARGEFILE, mode);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+  if (SINGLE_THREAD_P)
+    return INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  int result = INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+#else
+  return open(file, oflag | O_LARGEFILE, mode);
+#endif
 }
 #ifndef __LINUXTHREADS_OLD__
 libc_hidden_def(open64)
diff --git a/libc/sysdeps/linux/common/pause.c b/libc/sysdeps/linux/common/pause.c
index 19ba30706..cd0ea4a77 100644
--- a/libc/sysdeps/linux/common/pause.c
+++ b/libc/sysdeps/linux/common/pause.c
@@ -10,18 +10,30 @@
 #define __UCLIBC_HIDE_DEPRECATED__
 #include <sys/syscall.h>
 #include <unistd.h>
-#include <signal.h>
 
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(pause) weak_function pause;
-strong_alias(pause, __libc_pause)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
 #endif
 
-#ifdef __NR_pause
-_syscall0(int, pause)
-#else
-int pause(void)
+#include <signal.h>
+
+/* Suspend the process until a signal arrives.
+   This always returns -1 and sets errno to EINTR.  */
+int
+__libc_pause (void)
 {
-	return __sigpause(sigblock(0), 0);
+  sigset_t set;
+
+  __sigemptyset (&set);
+  sigprocmask (SIG_BLOCK, NULL, &set);
+
+  /* pause is a cancellation point, but so is sigsuspend.
+     So no need for anything special here.  */
+
+  return sigsuspend (&set);
 }
+weak_alias (__libc_pause, pause)
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+LIBC_CANCEL_HANDLED ();		/* sigsuspend handles our cancellation.  */
 #endif
diff --git a/libc/sysdeps/linux/common/poll.c b/libc/sysdeps/linux/common/poll.c
index 4a6f06e19..425da3c8a 100644
--- a/libc/sysdeps/linux/common/poll.c
+++ b/libc/sysdeps/linux/common/poll.c
@@ -20,30 +20,33 @@
 #include <sys/syscall.h>
 #include <sys/poll.h>
 
-#ifdef __NR_poll
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif 
+
+libc_hidden_proto(poll)
 
-_syscall3(int, poll, struct pollfd *, fds,
-	unsigned long int, nfds, int, timeout)
+#ifdef __NR_poll
 
-#elif defined(__NR_ppoll) && defined __UCLIBC_LINUX_SPECIFIC__
+#define __NR___syscall_poll __NR_poll
+static inline _syscall3(int, __syscall_poll, struct pollfd *, fds,
+			unsigned long int, nfds, int, timeout);
 
 int poll(struct pollfd *fds, nfds_t nfds, int timeout)
 {
-	struct timespec *ts = NULL, tval;
-	if (timeout > 0) {
-		tval.tv_sec = timeout / 1000;
-		tval.tv_nsec = (timeout % 1000) * 1000000;
-		ts = &tval;
-	} else if (timeout == 0) {
-		tval.tv_sec = 0;
-		tval.tv_nsec = 0;
-		ts = &tval;
-	}
-	return ppoll(fds, nfds, ts, NULL);
+    if (SINGLE_THREAD_P)
+	return __syscall_poll(fds, nfds, timeout);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+    int oldtype = LIBC_CANCEL_ASYNC ();
+    int result = __syscall_poll(fds, nfds, timeout);
+    LIBC_CANCEL_RESET (oldtype);
+    return result;
+#endif
 }
-
-#else
-/* ugh, this arch lacks poll, so we need to emulate this crap ... */
+#else /* !__NR_poll */
 
 #include <alloca.h>
 #include <sys/types.h>
@@ -53,6 +56,9 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout)
 #include <sys/param.h>
 #include <unistd.h>
 
+libc_hidden_proto(getdtablesize)
+libc_hidden_proto(select)
+
 /* uClinux 2.0 doesn't have poll, emulate it using select */
 
 /* Poll the file descriptors described by the NFDS structures starting at
@@ -220,10 +226,4 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout)
 }
 
 #endif
-
-#ifndef __LINUXTHREADS_OLD__
 libc_hidden_def(poll)
-#else
-libc_hidden_weak(poll)
-strong_alias(poll,__libc_poll)
-#endif
diff --git a/libc/sysdeps/linux/common/pselect.c b/libc/sysdeps/linux/common/pselect.c
index 63ab0dbb1..7e93537dd 100644
--- a/libc/sysdeps/linux/common/pselect.c
+++ b/libc/sysdeps/linux/common/pselect.c
@@ -22,9 +22,12 @@
 #include <stddef.h>	/* For NULL.  */
 #include <sys/time.h>
 #include <sys/select.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#endif
 
-extern __typeof(pselect) __libc_pselect;
-
+libc_hidden_proto(sigprocmask)
+libc_hidden_proto(select)
 
 
 /* Check the first NFDS descriptors each in READFDS (if not NULL) for read
@@ -33,8 +36,13 @@ extern __typeof(pselect) __libc_pselect;
    after waiting the interval specified therein.  Additionally set the sigmask
    SIGMASK for this call.  Returns the number of ready descriptors, or -1 for
    errors.  */
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+static int
+__pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+#else
 int
-__libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+#endif
 	   const struct timespec *timeout, const sigset_t *sigmask)
 {
   struct timeval tval;
@@ -64,4 +72,23 @@ __libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 
   return retval;
 }
-weak_alias(__libc_pselect,pselect)
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+int
+pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	   const struct timespec *timeout, const sigset_t *sigmask)
+{
+	if (SINGLE_THREAD_P)
+		return __pselect (nfds, readfds, writefds, exceptfds,
+				  timeout, sigmask);
+
+	int oldtype = LIBC_CANCEL_ASYNC ();
+
+	int result = __pselect (nfds, readfds, writefds, exceptfds,
+				 timeout, sigmask);
+
+	LIBC_CANCEL_RESET (oldtype);
+
+	return result;
+}
+#endif
diff --git a/libc/sysdeps/linux/common/readv.c b/libc/sysdeps/linux/common/readv.c
index 3c40a0d8d..fce396d5f 100644
--- a/libc/sysdeps/linux/common/readv.c
+++ b/libc/sysdeps/linux/common/readv.c
@@ -2,7 +2,8 @@
 /*
  * readv() for uClibc
  *
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  */
@@ -10,5 +11,40 @@
 #include <sys/syscall.h>
 #include <sys/uio.h>
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+
+/* We should deal with kernel which have a smaller UIO_FASTIOV as well
+   as a very big count.  */
+static ssize_t __readv (int fd, const struct iovec *vector, int count)
+{
+  ssize_t bytes_read;
+
+  bytes_read = INLINE_SYSCALL (readv, 3, fd, vector, count);
+
+  if (bytes_read >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
+    return bytes_read;
+
+  /* glibc tries again, but we do not. */
+  //return __atomic_readv_replacement (fd, vector, count);
+
+  return -1;
+}
+
+ssize_t readv (int fd, const struct iovec *vector, int count)
+{
+  if (SINGLE_THREAD_P)
+    return __readv (fd, vector, count);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  int result = __readv (fd, vector, count);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+#else
 _syscall3(ssize_t, readv, int, filedes, const struct iovec *, vector,
 		  int, count)
+#endif
diff --git a/libc/sysdeps/linux/common/select.c b/libc/sysdeps/linux/common/select.c
index caff28d7c..0c2d91984 100644
--- a/libc/sysdeps/linux/common/select.c
+++ b/libc/sysdeps/linux/common/select.c
@@ -11,15 +11,21 @@
 #include <sys/select.h>
 #include <stdint.h>
 
-extern __typeof(select) __libc_select;
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
 #define USEC_PER_SEC 1000000L
 
+extern __typeof(select) __libc_select;
+
 #if !defined(__NR__newselect) && !defined(__NR_select) && defined __USE_XOPEN2K
 # define __NR___libc_pselect6 __NR_pselect6
 _syscall6(int, __libc_pselect6, int, n, fd_set *, readfds, fd_set *, writefds,
-	fd_set *, exceptfds, const struct timespec *, timeout,
-	const sigset_t *, sigmask)
+        fd_set *, exceptfds, const struct timespec *, timeout,
+        const sigset_t *, sigmask)
 
 int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
                   struct timeval *timeout)
@@ -30,12 +36,12 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 		_ts.tv_sec = timeout->tv_sec;
 
 		/* GNU extension: allow for timespec values where the sub-sec
-		 * field is equal to or more than 1 second.  The kernel will
-		 * reject this on us, so take care of the time shift ourself.
-		 * Some applications (like readline and linphone) do this.
-		 * See 'clarification on select() type calls and invalid timeouts'
-		 * on the POSIX general list for more information.
-		 */
+		* field is equal to or more than 1 second.  The kernel will
+		* reject this on us, so take care of the time shift ourself.
+		* Some applications (like readline and linphone) do this.
+		* See 'clarification on select() type calls and invalid timeouts'
+		* on the POSIX general list for more information.
+		*/
 		usec = timeout->tv_usec;
 		if (usec >= USEC_PER_SEC) {
 			_ts.tv_sec += usec / USEC_PER_SEC;
@@ -46,18 +52,41 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 		ts = &_ts;
 	}
 
-	return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0);
+	if (SINGLE_THREAD_P)
+		return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif
+
 }
 
 #else
 
 #ifdef __NR__newselect
-# define __NR___libc_select __NR__newselect
+# define __NR___syscall_select __NR__newselect
 #else
-# define __NR___libc_select __NR_select
+# define __NR___syscall_select __NR_select
 #endif
-_syscall5(int, __libc_select, int, n, fd_set *, readfds, fd_set *, writefds,
-		  fd_set *, exceptfds, struct timeval *, timeout)
+
+_syscall5(int, __syscall_select, int, n, fd_set *, readfds,
+		fd_set *, writefds, fd_set *, exceptfds, struct timeval *, timeout);
+
+int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+                  struct timeval *timeout)
+{
+	if (SINGLE_THREAD_P)
+		return __syscall_select(n, readfds, writefds, exceptfds, timeout);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __syscall_select(n, readfds, writefds, exceptfds, timeout);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif
+}
 
 #endif
 
diff --git a/libc/sysdeps/linux/common/sigprocmask.c b/libc/sysdeps/linux/common/sigprocmask.c
index 13bb2beb7..011d7b367 100644
--- a/libc/sysdeps/linux/common/sigprocmask.c
+++ b/libc/sysdeps/linux/common/sigprocmask.c
@@ -14,6 +14,7 @@
 
 #undef sigprocmask
 
+libc_hidden_proto(sigprocmask)
 
 #ifdef __NR_rt_sigprocmask
 
@@ -24,20 +25,28 @@ _syscall4(int, __rt_sigprocmask, int, how, const sigset_t *, set,
 
 int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)
 {
-	if (set &&
-# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2)
-		(((unsigned int) how) > 2)
-# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3)
-		(((unsigned int)(how-1)) > 2)
-# else
-#  warning "compile time assumption violated.. slow path..."
-		((how != SIG_BLOCK) && (how != SIG_UNBLOCK)
-		 && (how != SIG_SETMASK))
+#ifdef SIGCANCEL
+	sigset_t local_newmask;
+
+	/*
+	 * The only thing we have to make sure here is that SIGCANCEL and
+	 * SIGSETXID are not blocked.
+	 */
+	if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+		|| __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+		))
+	{
+		local_newmask = *set;
+		__sigdelset (&local_newmask, SIGCANCEL);
+# ifdef SIGSETXID
+		__sigdelset (&local_newmask, SIGSETXID);
 # endif
-		) {
-		__set_errno(EINVAL);
-		return -1;
+		set = &local_newmask;
 	}
+#endif
+
 	return __rt_sigprocmask(how, set, oldset, _NSIG / 8);
 }
 
@@ -51,20 +60,28 @@ _syscall3(int, __syscall_sigprocmask, int, how, const sigset_t *, set,
 
 int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)
 {
-	if (set &&
-# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2)
-		(((unsigned int) how) > 2)
-# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3)
-		(((unsigned int)(how-1)) > 2)
-# else
-#  warning "compile time assumption violated.. slow path..."
-		((how != SIG_BLOCK) && (how != SIG_UNBLOCK)
-		 && (how != SIG_SETMASK))
+#ifdef SIGCANCEL
+	sigset_t local_newmask;
+
+	/*
+	 * The only thing we have to make sure here is that SIGCANCEL and
+	 * SIGSETXID are not blocked.
+	 */
+	if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+		|| __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+		))
+	{
+		local_newmask = *set;
+		__sigdelset (&local_newmask, SIGCANCEL);
+# ifdef SIGSETXID
+		__sigdelset (&local_newmask, SIGSETXID);
 # endif
-		) {
-		__set_errno(EINVAL);
-		return -1;
+		set = &local_newmask;
 	}
+#endif
+
 	return (__syscall_sigprocmask(how, set, oldset));
 }
 #endif
diff --git a/libc/sysdeps/linux/common/sigsuspend.c b/libc/sysdeps/linux/common/sigsuspend.c
index 3648e76b5..789eeda89 100644
--- a/libc/sysdeps/linux/common/sigsuspend.c
+++ b/libc/sysdeps/linux/common/sigsuspend.c
@@ -11,27 +11,49 @@
 
 #if defined __USE_POSIX
 #include <signal.h>
+#undef sigsuspend
 
-extern __typeof(sigsuspend) __libc_sigsuspend;
+libc_hidden_proto(sigsuspend)
 
 #ifdef __NR_rt_sigsuspend
 # define __NR___rt_sigsuspend __NR_rt_sigsuspend
-static __inline__ _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size)
 
-int __libc_sigsuspend(const sigset_t * mask)
+# ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#  include <errno.h>
+#  include <sysdep-cancel.h>
+
+/* Change the set of blocked signals to SET,
+   wait until a signal arrives, and restore the set of blocked signals.  */
+int sigsuspend (const sigset_t *set)
+{
+	if (SINGLE_THREAD_P)
+		return INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
+
+	int oldtype = LIBC_CANCEL_ASYNC ();
+
+	int result = INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
+
+	LIBC_CANCEL_RESET (oldtype);
+
+	return result;
+}
+# else
+static inline _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size);
+
+int sigsuspend(const sigset_t * mask)
 {
 	return __rt_sigsuspend(mask, _NSIG / 8);
 }
+# endif
 #else
 # define __NR___syscall_sigsuspend __NR_sigsuspend
 static __inline__ _syscall3(int, __syscall_sigsuspend, int, a, unsigned long int, b,
 		  unsigned long int, c)
 
-int __libc_sigsuspend(const sigset_t * set)
+int sigsuspend(const sigset_t * set)
 {
 	return __syscall_sigsuspend(0, 0, set->__val[0]);
 }
 #endif
-weak_alias(__libc_sigsuspend,sigsuspend)
-libc_hidden_weak(sigsuspend)
+libc_hidden_def(sigsuspend)
 #endif
diff --git a/libc/sysdeps/linux/common/wait.c b/libc/sysdeps/linux/common/wait.c
index b16495314..d4b79bd37 100644
--- a/libc/sysdeps/linux/common/wait.c
+++ b/libc/sysdeps/linux/common/wait.c
@@ -1,23 +1,43 @@
 /*
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  */
-
 #include <stdlib.h>
 #include <syscall.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/resource.h>
 
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(wait) weak_function wait;
-strong_alias(wait,__libc_wait)
-#endif
+/* Wait for a child to die.  When one does, put its status in *STAT_LOC
+ * and return its process ID.  For errors, return (pid_t) -1.  */
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+
+pid_t attribute_hidden
+__libc_wait (__WAIT_STATUS_DEFN stat_loc)
+{
+  if (SINGLE_THREAD_P)
+    return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
+			   (struct rusage *) NULL);
 
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  pid_t result = INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
+				 (struct rusage *) NULL);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+#else
 /* Wait for a child to die.  When one does, put its status in *STAT_LOC
  * and return its process ID.  For errors, return (pid_t) -1.  */
-__pid_t wait(__WAIT_STATUS_DEFN stat_loc)
+__pid_t __libc_wait (__WAIT_STATUS_DEFN stat_loc)
 {
-	return wait4(WAIT_ANY, stat_loc, 0, NULL);
+      return wait4 (WAIT_ANY, stat_loc, 0, (struct rusage *) NULL);
 }
+#endif
+weak_alias(__libc_wait,wait)
diff --git a/libc/sysdeps/linux/common/waitpid.c b/libc/sysdeps/linux/common/waitpid.c
index e46499377..d0437194d 100644
--- a/libc/sysdeps/linux/common/waitpid.c
+++ b/libc/sysdeps/linux/common/waitpid.c
@@ -1,5 +1,6 @@
 /* vi: set sw=4 ts=4: */
 /*
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
@@ -10,13 +11,27 @@
 #include <sys/wait.h>
 #include <sys/resource.h>
 
-__pid_t waitpid(__pid_t pid, int *wait_stat, int options)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include "sysdep-cancel.h"
+#else
+#define SINGLE_THREAD_P 1
+#endif
+
+libc_hidden_proto(wait4)
+
+extern __typeof(waitpid) __libc_waitpid;
+__pid_t __libc_waitpid(__pid_t pid, int *wait_stat, int options)
 {
-	return wait4(pid, wait_stat, options, NULL);
+	if (SINGLE_THREAD_P)
+		return wait4(pid, wait_stat, options, NULL);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = wait4(pid, wait_stat, options, NULL);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif
 }
-#ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(waitpid)
-#else
+libc_hidden_proto(waitpid)
+weak_alias(__libc_waitpid,waitpid)
 libc_hidden_weak(waitpid)
-strong_alias(waitpid,__libc_waitpid)
-#endif
diff --git a/libc/sysdeps/linux/common/writev.c b/libc/sysdeps/linux/common/writev.c
index 99de7e43d..bd0e4077d 100644
--- a/libc/sysdeps/linux/common/writev.c
+++ b/libc/sysdeps/linux/common/writev.c
@@ -10,5 +10,41 @@
 #include <sys/syscall.h>
 #include <sys/uio.h>
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+
+/* We should deal with kernel which have a smaller UIO_FASTIOV as well
+   as a very big count.  */
+static ssize_t __writev (int fd, const struct iovec *vector, int count)
+{
+  ssize_t bytes_written;
+
+  bytes_written = INLINE_SYSCALL (writev, 3, fd, vector, count);
+
+  if (bytes_written >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
+    return bytes_written;
+
+  /* glibc tries again, but we do not. */
+  /* return __atomic_writev_replacement (fd, vector, count); */
+
+  return -1;
+}
+
+ssize_t writev (int fd, const struct iovec *vector, int count)
+{
+  if (SINGLE_THREAD_P)
+    return __writev (fd, vector, count);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  ssize_t result = __writev (fd, vector, count);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+#else
 _syscall3(ssize_t, writev, int, filedes, const struct iovec *, vector,
 		  int, count)
+#endif
-- 
cgit v1.2.3