浏览代码

cancellation support for a large amount of the required syscalls

Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
Austin Foxley 15 年之前
父节点
当前提交
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
 #define SYS_RECVMSG     17
 #endif
 #endif
 
 
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__ 
+#include <sysdep-cancel.h>
+#include <pthreadP.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
 
 
 #ifdef L_accept
 #ifdef L_accept
-# ifdef __NR_accept
+extern __typeof(accept) __libc_accept;
-_syscall3(int, accept, int, call, struct sockaddr *, addr, socklen_t *,addrlen)
+#ifdef __NR_accept
-# elif defined(__NR_socketcall)
+#define __NR___libc_accept  __NR_accept
-int accept(int s, struct sockaddr *addr, socklen_t * addrlen)
+_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];
 	unsigned long args[3];
 
 
 	args[0] = s;
 	args[0] = s;
 	args[1] = (unsigned long) addr;
 	args[1] = (unsigned long) addr;
 	args[2] = (unsigned long) addrlen;
 	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
+#endif
-# ifndef __LINUXTHREADS_OLD__
+weak_alias(__libc_accept,accept)
-libc_hidden_def(accept)
-# else
 libc_hidden_weak(accept)
 libc_hidden_weak(accept)
-strong_alias(accept,__libc_accept)
-# endif
 #endif
 #endif
 
 
 #ifdef L_bind
 #ifdef L_bind
@@ -74,25 +88,32 @@ libc_hidden_def(bind)
 #endif
 #endif
 
 
 #ifdef L_connect
 #ifdef L_connect
-# ifdef __NR_connect
+extern __typeof(connect) __libc_connect;
-_syscall3(int, connect, int, sockfd, const struct sockaddr *, saddr, socklen_t, addrlen)
+#ifdef __NR_connect
-# elif defined(__NR_socketcall)
+#define __NR___libc_connect __NR_connect
-int connect(int sockfd, const struct sockaddr *saddr, socklen_t addrlen)
+_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];
 	unsigned long args[3];
 
 
 	args[0] = sockfd;
 	args[0] = sockfd;
 	args[1] = (unsigned long) saddr;
 	args[1] = (unsigned long) saddr;
 	args[2] = addrlen;
 	args[2] = addrlen;
+
+if (SINGLE_THREAD_P)
 	return __socketcall(SYS_CONNECT, args);
 	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
+#endif
-# ifndef __LINUXTHREADS_OLD__
+weak_alias(__libc_connect,connect)
-libc_hidden_def(connect)
-# else
 libc_hidden_weak(connect)
 libc_hidden_weak(connect)
-strong_alias(connect,__libc_connect)
-# endif
 #endif
 #endif
 
 
 #ifdef L_getpeername
 #ifdef L_getpeername
@@ -164,12 +185,14 @@ libc_hidden_def(listen)
 #endif
 #endif
 
 
 #ifdef L_recv
 #ifdef L_recv
-# ifdef __NR_recv
+extern __typeof(recv) __libc_recv;
-_syscall4(ssize_t, recv, int, sockfd, __ptr_t, buffer, size_t, len,
+#ifdef __NR_recv
+#define __NR___libc_recv __NR_recv
+_syscall4(ssize_t, __libc_recv, int, sockfd, __ptr_t, buffer, size_t, len,
 	int, flags)
 	int, flags)
