Browse Source

cancellation support for a large amount of the required syscalls

Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
Austin Foxley 14 years ago
parent
commit
57e8823548

+ 150 - 87
libc/inet/socketcalls.c

@@ -33,27 +33,41 @@ extern int __socketcall(int call, unsigned long *args) attribute_hidden;
 #define SYS_RECVMSG     17
 #endif
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__ 
+#include <sysdep-cancel.h>
+#include <pthreadP.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
 #ifdef L_accept
-# ifdef __NR_accept
-_syscall3(int, accept, int, call, struct sockaddr *, addr, socklen_t *,addrlen)
-# elif defined(__NR_socketcall)
-int accept(int s, struct sockaddr *addr, socklen_t * addrlen)
+extern __typeof(accept) __libc_accept;
+#ifdef __NR_accept
+#define __NR___libc_accept  __NR_accept
+_syscall3(int, __libc_accept, int, call, struct sockaddr *, addr, socklen_t *,addrlen)
+#elif defined(__NR_socketcall)
+int __libc_accept(int s, struct sockaddr *addr, socklen_t * addrlen)
 {
 	unsigned long args[3];
 
 	args[0] = s;
 	args[1] = (unsigned long) addr;
 	args[2] = (unsigned long) addrlen;
-	return __socketcall(SYS_ACCEPT, args);
+	
+	if (SINGLE_THREAD_P)
+		return __socketcall(SYS_ACCEPT, args);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __socketcall(SYS_ACCEPT, args);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif		
+		
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(accept)
-# else
+#endif
+weak_alias(__libc_accept,accept)
 libc_hidden_weak(accept)
-strong_alias(accept,__libc_accept)
-# endif
 #endif
 
 #ifdef L_bind
@@ -74,25 +88,32 @@ libc_hidden_def(bind)
 #endif
 
 #ifdef L_connect
-# ifdef __NR_connect
-_syscall3(int, connect, int, sockfd, const struct sockaddr *, saddr, socklen_t, addrlen)
-# elif defined(__NR_socketcall)
-int connect(int sockfd, const struct sockaddr *saddr, socklen_t addrlen)
+extern __typeof(connect) __libc_connect;
+#ifdef __NR_connect
+#define __NR___libc_connect __NR_connect
+_syscall3(int, __libc_connect, int, sockfd, const struct sockaddr *, saddr, socklen_t, addrlen)
+#elif defined(__NR_socketcall)
+int __libc_connect(int sockfd, const struct sockaddr *saddr, socklen_t addrlen)
 {
 	unsigned long args[3];
 
 	args[0] = sockfd;
 	args[1] = (unsigned long) saddr;
 	args[2] = addrlen;
+
+if (SINGLE_THREAD_P)
 	return __socketcall(SYS_CONNECT, args);
+		
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __socketcall(SYS_CONNECT, args);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif		
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(connect)
-# else
+#endif
+weak_alias(__libc_connect,connect)
 libc_hidden_weak(connect)
-strong_alias(connect,__libc_connect)
-# endif
 #endif
 
 #ifdef L_getpeername
@@ -164,12 +185,14 @@ libc_hidden_def(listen)
 #endif
 
 #ifdef L_recv
-# ifdef __NR_recv
-_syscall4(ssize_t, recv, int, sockfd, __ptr_t, buffer, size_t, len,
+extern __typeof(recv) __libc_recv;
+#ifdef __NR_recv
+#define __NR___libc_recv __NR_recv
+_syscall4(ssize_t, __libc_recv, int, sockfd, __ptr_t, buffer, size_t, len,
 	int, flags)
-# elif defined(__NR_socketcall)
+#elif defined(__NR_socketcall)
 /* recv, recvfrom added by bir7@leland.stanford.edu */
-ssize_t recv(int sockfd, __ptr_t buffer, size_t len, int flags)
+ssize_t __libc_recv(int sockfd, __ptr_t buffer, size_t len, int flags)
 {
 	unsigned long args[4];
 
@@ -177,29 +200,36 @@ ssize_t recv(int sockfd, __ptr_t buffer, size_t len, int flags)
 	args[1] = (unsigned long) buffer;
 	args[2] = len;
 	args[3] = flags;
-	return (__socketcall(SYS_RECV, args));
+	
+	if (SINGLE_THREAD_P)
+		return (__socketcall(SYS_RECV, args));
+	
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __socketcall(SYS_RECV, args);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif		
 }
-# elif defined(__NR_recvfrom)
-ssize_t recv(int sockfd, __ptr_t buffer, size_t len, int flags)
+#elif defined(__NR_recvfrom)
+ssize_t __libc_recv(int sockfd, __ptr_t buffer, size_t len, int flags)
 {
 	return (recvfrom(sockfd, buffer, len, flags, NULL, NULL));
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(recv)
-# else
+#endif
+weak_alias(__libc_recv,recv)
 libc_hidden_weak(recv)
-strong_alias(recv,__libc_recv)
-# endif
 #endif
 
 #ifdef L_recvfrom
-# ifdef __NR_recvfrom
-_syscall6(ssize_t, recvfrom, int, sockfd, __ptr_t, buffer, size_t, len,
+extern __typeof(recvfrom) __libc_recvfrom;
+#ifdef __NR_recvfrom
+#define __NR___libc_recvfrom __NR_recvfrom
+_syscall6(ssize_t, __libc_recvfrom, int, sockfd, __ptr_t, buffer, size_t, len,
 	int, flags, struct sockaddr *, to, socklen_t *, tolen)
-# elif defined(__NR_socketcall)
+#elif defined(__NR_socketcall)
 /* recv, recvfrom added by bir7@leland.stanford.edu */
-ssize_t recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags,
+ssize_t __libc_recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags,
 		 struct sockaddr *to, socklen_t * tolen)
 {
 	unsigned long args[6];
@@ -210,45 +240,59 @@ ssize_t recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags,
 	args[3] = flags;
 	args[4] = (unsigned long) to;
 	args[5] = (unsigned long) tolen;
+
+if (SINGLE_THREAD_P)
 	return (__socketcall(SYS_RECVFROM, args));
+	
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __socketcall(SYS_RECVFROM, args);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif		
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(recvfrom)
-# else
+#endif
+weak_alias(__libc_recvfrom,recvfrom)
 libc_hidden_weak(recvfrom)
-strong_alias(recvfrom,__libc_recvfrom)
-# endif
 #endif
 
 #ifdef L_recvmsg
-# ifdef __NR_recvmsg
-_syscall3(ssize_t, recvmsg, int, sockfd, struct msghdr *, msg, int, flags)
-# elif defined(__NR_socketcall)
-ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
+extern __typeof(recvmsg) __libc_recvmsg;
+#ifdef __NR_recvmsg
+#define __NR___libc_recvmsg __NR_recvmsg
+_syscall3(ssize_t, __libc_recvmsg, int, sockfd, struct msghdr *, msg, int, flags)
+#elif defined(__NR_socketcall)
+ssize_t __libc_recvmsg(int sockfd, struct msghdr *msg, int flags)
 {
 	unsigned long args[3];
 
 	args[0] = sockfd;
 	args[1] = (unsigned long) msg;
 	args[2] = flags;
-	return (__socketcall(SYS_RECVMSG, args));
+	
+if (SINGLE_THREAD_P)
+	return (__socketcall(SYS_RECVMSG, args));	
+	
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __socketcall(SYS_RECVMSG, args);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif		
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(recvmsg)
-# else
+#endif
+weak_alias(__libc_recvmsg,recvmsg)
 libc_hidden_weak(recvmsg)
-strong_alias(recvmsg,__libc_recvmsg)
-# endif
 #endif
 
 #ifdef L_send
-# ifdef __NR_send
-_syscall4(ssize_t, send, int, sockfd, const void *, buffer, size_t, len, int, flags)
-# elif defined(__NR_socketcall)
+extern __typeof(send) __libc_send;
+#ifdef __NR_send
+#define __NR___libc_send    __NR_send
+_syscall4(ssize_t, __libc_send, int, sockfd, const void *, buffer, size_t, len, int, flags)
+#elif defined(__NR_socketcall)
 /* send, sendto added by bir7@leland.stanford.edu */
-ssize_t send(int sockfd, const void *buffer, size_t len, int flags)
+ssize_t __libc_send(int sockfd, const void *buffer, size_t len, int flags)
 {
 	unsigned long args[4];
 
@@ -256,51 +300,65 @@ ssize_t send(int sockfd, const void *buffer, size_t len, int flags)
 	args[1] = (unsigned long) buffer;
 	args[2] = len;
 	args[3] = flags;
+	
+if (SINGLE_THREAD_P)
 	return (__socketcall(SYS_SEND, args));
+		
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __socketcall(SYS_SEND, args);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif		
 }
-# elif defined(__NR_sendto)
-ssize_t send(int sockfd, const void *buffer, size_t len, int flags)
+#elif defined(__NR_sendto)
+ssize_t __libc_send(int sockfd, const void *buffer, size_t len, int flags)
 {
 	return (sendto(sockfd, buffer, len, flags, NULL, 0));
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(send)
-# else
+#endif
+weak_alias(__libc_send,send)
 libc_hidden_weak(send)
-strong_alias(send,__libc_send)
-# endif
 #endif
 
 #ifdef L_sendmsg
-# ifdef __NR_sendmsg
-_syscall3(ssize_t, sendmsg, int, sockfd, const struct msghdr *, msg, int, flags)
-# elif defined(__NR_socketcall)
-ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
+extern __typeof(sendmsg) __libc_sendmsg;
+#ifdef __NR_sendmsg
+#define __NR___libc_sendmsg __NR_sendmsg
+_syscall3(ssize_t, __libc_sendmsg, int, sockfd, const struct msghdr *, msg, int, flags)
+#elif defined(__NR_socketcall)
+ssize_t __libc_sendmsg(int sockfd, const struct msghdr *msg, int flags)
 {
 	unsigned long args[3];
 
 	args[0] = sockfd;
 	args[1] = (unsigned long) msg;
 	args[2] = flags;
+	
+if (SINGLE_THREAD_P)
 	return (__socketcall(SYS_SENDMSG, args));
+	
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __socketcall(SYS_SENDMSG, args);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif		
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(sendmsg)
-# else
+#endif
+weak_alias(__libc_sendmsg,sendmsg)
 libc_hidden_weak(sendmsg)
-strong_alias(sendmsg,__libc_sendmsg)
-# endif
 #endif
 
 #ifdef L_sendto
-# ifdef __NR_sendto
-_syscall6(ssize_t, sendto, int, sockfd, const void *, buffer,
+extern __typeof(sendto) __libc_sendto;
+#ifdef __NR_sendto
+#define __NR___libc_sendto  __NR_sendto
+_syscall6(ssize_t, __libc_sendto, int, sockfd, const void *, buffer,
 	size_t, len, int, flags, const struct sockaddr *, to, socklen_t, tolen)
-# elif defined(__NR_socketcall)
+#elif defined(__NR_socketcall)
 /* send, sendto added by bir7@leland.stanford.edu */
-ssize_t sendto(int sockfd, const void *buffer, size_t len, int flags,
+ssize_t __libc_sendto(int sockfd, const void *buffer, size_t len, int flags,
 	   const struct sockaddr *to, socklen_t tolen)
 {
 	unsigned long args[6];
@@ -311,15 +369,20 @@ ssize_t sendto(int sockfd, const void *buffer, size_t len, int flags,
 	args[3] = flags;
 	args[4] = (unsigned long) to;
 	args[5] = tolen;
+	
+if (SINGLE_THREAD_P)
 	return (__socketcall(SYS_SENDTO, args));
+	
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype = LIBC_CANCEL_ASYNC ();
+	int result = __socketcall(SYS_SENDTO, args);
+	LIBC_CANCEL_RESET (oldtype);
+	return result;
+#endif		
 }
-# endif
-# ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(sendto)
-# else
+#endif
+weak_alias(__libc_sendto,sendto)
 libc_hidden_weak(sendto)
-strong_alias(sendto,__libc_sendto)
-# endif
 #endif
 
 #ifdef L_setsockopt

+ 46 - 7
libc/misc/sysvipc/msgq.c

@@ -1,6 +1,11 @@
 #include <errno.h>
 #include <sys/msg.h>
 #include "ipc.h"
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include "sysdep-cancel.h"
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
 
 #ifdef L_msgctl
@@ -43,31 +48,65 @@ struct new_msg_buf{
 
 #ifdef L_msgrcv
 #ifdef __NR_msgrcv
-_syscall5(int, msgrcv, int, msqid, void *, msgp, size_t, msgsz, long int, msgtyp, int, msgflg)
-#else
-int msgrcv (int msqid, void *msgp, size_t msgsz,
-	long int msgtyp, int msgflg)
+#define __NR___syscall_msgrcv __NR_msgrcv
+static inline _syscall5(int, __syscall_msgrcv, int, msqid, void *, msgp,
+			size_t, msgsz, long int, msgtyp, int, msgflg)
+#endif
+static inline int do_msgrcv (int msqid, void *msgp, size_t msgsz,
+			    long int msgtyp, int msgflg)
 {
+#ifdef __NR_msgrcv
+    return __syscall_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+#else
     struct new_msg_buf temp;
 
     temp.r_msgtyp = msgtyp;
     temp.oldmsg = msgp;
     return __syscall_ipc(IPCOP_msgrcv ,msqid ,msgsz ,msgflg ,&temp, 0);
+#endif
 }
+int msgrcv (int msqid, void *msgp, size_t msgsz,
+	    long int msgtyp, int msgflg)
+{
+    if (SINGLE_THREAD_P)
+	return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+    int oldtype = LIBC_CANCEL_ASYNC ();
+    int result = do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+    LIBC_CANCEL_RESET (oldtype);
+    return result;
 #endif
+}
 #endif
 
 
 
 #ifdef L_msgsnd
 #ifdef __NR_msgsnd
-_syscall4(int, msgsnd, int, msqid, const void *, msgp, size_t, msgsz, int, msgflg)
-#else
+#define __NR___syscall_msgsnd __NR_msgsnd
+static inline _syscall4(int, __syscall_msgsnd, int, msqid, const void *, msgp,
+			size_t, msgsz, int, msgflg)
+#endif
 /* Send message to message queue.  */
-int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
+static inline int do_msgsnd (int msqid, const void *msgp, size_t msgsz,
+			    int msgflg)
 {
+#ifdef __NR_msgsnd
+    return __syscall_msgsnd(msqid, msgp, msgsz, msgflg);
+#else
     return __syscall_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg, (void *)msgp, 0);
+#endif
 }
+int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
+{
+    if (SINGLE_THREAD_P)
+	return do_msgsnd(msqid, msgp, msgsz, msgflg);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+    int oldtype = LIBC_CANCEL_ASYNC ();
+    int result = do_msgsnd(msqid, msgp, msgsz, msgflg);
+    LIBC_CANCEL_RESET (oldtype);
+    return result;
 #endif
+}
 #endif
 

+ 19 - 1
libc/signal/sigpause.c

@@ -23,7 +23,9 @@
 #define __FAVOR_BSD
 #include <signal.h>
 #include <stddef.h>		/* For NULL.  */
-#include <string.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#endif
 
 
 #include "sigset-cvt-mask.h"
@@ -45,6 +47,9 @@ int __sigpause (int sig_or_mask, int is_sig)
   else
     sigset_set_old_mask (&set, sig_or_mask);
 
+  /* Note the sigpause() is a cancellation point.  But since we call
+     sigsuspend() which itself is a cancellation point we do not have
+     to do anything here.  */
   return sigsuspend (&set);
 }
 libc_hidden_def(__sigpause)
@@ -56,5 +61,18 @@ libc_hidden_def(__sigpause)
    the BSD version.  So make this the default.  */
 int sigpause (int mask)
 {
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+  if (SINGLE_THREAD_P)
+    return __sigpause (mask, 0);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  int result = __sigpause (mask, 0);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+#else
   return __sigpause (mask, 0);
+#endif
 }

+ 76 - 7
libc/signal/sigwait.c

@@ -1,7 +1,8 @@
 /* vi: set sw=4 ts=4: */
 /* sigwait
  *
- * Copyright (C) 2003 by Erik Andersen <andersen@uclibc.org>
+ * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2003-2005 by Erik Andersen <andersen@uclibc.org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,19 +23,86 @@
 #include <signal.h>
 #include <string.h>
 
-#if defined __UCLIBC_HAS_REALTIME__
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+# include <sysdep-cancel.h>
 
-int sigwait(const sigset_t *set, int *sig)
+# 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.  */
+	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);
+
+	return ret;
+}
+
+int 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;
+}
+# else /* __NR_rt_sigtimedwait */
+#  error We must have rt_sigtimedwait defined!!!
+# endif
+#else /* __UCLIBC_HAS_THREADS_NATIVE__ */
+
+# if defined __UCLIBC_HAS_REALTIME__
+
+int sigwait (const sigset_t *set, int *sig)
 {
-	int ret = sigwaitinfo(set, NULL);
-	if (ret != -1) {
+	int ret = 1;
+	if ((ret = sigwaitinfo(set, NULL)) != -1) {
 		*sig = ret;
 		return 0;
 	}
 	return 1;
 }
 
-#else /* __UCLIBC_HAS_REALTIME__ */
+# else /* __UCLIBC_HAS_REALTIME__ */
 /* variant without REALTIME extensions */
 
 static smallint was_sig; /* obviously not thread-safe */
@@ -94,4 +162,5 @@ int sigwait (const sigset_t *set, int *sig)
   *sig = was_sig;
   return was_sig == -1 ? -1 : 0;
 }
-#endif /* __UCLIBC_HAS_REALTIME__ */
+# endif /* __UCLIBC_HAS_REALTIME__ */
+#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */

+ 201 - 0
libc/stdlib/system.c

@@ -10,8 +10,15 @@
 #include <unistd.h>
 #include <sys/wait.h>
 #include <stdlib.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sched.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
+#include <sysdep-cancel.h>
+#endif
 
 
+#if !defined __UCLIBC_HAS_THREADS_NATIVE__
 /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
 #include <sys/syscall.h>
 #ifndef __NR_vfork
@@ -61,4 +68,198 @@ int __libc_system(const char *command)
 	signal(SIGCHLD, save_chld);
 	return wait_val;
 }
+#else
+/* We have to and actually can handle cancelable system().  The big
+   problem: we have to kill the child process if necessary.  To do
+   this a cleanup handler has to be registered and is has to be able
+   to find the PID of the child.  The main problem is to reliable have
+   the PID when needed.  It is not necessary for the parent thread to
+   return.  It might still be in the kernel when the cancellation
+   request comes.  Therefore we have to use the clone() calls ability
+   to have the kernel write the PID into the user-level variable.  */
+
+libc_hidden_proto(sigaction)
+libc_hidden_proto(waitpid)
+      
+#if defined __ia64__
+# define FORK() \
+  INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
+		  &pid, NULL, NULL)
+#elif defined __sparc__
+# define FORK() \
+  INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
+#elif defined __s390__
+# define FORK() \
+  INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid)
+#else
+# define FORK() \
+  INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
+#endif
+
+static void cancel_handler (void *arg);
+
+# define CLEANUP_HANDLER \
+  __libc_cleanup_region_start (1, cancel_handler, &pid)
+
+# define CLEANUP_RESET \
+  __libc_cleanup_region_end (0)
+
+static struct sigaction intr, quit;
+static int sa_refcntr;
+__libc_lock_define_initialized (static, lock);
+
+# define DO_LOCK() __libc_lock_lock (lock)
+# define DO_UNLOCK() __libc_lock_unlock (lock)
+# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
+# define ADD_REF() sa_refcntr++
+# define SUB_REF() --sa_refcntr
+
+/* Execute LINE as a shell command, returning its status.  */
+static int
+do_system (const char *line)
+{
+  int status, save;
+  pid_t pid;
+  struct sigaction sa;
+  sigset_t omask;
+
+  sa.sa_handler = SIG_IGN;
+  sa.sa_flags = 0;
+  __sigemptyset (&sa.sa_mask);
+
+  DO_LOCK ();
+  if (ADD_REF () == 0)
+    {
+      if (sigaction (SIGINT, &sa, &intr) < 0)
+	{
+	  SUB_REF ();
+	  goto out;
+	}
+      if (sigaction (SIGQUIT, &sa, &quit) < 0)
+	{
+	  save = errno;
+	  SUB_REF ();
+	  goto out_restore_sigint;
+	}
+    }
+  DO_UNLOCK ();
+
+  /* We reuse the bitmap in the 'sa' structure.  */
+  __sigaddset (&sa.sa_mask, SIGCHLD);
+  save = errno;
+  if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
+    {
+	{
+	  DO_LOCK ();
+	  if (SUB_REF () == 0)
+	    {
+	      save = errno;
+	      (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+	    out_restore_sigint:
+	      (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+	      __set_errno (save);
+	    }
+	out:
+	  DO_UNLOCK ();
+	  return -1;
+	}
+    }
+
+  CLEANUP_HANDLER;
+
+  pid = FORK ();
+  if (pid == (pid_t) 0)
+    {
+      /* Child side.  */
+      const char *new_argv[4];
+      new_argv[0] = "/bin/sh";
+      new_argv[1] = "-c";
+      new_argv[2] = line;
+      new_argv[3] = NULL;
+
+      /* Restore the signals.  */
+      (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+      (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+      (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
+      INIT_LOCK ();
+
+      /* Exec the shell.  */
+      (void) execve ("/bin/sh", (char *const *) new_argv, __environ);
+      _exit (127);
+    }
+  else if (pid < (pid_t) 0)
+    /* The fork failed.  */
+    status = -1;
+  else
+    /* Parent side.  */
+    {
+      /* Note the system() is a cancellation point.  But since we call
+	 waitpid() which itself is a cancellation point we do not
+	 have to do anything here.  */
+      if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+	status = -1;
+    }
+
+  CLEANUP_RESET;
+
+  save = errno;
+  DO_LOCK ();
+  if ((SUB_REF () == 0
+       && (sigaction (SIGINT, &intr, (struct sigaction *) NULL)
+	   | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
+      || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
+    {
+	status = -1;
+    }
+  DO_UNLOCK ();
+
+  return status;
+}
+
+
+int
+__libc_system (const char *line)
+{
+  if (line == NULL)
+    /* Check that we have a command processor available.  It might
+       not be available after a chroot(), for example.  */
+    return do_system ("exit 0") == 0;
+
+  if (SINGLE_THREAD_P)
+    return do_system (line);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+
+  int result = do_system (line);
+
+  LIBC_CANCEL_RESET (oldtype);
+
+  return result;
+}
+
+
+/* The cancellation handler.  */
+static void
+cancel_handler (void *arg)
+{
+  pid_t child = *(pid_t *) arg;
+
+  INTERNAL_SYSCALL_DECL (err);
+  INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
+
+  TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
+
+  DO_LOCK ();
+
+  if (SUB_REF () == 0)
+    {
+      (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+      (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+    }
+
+  DO_UNLOCK ();
+}
+#endif
+#ifdef IS_IN_libc
 weak_alias(__libc_system,system)
+#endif

+ 76 - 24
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)

+ 66 - 24
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)

+ 3 - 1
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,

+ 2 - 2
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 */

+ 23 - 4
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)

+ 23 - 7
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)

+ 23 - 6
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)

+ 26 - 7
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)

+ 18 - 1
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)

+ 21 - 9
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

+ 24 - 24
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

+ 31 - 4
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

+ 37 - 1
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

+ 43 - 14
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
 

+ 41 - 24
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

+ 28 - 6
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

+ 27 - 7
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)

+ 22 - 7
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

+ 36 - 0
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

+ 22 - 5
libc/termios/tcdrain.c

@@ -19,14 +19,31 @@
 #include <errno.h>
 #include <termios.h>
 #include <sys/ioctl.h>
-
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(tcdrain) weak_function tcdrain;
-strong_alias(tcdrain,__libc_tcdrain)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
 #endif
 
+libc_hidden_proto(ioctl)
+
+extern __typeof(tcdrain) __libc_tcdrain;
 /* Wait for pending output to be written on FD.  */
-int tcdrain(int fd)
+int __libc_tcdrain (int fd)
 {
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	if (SINGLE_THREAD_P)
+		/* With an argument of 1, TCSBRK for output to be drain.  */
+		return INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1);
+
+	int oldtype = LIBC_CANCEL_ASYNC ();
+
+	/* With an argument of 1, TCSBRK for output to be drain.  */
+	int result = INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1);
+
+	LIBC_CANCEL_RESET (oldtype);
+
+	return result;
+#else
 	return ioctl(fd, TCSBRK, 1);
+#endif
 }
+weak_alias(__libc_tcdrain,tcdrain)