summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux
diff options
context:
space:
mode:
authorAustin Foxley <austinf@cetoncorp.com>2009-10-17 14:32:36 -0700
committerAustin Foxley <austinf@cetoncorp.com>2009-10-17 14:32:36 -0700
commit57e8823548ad6e65d33b2153edeb18fb0edc20e6 (patch)
tree8cfc6fea89ec4e90c94b5764233ee2b2ed9cc54d /libc/sysdeps/linux
parent9a737ab7a40984cfdfffd014562a220a3736a10f (diff)
cancellation support for a large amount of the required syscalls
Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
Diffstat (limited to 'libc/sysdeps/linux')
-rw-r--r--libc/sysdeps/linux/common/__rt_sigtimedwait.c100
-rw-r--r--libc/sysdeps/linux/common/__syscall_fcntl.c90
-rw-r--r--libc/sysdeps/linux/common/__syscall_rt_sigaction.c4
-rw-r--r--libc/sysdeps/linux/common/bits/kernel_sigaction.h4
-rw-r--r--libc/sysdeps/linux/common/fsync.c27
-rw-r--r--libc/sysdeps/linux/common/ioctl.c30
-rw-r--r--libc/sysdeps/linux/common/msync.c29
-rw-r--r--libc/sysdeps/linux/common/nanosleep.c33
-rw-r--r--libc/sysdeps/linux/common/open64.c19
-rw-r--r--libc/sysdeps/linux/common/pause.c30
-rw-r--r--libc/sysdeps/linux/common/poll.c48
-rw-r--r--libc/sysdeps/linux/common/pselect.c35
-rw-r--r--libc/sysdeps/linux/common/readv.c38
-rw-r--r--libc/sysdeps/linux/common/select.c57
-rw-r--r--libc/sysdeps/linux/common/sigprocmask.c65
-rw-r--r--libc/sysdeps/linux/common/sigsuspend.c34
-rw-r--r--libc/sysdeps/linux/common/wait.c34
-rw-r--r--libc/sysdeps/linux/common/waitpid.c29
-rw-r--r--libc/sysdeps/linux/common/writev.c36
19 files changed, 570 insertions, 172 deletions
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