-# elif defined(__NR_socketcall)
+#elif defined(__NR_socketcall)
 /* recv, recvfrom added by bir7@leland.stanford.edu */
 /* 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];
 	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[1] = (unsigned long) buffer;
 	args[2] = len;
 	args[2] = len;
 	args[3] = flags;
 	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)
+#elif defined(__NR_recvfrom)
-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)
 {
 {
 	return (recvfrom(sockfd, buffer, len, flags, NULL, NULL));
 	return (recvfrom(sockfd, buffer, len, flags, NULL, NULL));
 }
 }
-# endif
+#endif
-# ifndef __LINUXTHREADS_OLD__
+weak_alias(__libc_recv,recv)
-libc_hidden_def(recv)
-# else
 libc_hidden_weak(recv)
 libc_hidden_weak(recv)
-strong_alias(recv,__libc_recv)
-# endif
 #endif
 #endif
 
 
 #ifdef L_recvfrom
 #ifdef L_recvfrom
-# ifdef __NR_recvfrom
+extern __typeof(recvfrom) __libc_recvfrom;
-_syscall6(ssize_t, recvfrom, int, sockfd, __ptr_t, buffer, size_t, len,
+#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)
 	int, flags, struct sockaddr *, to, socklen_t *, tolen)
-# elif defined(__NR_socketcall)
+#elif defined(__NR_socketcall)
 /* recv, recvfrom added by bir7@leland.stanford.edu */
 /* 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)
 		 struct sockaddr *to, socklen_t * tolen)
 {
 {
 	unsigned long args[6];
 	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[3] = flags;
 	args[4] = (unsigned long) to;
 	args[4] = (unsigned long) to;
 	args[5] = (unsigned long) tolen;
 	args[5] = (unsigned long) tolen;
+
+if (SINGLE_THREAD_P)
 	return (__socketcall(SYS_RECVFROM, args));
 	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
+#endif
-# ifndef __LINUXTHREADS_OLD__
+weak_alias(__libc_recvfrom,recvfrom)
-libc_hidden_def(recvfrom)
-# else
 libc_hidden_weak(recvfrom)
 libc_hidden_weak(recvfrom)
-strong_alias(recvfrom,__libc_recvfrom)
-# endif
 #endif
 #endif
 
 
 #ifdef L_recvmsg
 #ifdef L_recvmsg
-# ifdef __NR_recvmsg
+extern __typeof(recvmsg) __libc_recvmsg;
-_syscall3(ssize_t, recvmsg, int, sockfd, struct msghdr *, msg, int, flags)
+#ifdef __NR_recvmsg
-# elif defined(__NR_socketcall)
+#define __NR___libc_recvmsg __NR_recvmsg
-ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
+_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];
 	unsigned long args[3];
 
 
 	args[0] = sockfd;
 	args[0] = sockfd;
 	args[1] = (unsigned long) msg;
 	args[1] = (unsigned long) msg;
 	args[2] = flags;
 	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
+#endif
-# ifndef __LINUXTHREADS_OLD__
+weak_alias(__libc_recvmsg,recvmsg)
-libc_hidden_def(recvmsg)
-# else
 libc_hidden_weak(recvmsg)
 libc_hidden_weak(recvmsg)
-strong_alias(recvmsg,__libc_recvmsg)
-# endif
 #endif
 #endif
 
 
 #ifdef L_send
 #ifdef L_send
-# ifdef __NR_send
+extern __typeof(send) __libc_send;
-_syscall4(ssize_t, send, int, sockfd, const void *, buffer, size_t, len, int, flags)
+#ifdef __NR_send
-# elif defined(__NR_socketcall)
+#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 */
 /* 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];
 	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[1] = (unsigned long) buffer;
 	args[2] = len;
 	args[2] = len;
 	args[3] = flags;
 	args[3] = flags;
+	
+if (SINGLE_THREAD_P)
 	return (__socketcall(SYS_SEND, args));
 	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)
+#elif defined(__NR_sendto)
-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)
 {
 {
 	return (sendto(sockfd, buffer, len, flags, NULL, 0));
 	return (sendto(sockfd, buffer, len, flags, NULL, 0));
 }
 }
-# endif
+#endif
-# ifndef __LINUXTHREADS_OLD__
+weak_alias(__libc_send,send)
-libc_hidden_def(send)
-# else
 libc_hidden_weak(send)
 libc_hidden_weak(send)
-strong_alias(send,__libc_send)
-# endif
 #endif
 #endif
 
 
 #ifdef L_sendmsg
 #ifdef L_sendmsg
-# ifdef __NR_sendmsg
+extern __typeof(sendmsg) __libc_sendmsg;
-_syscall3(ssize_t, sendmsg, int, sockfd, const struct msghdr *, msg, int, flags)
+#ifdef __NR_sendmsg
-# elif defined(__NR_socketcall)
+#define __NR___libc_sendmsg __NR_sendmsg
-ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
+_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];
 	unsigned long args[3];
 
 
 	args[0] = sockfd;
 	args[0] = sockfd;
 	args[1] = (unsigned long) msg;
 	args[1] = (unsigned long) msg;
 	args[2] = flags;
 	args[2] = flags;
+	
+if (SINGLE_THREAD_P)
 	return (__socketcall(SYS_SENDMSG, args));
 	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
+#endif
-# ifndef __LINUXTHREADS_OLD__
+weak_alias(__libc_sendmsg,sendmsg)
-libc_hidden_def(sendmsg)
-# else
 libc_hidden_weak(sendmsg)
 libc_hidden_weak(sendmsg)
-strong_alias(sendmsg,__libc_sendmsg)
-# endif
 #endif
 #endif
 
 
 #ifdef L_sendto
 #ifdef L_sendto
-# ifdef __NR_sendto
+extern __typeof(sendto) __libc_sendto;
-_syscall6(ssize_t, sendto, int, sockfd, const void *, buffer,
+#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)
 	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 */
 /* 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)
 	   const struct sockaddr *to, socklen_t tolen)
 {
 {
 	unsigned long args[6];
 	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[3] = flags;
 	args[4] = (unsigned long) to;
 	args[4] = (unsigned long) to;
 	args[5] = tolen;
 	args[5] = tolen;
+	
+if (SINGLE_THREAD_P)
 	return (__socketcall(SYS_SENDTO, args));
 	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
+#endif
-# ifndef __LINUXTHREADS_OLD__
+weak_alias(__libc_sendto,sendto)
-libc_hidden_def(sendto)
-# else
 libc_hidden_weak(sendto)
 libc_hidden_weak(sendto)
-strong_alias(sendto,__libc_sendto)
-# endif
 #endif
 #endif
 
 
 #ifdef L_setsockopt
 #ifdef L_setsockopt

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

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

+ 19 - 1
libc/signal/sigpause.c

@@ -23,7 +23,9 @@
 #define __FAVOR_BSD
 #define __FAVOR_BSD
 #include <signal.h>
 #include <signal.h>
 #include <stddef.h>		/* For NULL.  */
 #include <stddef.h>		/* For NULL.  */
