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