-#include <string.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#endif
 
 
 
 
 #include "sigset-cvt-mask.h"
 #include "sigset-cvt-mask.h"
@@ -45,6 +47,9 @@ int __sigpause (int sig_or_mask, int is_sig)
   else
   else
     sigset_set_old_mask (&set, sig_or_mask);
     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);
   return sigsuspend (&set);
 }
 }
 libc_hidden_def(__sigpause)
 libc_hidden_def(__sigpause)
@@ -56,5 +61,18 @@ libc_hidden_def(__sigpause)
    the BSD version.  So make this the default.  */
    the BSD version.  So make this the default.  */
 int sigpause (int mask)
 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);
   return __sigpause (mask, 0);
+#endif
 }
 }

+ 76 - 7
libc/signal/sigwait.c

@@ -1,7 +1,8 @@
 /* vi: set sw=4 ts=4: */
 /* vi: set sw=4 ts=4: */
 /* sigwait
 /* 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
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -22,19 +23,86 @@
 #include <signal.h>
 #include <signal.h>
 #include <string.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);
+	int ret = 1;
-	if (ret != -1) {
+	if ((ret = sigwaitinfo(set, NULL)) != -1) {
 		*sig = ret;
 		*sig = ret;
 		return 0;
 		return 0;
 	}
 	}
 	return 1;
 	return 1;
 }
 }
 
 
-#else /* __UCLIBC_HAS_REALTIME__ */
+# else /* __UCLIBC_HAS_REALTIME__ */
 /* variant without REALTIME extensions */
 /* variant without REALTIME extensions */
 
 
 static smallint was_sig; /* obviously not thread-safe */
 static smallint was_sig; /* obviously not thread-safe */
@@ -94,4 +162,5 @@ int sigwait (const sigset_t *set, int *sig)
   *sig = was_sig;
   *sig = was_sig;
   return was_sig == -1 ? -1 : 0;
   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 <unistd.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
 #include <stdlib.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 */
 /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #ifndef __NR_vfork
 #ifndef __NR_vfork
@@ -61,4 +68,198 @@ int __libc_system(const char *command)
 	signal(SIGCHLD, save_chld);
 	signal(SIGCHLD, save_chld);
 	return wait_val;
 	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)
 weak_alias(__libc_system,system)
+#endif

+ 76 - 24
libc/sysdeps/linux/common/__rt_sigtimedwait.c

@@ -2,44 +2,97 @@
 /*
 /*
  * __rt_sigtimedwait() for uClibc
  * __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 <sys/syscall.h>
 #include <signal.h>
 #include <signal.h>
-#define __need_NULL
+#include <string.h>
-#include <stddef.h>
 
 
+libc_hidden_proto(memcpy)
 
 
 #ifdef __NR_rt_sigtimedwait
 #ifdef __NR_rt_sigtimedwait
-#define __NR___rt_sigtimedwait __NR_rt_sigtimedwait
+#include <string.h>
-static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set, siginfo_t *, info,
+libc_hidden_proto(memcpy)
-		  const struct timespec *, timeout, size_t, setsize)
 
 
-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,
+/* Return any pending signal or wait for one for the given time.  */
-				 const struct timespec *timeout)
+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
+# else
-int sigwaitinfo(const sigset_t * set, siginfo_t * info)
+#  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)
+	return __rt_sigtimedwait(set, info, timeout, _NSIG / 8);
-		__set_errno(EINVAL);
-	else
-		__set_errno(ENOSYS);
-	return -1;
 }
 }
-
+# endif /* !__UCLIBC_HAS_THREADS_NATIVE__ */
-int sigtimedwait(const sigset_t * set, siginfo_t * info,
+#else
-				 const struct timespec *timeout)
+int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info,
+									const struct timespec *timeout)
 {
 {
 	if (set == NULL)
 	if (set == NULL)
 		__set_errno(EINVAL);
 		__set_errno(EINVAL);
@@ -48,5 +101,4 @@ int sigtimedwait(const sigset_t * set, siginfo_t * info,
 	return -1;
 	return -1;
 }
 }
 #endif
 #endif
-libc_hidden_def(sigwaitinfo)
+weak_alias(__sigtimedwait,sigtimedwait)
-libc_hidden_def(sigtimedwait)

+ 66 - 24
libc/sysdeps/linux/common/__syscall_fcntl.c

@@ -2,6 +2,7 @@
 /*
 /*
  * __syscall_fcntl() for uClibc
  * __syscall_fcntl() for uClibc
  *
  *
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  *
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
@@ -9,42 +10,83 @@
 
 
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #include <stdarg.h>
 #include <stdarg.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>	/* Must come before <fcntl.h>.  */
+#endif
 #include <fcntl.h>
 #include <fcntl.h>
 #include <bits/wordsize.h>
 #include <bits/wordsize.h>
 
 
-#define __NR___syscall_fcntl __NR_fcntl
+extern __typeof(fcntl) __libc_fcntl;
-static __always_inline
+libc_hidden_proto(__libc_fcntl) 
-_syscall3(int, __syscall_fcntl, int, fd, int, cmd, long, arg)
 
 
-int fcntl(int fd, int cmd, ...)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
-{
+int __fcntl_nocancel (int fd, int cmd, ...)
-	long arg;
+{   
-	va_list list;
+	va_list ap;
+	void *arg;
 
 
-	va_start(list, cmd);
+	va_start (ap, cmd);
-	arg = va_arg(list, long);
+	arg = va_arg (ap, void *);
-	va_end(list);
+	va_end (ap);
 
 
-#if __WORDSIZE == 32
+# if __WORDSIZE == 32
 	if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) {
 	if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) {
-#if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
+#  if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64
-		return fcntl64(fd, cmd, arg);
+		return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
-#else
+#  else
 		__set_errno(ENOSYS);
 		__set_errno(ENOSYS);
 		return -1;
 		return -1;
-#endif
+#  endif
 	}
 	}
+# endif
+	return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+}
 #endif
 #endif
 
 
-	return (__syscall_fcntl(fd, cmd, arg));
+int __libc_fcntl (int fd, int cmd, ...)
-}
+{
-#ifndef __LINUXTHREADS_OLD__
+	va_list ap;
-libc_hidden_def(fcntl)
+	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
 #else
-libc_hidden_weak(fcntl)
+# if __WORDSIZE == 32
-strong_alias(fcntl,__libc_fcntl)
+	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
 #endif
+}
+libc_hidden_def(__libc_fcntl)
 
 
-#if ! defined __NR_fcntl64 && defined __UCLIBC_HAS_LFS__
+libc_hidden_proto(fcntl)
-strong_alias(fcntl,fcntl64)
+weak_alias(__libc_fcntl,fcntl)
-#endif
+libc_hidden_weak(fcntl)

+ 3 - 1
libc/sysdeps/linux/common/__syscall_rt_sigaction.c

@@ -12,7 +12,9 @@
 #ifdef __NR_rt_sigaction
 #ifdef __NR_rt_sigaction
 #include <signal.h>
 #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
 #define __NR___syscall_rt_sigaction __NR_rt_sigaction
 _syscall4(int, __syscall_rt_sigaction, int, signum,
 _syscall4(int, __syscall_rt_sigaction, int, signum,
 		  const struct sigaction *, act, struct sigaction *, oldact,
 		  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 *,
 extern int __syscall_sigaction(int, const struct old_kernel_sigaction *,
-	struct old_kernel_sigaction *) attribute_hidden;
+	struct old_kernel_sigaction *);
 
 
 #endif
 #endif
 
 
 
 
 extern int __syscall_rt_sigaction(int, const struct sigaction *,
 extern int __syscall_rt_sigaction(int, const struct sigaction *,
-	struct sigaction *, size_t) attribute_hidden;
+	struct sigaction *, size_t);
 
 
 #endif /* _BITS_SIGACTION_STRUCT_H */
 #endif /* _BITS_SIGACTION_STRUCT_H */

+ 23 - 4
libc/sysdeps/linux/common/fsync.c

@@ -10,9 +10,28 @@
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
-#ifdef __LINUXTHREADS_OLD__
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
-extern __typeof(fsync) weak_function fsync;
+#include "sysdep-cancel.h"
-strong_alias(fsync,__libc_fsync)
+#else
+#define SINGLE_THREAD_P 1
 #endif
 #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 <stdarg.h>
 #include <sys/ioctl.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
 #define __NR___syscall_ioctl __NR_ioctl
 static __always_inline
 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, ...)
 int ioctl(int fd, unsigned long int request, ...)
 {
 {
-    void *arg;
+	void *arg;
-    va_list list;
+	va_list list;
+
+	va_start(list, request);
+	arg = va_arg(list, void *);
+
+	va_end(list);
 
 
-    va_start(list, request);
+	if (SINGLE_THREAD_P)
-    arg = va_arg(list, void *);
+		return __syscall_ioctl(fd, request, arg);
-    va_end(list);
 
 
-    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)
 libc_hidden_def(ioctl)

+ 23 - 6
libc/sysdeps/linux/common/msync.c

@@ -9,16 +9,33 @@
 
 
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #include <unistd.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) __libc_msync;
-extern __typeof(msync) weak_function msync;
+int __libc_msync(void * addr, size_t length, int flags)
-strong_alias(msync,__libc_msync)
+{
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+	int oldtype, result;
 #endif
 #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
 #endif
+}
+weak_alias(__libc_msync,msync)

+ 26 - 7
libc/sysdeps/linux/common/nanosleep.c

@@ -10,13 +10,32 @@
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #include <time.h>
 #include <time.h>
 
 
-#if defined __USE_POSIX199309 && defined __NR_nanosleep
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__ 
-_syscall2(int, nanosleep, const struct timespec *, req,
+#include <sysdep-cancel.h>
-		  struct timespec *, rem)
+#include <pthreadP.h>
-#ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(nanosleep)
 #else
 #else
-libc_hidden_weak(nanosleep)
+#define SINGLE_THREAD_P 1
-strong_alias(nanosleep,__libc_nanosleep)
 #endif
 #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
 #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 <features.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdarg.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+#endif
 
 
 #ifdef __UCLIBC_HAS_LFS__
 #ifdef __UCLIBC_HAS_LFS__
 
 
@@ -28,7 +32,20 @@ int open64 (const char *file, int oflag, ...)
 	va_end (arg);
 	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__
 #ifndef __LINUXTHREADS_OLD__
 libc_hidden_def(open64)
 libc_hidden_def(open64)

+ 21 - 9
libc/sysdeps/linux/common/pause.c

@@ -10,18 +10,30 @@
 #define __UCLIBC_HIDE_DEPRECATED__
 #define __UCLIBC_HIDE_DEPRECATED__
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #include <unistd.h>
 #include <unistd.h>
-#include <signal.h>
 
 
-#ifdef __LINUXTHREADS_OLD__
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
-extern __typeof(pause) weak_function pause;
+#include <sysdep-cancel.h>
-strong_alias(pause, __libc_pause)
 #endif
 #endif
 
 
-#ifdef __NR_pause
+#include <signal.h>
-_syscall0(int, pause)
+
-#else
+/* Suspend the process until a signal arrives.
-int pause(void)
+   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
 #endif

+ 24 - 24
libc/sysdeps/linux/common/poll.c

@@ -20,30 +20,33 @@
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #include <sys/poll.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,
+#ifdef __NR_poll
-	unsigned long int, nfds, int, timeout)
 
 
-#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)
 int poll(struct pollfd *fds, nfds_t nfds, int timeout)
 {
 {
-	struct timespec *ts = NULL, tval;
+    if (SINGLE_THREAD_P)
-	if (timeout > 0) {
+	return __syscall_poll(fds, nfds, timeout);
-		tval.tv_sec = timeout / 1000;
+
-		tval.tv_nsec = (timeout % 1000) * 1000000;
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
-		ts = &tval;
+    int oldtype = LIBC_CANCEL_ASYNC ();
-	} else if (timeout == 0) {
+    int result = __syscall_poll(fds, nfds, timeout);
-		tval.tv_sec = 0;
+    LIBC_CANCEL_RESET (oldtype);
-		tval.tv_nsec = 0;
+    return result;
-		ts = &tval;
+#endif
-	}
-	return ppoll(fds, nfds, ts, NULL);
 }
 }
-
+#else /* !__NR_poll */
-#else
-/* ugh, this arch lacks poll, so we need to emulate this crap ... */
 
 
 #include <alloca.h>
 #include <alloca.h>
 #include <sys/types.h>
 #include <sys/types.h>
@@ -53,6 +56,9 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout)
 #include <sys/param.h>
 #include <sys/param.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
+libc_hidden_proto(getdtablesize)
+libc_hidden_proto(select)
+
 /* uClinux 2.0 doesn't have poll, emulate it using select */
 /* uClinux 2.0 doesn't have poll, emulate it using select */
 
 
 /* Poll the file descriptors described by the NFDS structures starting at
 /* 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
 #endif
-
-#ifndef __LINUXTHREADS_OLD__
 libc_hidden_def(poll)
 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 <stddef.h>	/* For NULL.  */
 #include <sys/time.h>
 #include <sys/time.h>
 #include <sys/select.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
 /* 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
    after waiting the interval specified therein.  Additionally set the sigmask
    SIGMASK for this call.  Returns the number of ready descriptors, or -1 for
    SIGMASK for this call.  Returns the number of ready descriptors, or -1 for
    errors.  */
    errors.  */
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+static int
+__pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+#else
 int
 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)
 	   const struct timespec *timeout, const sigset_t *sigmask)
 {
 {
   struct timeval tval;
   struct timeval tval;
@@ -64,4 +72,23 @@ __libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 
 
   return retval;
   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
  * 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.
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  */
  */
@@ -10,5 +11,40 @@
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #include <sys/uio.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,
 _syscall3(ssize_t, readv, int, filedes, const struct iovec *, vector,
 		  int, count)
 		  int, count)
+#endif

+ 43 - 14
libc/sysdeps/linux/common/select.c

@@ -11,15 +11,21 @@
 #include <sys/select.h>
 #include <sys/select.h>
 #include <stdint.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
 #define USEC_PER_SEC 1000000L
 
 
+extern __typeof(select) __libc_select;
+
 #if !defined(__NR__newselect) && !defined(__NR_select) && defined __USE_XOPEN2K
 #if !defined(__NR__newselect) && !defined(__NR_select) && defined __USE_XOPEN2K
 # define __NR___libc_pselect6 __NR_pselect6
 # define __NR___libc_pselect6 __NR_pselect6
 _syscall6(int, __libc_pselect6, int, n, fd_set *, readfds, fd_set *, writefds,
 _syscall6(int, __libc_pselect6, int, n, fd_set *, readfds, fd_set *, writefds,
-	fd_set *, exceptfds, const struct timespec *, timeout,
+        fd_set *, exceptfds, const struct timespec *, timeout,
-	const sigset_t *, sigmask)
+        const sigset_t *, sigmask)
 
 
 int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
                   struct timeval *timeout)
                   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;
 		_ts.tv_sec = timeout->tv_sec;
 
 
 		/* GNU extension: allow for timespec values where the sub-sec
 		/* GNU extension: allow for timespec values where the sub-sec
-		 * field is equal to or more than 1 second.  The kernel will
+		* field is equal to or more than 1 second.  The kernel will
-		 * reject this on us, so take care of the time shift ourself.
+		* reject this on us, so take care of the time shift ourself.
-		 * Some applications (like readline and linphone) do this.
+		* Some applications (like readline and linphone) do this.
-		 * See 'clarification on select() type calls and invalid timeouts'
+		* See 'clarification on select() type calls and invalid timeouts'
-		 * on the POSIX general list for more information.
+		* on the POSIX general list for more information.
-		 */
+		*/
 		usec = timeout->tv_usec;
 		usec = timeout->tv_usec;
 		if (usec >= USEC_PER_SEC) {
 		if (usec >= USEC_PER_SEC) {
 			_ts.tv_sec += 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;
 		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
 #else
 
 
 #ifdef __NR__newselect
 #ifdef __NR__newselect
-# define __NR___libc_select __NR__newselect
+# define __NR___syscall_select __NR__newselect
 #else
 #else
-# define __NR___libc_select __NR_select
+# define __NR___syscall_select __NR_select
 #endif
 #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
 #endif
 
 

+ 41 - 24
libc/sysdeps/linux/common/sigprocmask.c

@@ -14,6 +14,7 @@
 
 
 #undef sigprocmask
 #undef sigprocmask
 
 
+libc_hidden_proto(sigprocmask)
 
 
 #ifdef __NR_rt_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)
 int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)
 {
 {
-	if (set &&
+#ifdef SIGCANCEL
-# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2)
+	sigset_t local_newmask;
-		(((unsigned int) how) > 2)
+
-# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3)
+	/*
-		(((unsigned int)(how-1)) > 2)
+	 * The only thing we have to make sure here is that SIGCANCEL and
-# else
+	 * SIGSETXID are not blocked.
-#  warning "compile time assumption violated.. slow path..."
+	 */
-		((how != SIG_BLOCK) && (how != SIG_UNBLOCK)
+	if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
-		 && (how != SIG_SETMASK))
+# ifdef SIGSETXID
+		|| __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+		))
+	{
+		local_newmask = *set;
+		__sigdelset (&local_newmask, SIGCANCEL);
+# ifdef SIGSETXID
+		__sigdelset (&local_newmask, SIGSETXID);
 # endif
 # endif
-		) {
+		set = &local_newmask;
-		__set_errno(EINVAL);
-		return -1;
 	}
 	}
+#endif
+
 	return __rt_sigprocmask(how, set, oldset, _NSIG / 8);
 	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)
 int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)
 {
 {
-	if (set &&
+#ifdef SIGCANCEL
-# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2)
+	sigset_t local_newmask;
-		(((unsigned int) how) > 2)
+
-# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3)
+	/*
-		(((unsigned int)(how-1)) > 2)
+	 * The only thing we have to make sure here is that SIGCANCEL and
-# else
+	 * SIGSETXID are not blocked.
-#  warning "compile time assumption violated.. slow path..."
+	 */
-		((how != SIG_BLOCK) && (how != SIG_UNBLOCK)
+	if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
-		 && (how != SIG_SETMASK))
+# ifdef SIGSETXID
+		|| __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+		))
+	{
+		local_newmask = *set;
+		__sigdelset (&local_newmask, SIGCANCEL);
+# ifdef SIGSETXID
+		__sigdelset (&local_newmask, SIGSETXID);
 # endif
 # endif
-		) {
+		set = &local_newmask;
-		__set_errno(EINVAL);
-		return -1;
 	}
 	}
+#endif
+
 	return (__syscall_sigprocmask(how, set, oldset));
 	return (__syscall_sigprocmask(how, set, oldset));
 }
 }
 #endif
 #endif

+ 28 - 6
libc/sysdeps/linux/common/sigsuspend.c

@@ -11,27 +11,49 @@
 
 
 #if defined __USE_POSIX
 #if defined __USE_POSIX
 #include <signal.h>
 #include <signal.h>
+#undef sigsuspend
 
 
-extern __typeof(sigsuspend) __libc_sigsuspend;
+libc_hidden_proto(sigsuspend)
 
 
 #ifdef __NR_rt_sigsuspend
 #ifdef __NR_rt_sigsuspend
 # define __NR___rt_sigsuspend __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);
 	return __rt_sigsuspend(mask, _NSIG / 8);
 }
 }
+# endif
 #else
 #else
 # define __NR___syscall_sigsuspend __NR_sigsuspend
 # define __NR___syscall_sigsuspend __NR_sigsuspend
 static __inline__ _syscall3(int, __syscall_sigsuspend, int, a, unsigned long int, b,
 static __inline__ _syscall3(int, __syscall_sigsuspend, int, a, unsigned long int, b,
 		  unsigned long int, c)
 		  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]);
 	return __syscall_sigsuspend(0, 0, set->__val[0]);
 }
 }
 #endif
 #endif
-weak_alias(__libc_sigsuspend,sigsuspend)
+libc_hidden_def(sigsuspend)
-libc_hidden_weak(sigsuspend)
 #endif
 #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>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  *
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  */
  */
-
 #include <stdlib.h>
 #include <stdlib.h>
 #include <syscall.h>
 #include <syscall.h>
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
 #include <sys/resource.h>
 #include <sys/resource.h>
 
 
-#ifdef __LINUXTHREADS_OLD__
+/* Wait for a child to die.  When one does, put its status in *STAT_LOC
-extern __typeof(wait) weak_function wait;
+ * and return its process ID.  For errors, return (pid_t) -1.  */
-strong_alias(wait,__libc_wait)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
-#endif
+#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
 /* 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.  */
  * 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: */
 /* vi: set sw=4 ts=4: */
 /*
 /*
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  *
  *
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
@@ -10,13 +11,27 @@
 #include <sys/wait.h>
 #include <sys/wait.h>
 #include <sys/resource.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_proto(waitpid)
-libc_hidden_def(waitpid)
+weak_alias(__libc_waitpid,waitpid)
-#else
 libc_hidden_weak(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/syscall.h>
 #include <sys/uio.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,
 _syscall3(ssize_t, writev, int, filedes, const struct iovec *, vector,
 		  int, count)
 		  int, count)
+#endif

+ 22 - 5
libc/termios/tcdrain.c

@@ -19,14 +19,31 @@
 #include <errno.h>
 #include <errno.h>
 #include <termios.h>
 #include <termios.h>
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
-
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
-#ifdef __LINUXTHREADS_OLD__
+#include <sysdep-cancel.h>
-extern __typeof(tcdrain) weak_function tcdrain;
-strong_alias(tcdrain,__libc_tcdrain)
 #endif
 #endif
 
 
+libc_hidden_proto(ioctl)
+
+extern __typeof(tcdrain) __libc_tcdrain;
 /* Wait for pending output to be written on FD.  */
 /* 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);
 	return ioctl(fd, TCSBRK, 1);
+#endif
 }
 }
+weak_alias(__libc_tcdrain,tcdrain)