diff options
Diffstat (limited to 'libc')
119 files changed, 4977 insertions, 940 deletions
diff --git a/libc/Makefile.in b/libc/Makefile.in index 323c4e463..37eaa65eb 100644 --- a/libc/Makefile.in +++ b/libc/Makefile.in @@ -16,10 +16,12 @@ VERSION_SCRIPT := -Wl,--version-script,$(VERSION_SCRIPT)  endif  LDFLAGS-libc.so := $(LDFLAGS) $(VERSION_SCRIPT) -Wl,-init,$(SYMBOL_PREFIX)__uClibc_init - +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS += -D__USE_STDIO_FUTEXES__ +endif  LIBS-libc.so := $(interp) $(ldso) $(top_builddir)lib/$(NONSHARED_LIBNAME) -# we have SHARED_MAJORNAME=libc.so.$(MAJOR_VERSION) defined in Rules.mak +# we have SHARED_LIBNAME=libc.so.$(ABI_VERSION) defined in Rules.mak  libc_FULL_NAME := libuClibc-$(VERSION).so  # this comes first, so duplicate removal works correctly @@ -58,18 +60,18 @@ OUTPUT_FORMAT = $(CC) $(CFLAGS) -Wl,--verbose 2>&1 | $(SED) -n '/OUTPUT_FORMAT/,  ifeq ($(DOMULTI),n)  $(libc.depend): $(libc_OUT)/libc_so.a $(LIBS-libc.so) -	$(call link.so,$(libc_FULL_NAME),$(MAJOR_VERSION)) +	$(call link.so,$(libc_FULL_NAME),$(ABI_VERSION))  else  $(libc.depend): $(libc_OUT)/libc.oS $(libc-nomulti-y:.o=.oS) | $(LIBS-libc.so) -	$(call linkm.so,$(libc_FULL_NAME),$(MAJOR_VERSION)) +	$(call linkm.so,$(libc_FULL_NAME),$(ABI_VERSION))  endif  	$(Q)$(RM) $@  	$(Q)cp $(top_srcdir)extra/scripts/format.lds $@  	$(Q)$(OUTPUT_FORMAT) >> $@  ifeq ($(COMPAT_ATEXIT),y) -	$(Q)echo "GROUP ( $(NONSHARED_LIBNAME) $(SHARED_MAJORNAME) $(ASNEEDED) )" >> $@ +	$(Q)echo "GROUP ( $(NONSHARED_LIBNAME) $(SHARED_LIBNAME) $(ASNEEDED) )" >> $@  else -	$(Q)echo "GROUP ( $(SHARED_MAJORNAME) $(NONSHARED_LIBNAME) $(ASNEEDED) )" >> $@ +	$(Q)echo "GROUP ( $(SHARED_LIBNAME) $(NONSHARED_LIBNAME) $(ASNEEDED) )" >> $@  endif  $(libc_OUT)/libc_so.a: $(libc-so-y) | $(top_builddir)lib/libc.a $(top_builddir)lib/$(NONSHARED_LIBNAME) diff --git a/libc/inet/getaddrinfo.c b/libc/inet/getaddrinfo.c index b91486f53..8c7f7b9f1 100644 --- a/libc/inet/getaddrinfo.c +++ b/libc/inet/getaddrinfo.c @@ -56,6 +56,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  #include <assert.h>  #include <errno.h>  #include <netdb.h> +#include <tls.h>  #include <resolv.h>  #include <stdio.h>  #include <stdlib.h> @@ -307,7 +308,7 @@ gaih_local(const char *name, const struct gaih_service *service,  		char *buf = ((struct sockaddr_un *)ai->ai_addr)->sun_path;  		if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0 -		 || __gen_tempname(buf, __GT_NOCREATE) != 0 +		 || __gen_tempname(buf, __GT_NOCREATE, 0) != 0  		) {  			return -EAI_SYSTEM;  		} diff --git a/libc/inet/hostid.c b/libc/inet/hostid.c index ac4c56c35..90b22ae7a 100644 --- a/libc/inet/hostid.c +++ b/libc/inet/hostid.c @@ -14,6 +14,7 @@  #include <stdlib.h>  #include <string.h>  #include <netdb.h> +#include <not-cancel.h>  #define HOSTID "/etc/hostid" @@ -25,11 +26,11 @@ int sethostid(long int new_id)  	if (geteuid() || getuid())  		return __set_errno(EPERM); -	fd = open(HOSTID, O_CREAT|O_WRONLY, 0644); +	fd = open_not_cancel(HOSTID, O_CREAT|O_WRONLY, 0644);  	if (fd < 0)  		return fd; -	ret = write(fd, &new_id, sizeof(new_id)) == sizeof(new_id) ? 0 : -1; -	close(fd); +	ret = write_not_cancel(fd, &new_id, sizeof(new_id)) == sizeof(new_id) ? 0 : -1; +	close_not_cancel_no_status (fd);  	return ret;  }  #endif @@ -44,10 +45,10 @@ long int gethostid(void)  	 * It is not an error if we cannot read this file. It is not even an  	 * error if we cannot read all the bytes, we just carry on trying...  	 */ -	fd = open(HOSTID, O_RDONLY); +	fd = open_not_cancel_2(HOSTID, O_RDONLY);  	if (fd >= 0) { -		int i = read(fd, &id, sizeof(id)); -		close(fd); +		int i = read_not_cancel(fd, &id, sizeof(id)); +		close_not_cancel_no_status(fd);  		if (i > 0)  			return id;  	} diff --git a/libc/inet/if_index.c b/libc/inet/if_index.c index 750a4649e..8efcd2a76 100644 --- a/libc/inet/if_index.c +++ b/libc/inet/if_index.c @@ -32,6 +32,7 @@  #include <sys/socket.h>  #include <sys/ioctl.h>  #include <libc-internal.h> +#include <not-cancel.h>  #include "netlinkaccess.h" @@ -55,13 +56,13 @@ if_nametoindex(const char* ifname)      {        /* close never fails here, fd is just a unconnected socket.         *int saved_errno = errno; */ -      close(fd); +      close_not_cancel_no_status(fd);        /*if (saved_errno == EINVAL)         *  __set_errno(ENOSYS); */        return 0;      } -  close(fd); +  close_not_cancel_no_status(fd);    return ifr.ifr_ifindex;  #endif  } @@ -112,7 +113,7 @@ if_nameindex (void)        if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)  	{ -	  close (fd); +	  close_not_cancel_no_status (fd);  	  return NULL;  	}      } @@ -123,7 +124,7 @@ if_nameindex (void)    idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));    if (idx == NULL)      { -      close(fd); +      close_not_cancel_no_status (fd);        __set_errno(ENOBUFS);        return NULL;      } @@ -141,7 +142,7 @@ if_nameindex (void)  	  for (j =  0; j < i; ++j)  	    free (idx[j].if_name);  	  free(idx); -	  close(fd); +	  close_not_cancel_no_status (fd);  	  if (saved_errno == EINVAL)  	    saved_errno = ENOSYS;  	  else if (saved_errno == ENOMEM) @@ -155,7 +156,7 @@ if_nameindex (void)    idx[i].if_index = 0;    idx[i].if_name = NULL; -  close(fd); +  close_not_cancel_no_status (fd);    return idx;  #endif  } @@ -298,14 +299,14 @@ if_indextoname (unsigned int ifindex, char *ifname)    if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)      {        int serrno = errno; -      close (fd); +      close_not_cancel_no_status (fd);        if (serrno == ENODEV)  	/* POSIX requires ENXIO.  */  	serrno = ENXIO;        __set_errno (serrno);        return NULL;    } -  close (fd); +  close_not_cancel_no_status (fd);    return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);  # else diff --git a/libc/inet/socketcalls.c b/libc/inet/socketcalls.c index 8bb09cabb..e4bdbcb59 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; -	return __socketcall(SYS_CONNECT, args); + +	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; -	return (__socketcall(SYS_RECVFROM, args)); + +	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; -	return (__socketcall(SYS_SEND, args)); + +	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; -	return (__socketcall(SYS_SENDMSG, args)); + +	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; -	return (__socketcall(SYS_SENDTO, args)); + +	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/Makefile.in b/libc/misc/Makefile.in index 838081d66..6c09d3142 100644 --- a/libc/misc/Makefile.in +++ b/libc/misc/Makefile.in @@ -21,6 +21,7 @@ include $(top_srcdir)libc/misc/gnu/Makefile.in  include $(top_srcdir)libc/misc/internals/Makefile.in  include $(top_srcdir)libc/misc/locale/Makefile.in  include $(top_srcdir)libc/misc/mntent/Makefile.in +include $(top_srcdir)libc/misc/pthread/Makefile.in  include $(top_srcdir)libc/misc/regex/Makefile.in  include $(top_srcdir)libc/misc/search/Makefile.in  include $(top_srcdir)libc/misc/statfs/Makefile.in diff --git a/libc/misc/dirent/closedir.c b/libc/misc/dirent/closedir.c index cca03b8f7..dfb53f888 100644 --- a/libc/misc/dirent/closedir.c +++ b/libc/misc/dirent/closedir.c @@ -9,6 +9,7 @@  #include <stdlib.h>  #include <unistd.h>  #include "dirstream.h" +#include <not-cancel.h>  int closedir(DIR * dir) @@ -31,6 +32,6 @@ int closedir(DIR * dir)  	__UCLIBC_MUTEX_UNLOCK(dir->dd_lock);  	free(dir->dd_buf);  	free(dir); -	return close(fd); +	return close_not_cancel(fd);  }  libc_hidden_def(closedir) diff --git a/libc/misc/dirent/opendir.c b/libc/misc/dirent/opendir.c index b43f60814..66a5cc9e9 100644 --- a/libc/misc/dirent/opendir.c +++ b/libc/misc/dirent/opendir.c @@ -12,6 +12,7 @@  #include <unistd.h>  #include <sys/dir.h>  #include <sys/stat.h> +#include <not-cancel.h>  #include <dirent.h>  #include "dirstream.h" @@ -34,7 +35,7 @@ static DIR *fd_to_DIR(int fd, __blksize_t size)  		free(ptr);  		return NULL;  	} -	__pthread_mutex_init(&ptr->dd_lock, NULL); +	__UCLIBC_MUTEX_INIT_VAR(ptr->dd_lock);  	return ptr;  } @@ -81,7 +82,7 @@ DIR *opendir(const char *name)  	}  # define O_DIRECTORY 0  #endif -	fd = open(name, O_RDONLY|O_NDELAY|O_DIRECTORY|O_CLOEXEC); +	fd = open_not_cancel_2(name, O_RDONLY|O_NDELAY|O_DIRECTORY|O_CLOEXEC);  	if (fd < 0)  		return NULL;  	/* Note: we should check to make sure that between the stat() and open() @@ -93,7 +94,7 @@ DIR *opendir(const char *name)  		/* this close() never fails  		 *int saved_errno;  		 *saved_errno = errno; */ -		close(fd); +		close_not_cancel_no_status(fd);  		/*__set_errno(saved_errno);*/  		return NULL;  	} @@ -102,12 +103,13 @@ DIR *opendir(const char *name)  	 * exec. From "Anna Pluzhnikov" <besp@midway.uchicago.edu>.  	 */  #ifndef __ASSUME_O_CLOEXEC -	fcntl(fd, F_SETFD, FD_CLOEXEC); +	fcntl_not_cancel(fd, F_SETFD, FD_CLOEXEC);  #endif  	ptr = fd_to_DIR(fd, statbuf.st_blksize); +  	if (!ptr) { -		close(fd); +		close_not_cancel_no_status(fd);  		__set_errno(ENOMEM);  	}  	return ptr; diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c index 6e520fabb..f7e45c60c 100644 --- a/libc/misc/internals/__uClibc_main.c +++ b/libc/misc/internals/__uClibc_main.c @@ -1,5 +1,6 @@  /* - * Copyright (C) Feb 2001 Manuel Novoa III + * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com> + * Copyright (C) 2001 by Manuel Novoa III <mjn3@uclibc.org>   * Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>   *   * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. @@ -13,8 +14,10 @@   * avoided in the static library case.   */ -#define	_ERRNO_H  #include <features.h> +#ifndef __UCLIBC_HAS_THREADS_NATIVE__ +#define	_ERRNO_H +#endif  #include <unistd.h>  #include <stdlib.h>  #include <string.h> @@ -22,10 +25,17 @@  #include <link.h>  #include <bits/uClibc_page.h>  #include <paths.h> +#include <unistd.h>  #include <asm/errno.h>  #include <fcntl.h>  #include <sys/stat.h>  #include <sys/sysmacros.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <errno.h> +#include <pthread-functions.h> +#include <not-cancel.h> +#include <atomic.h> +#endif  #ifndef SHARED @@ -64,16 +74,17 @@ void internal_function _dl_aux_init (ElfW(auxv_t) *av);   * Prototypes.   */  extern int *weak_const_function __errno_location(void); -libc_hidden_proto(__errno_location)  extern int *weak_const_function __h_errno_location(void); -libc_hidden_proto(__h_errno_location) -  extern void weak_function _stdio_init(void) attribute_hidden;  #ifdef __UCLIBC_HAS_LOCALE__  extern void weak_function _locale_init(void) attribute_hidden;  #endif  #ifdef __UCLIBC_HAS_THREADS__ +#if !defined (__UCLIBC_HAS_THREADS_NATIVE__) || defined (SHARED)  extern void weak_function __pthread_initialize_minimal(void); +#else +extern void __pthread_initialize_minimal(void); +#endif  #endif  /* If __UCLIBC_FORMAT_SHARED_FLAT__, all array initialisation and finalisation @@ -126,7 +137,7 @@ static void __check_one_fd(int fd, int mode)  	int nullfd = open(_PATH_DEVNULL, mode);  	/* /dev/null is major=1 minor=3.  Make absolutely certain  	 * that is in fact the device that we have opened and not -	 * some other weird file... [removed in uclibc] */ +	 * some other wierd file... [removed in uclibc] */  	if (nullfd!=fd)  	{  		abort(); @@ -181,17 +192,20 @@ void __uClibc_init(void)       * __pthread_initialize_minimal so we can use pthread_locks       * whenever they are needed.       */ +#if !defined (__UCLIBC_HAS_THREADS_NATIVE__) || defined (SHARED)      if (likely(__pthread_initialize_minimal!=NULL)) +#endif  	__pthread_initialize_minimal();  #endif  #ifndef SHARED  # ifdef __UCLIBC_HAS_SSP__      /* Set up the stack checker's canary.  */ -    stack_chk_guard = _dl_setup_stack_chk_guard();  #  ifdef THREAD_SET_STACK_GUARD +    uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard();      THREAD_SET_STACK_GUARD (stack_chk_guard);  #   ifdef __UCLIBC_HAS_SSP_COMPAT__ +    stack_chk_guard = _dl_setup_stack_chk_guard();      __guard = stack_chk_guard;  #   endif  #  else @@ -266,6 +280,11 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,      ElfW(auxv_t) auxvt[AT_EGID + 1];  #endif +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	/* Result of the 'main' function.  */ +	int result; +#endif +  #ifndef SHARED      __libc_stack_end = stack_end;  #endif @@ -385,34 +404,57 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,      if (likely(__h_errno_location!=NULL))  	*(__h_errno_location()) = 0; -    /* -     * Finally, invoke application's main and then exit. -     */ -    exit(main(argc, argv, __environ)); -} +#if defined HAVE_CLEANUP_JMP_BUF && defined __UCLIBC_HAS_THREADS_NATIVE__ +	/* Memory for the cancellation buffer.  */ +	struct pthread_unwind_buf unwind_buf; -#if defined(__UCLIBC_HAS_THREADS__) && !defined(SHARED) -/* Weaks for internal library use only. - * - * We need to define weaks here to cover all the pthread functions that - * libc itself will use so that we aren't forced to link libc against - * libpthread.  This file is only used in libc.a and since we have - * weaks here, they will be automatically overridden by libpthread.a - * if it gets linked in. - */ +	int not_first_call; +	not_first_call = +		setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); +	if (__builtin_expect (! not_first_call, 1)) +	{ +		struct pthread *self = THREAD_SELF; + +		/* Store old info.  */ +		unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); +		unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup); + +		/* Store the new cleanup handler info.  */ +		THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf); -static int __pthread_return_0 (void) { return 0; } -static void __pthread_return_void (void) { return; } - -weak_alias (__pthread_return_0, __pthread_mutex_init) -weak_alias (__pthread_return_0, __pthread_mutex_lock) -weak_alias (__pthread_return_0, __pthread_mutex_trylock) -weak_alias (__pthread_return_0, __pthread_mutex_unlock) -weak_alias (__pthread_return_void, _pthread_cleanup_push_defer) -weak_alias (__pthread_return_void, _pthread_cleanup_pop_restore) -# ifdef __UCLIBC_HAS_THREADS_NATIVE__ -weak_alias (__pthread_return_0, __pthread_mutexattr_init) -weak_alias (__pthread_return_0, __pthread_mutexattr_destroy) -weak_alias (__pthread_return_0, __pthread_mutexattr_settype) +		/* Run the program.  */ +		result = main (argc, argv, __environ); +	} +	else +	{ +		/* Remove the thread-local data.  */ +# ifdef SHARED +		__libc_pthread_functions.ptr__nptl_deallocate_tsd (); +# else +		extern void __nptl_deallocate_tsd (void) __attribute ((weak)); +		__nptl_deallocate_tsd ();  # endif + +		/* One less thread.  Decrement the counter.  If it is zero we +		   terminate the entire process.  */ +		result = 0; +# ifdef SHARED +		unsigned int *const ptr = __libc_pthread_functions.ptr_nthreads; +# else +		extern unsigned int __nptl_nthreads __attribute ((weak)); +		unsigned int *const ptr = &__nptl_nthreads; +# endif + +		if (! atomic_decrement_and_test (ptr)) +			/* Not much left to do but to exit the thread, not the process.  */ +			__exit_thread_inline (0); +	} + +	exit (result); +#else +	/* +	 * Finally, invoke application's main and then exit. +	 */ +	exit (main (argc, argv, __environ));  #endif +} diff --git a/libc/misc/internals/tempname.c b/libc/misc/internals/tempname.c index cbd4ced7a..4145c9478 100644 --- a/libc/misc/internals/tempname.c +++ b/libc/misc/internals/tempname.c @@ -168,14 +168,14 @@ static void brain_damaged_fillrand(unsigned char *buf, unsigned int len)     KIND may be one of:     __GT_NOCREATE:       simply verify that the name does not exist -                        at the time of the call. +                        at the time of the call. mode argument is ignored.     __GT_FILE:           create the file using open(O_CREAT|O_EXCL) -                        and return a read-write fd.  The file is mode 0600. +                        and return a read-write fd with given mode.     __GT_BIGFILE:        same as __GT_FILE but use open64(). -   __GT_DIR:            create a directory, which will be mode 0700. +   __GT_DIR:            create a directory with given mode.  */ -int attribute_hidden __gen_tempname (char *tmpl, int kind) +int __gen_tempname (char *tmpl, int kind, mode_t mode)  {      char *XXXXXX;      unsigned int i; @@ -217,15 +217,15 @@ int attribute_hidden __gen_tempname (char *tmpl, int kind)  			fd = 0;  		}  	    case __GT_FILE: -		fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); +		fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);  		break;  #if defined __UCLIBC_HAS_LFS__  	    case __GT_BIGFILE: -		fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); +		fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);  		break;  #endif  	    case __GT_DIR: -		fd = mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); +		fd = mkdir (tmpl, mode);  		break;  	    default:  		fd = -1; diff --git a/libc/misc/internals/tempname.h b/libc/misc/internals/tempname.h index ac40bef6e..017dc5190 100644 --- a/libc/misc/internals/tempname.h +++ b/libc/misc/internals/tempname.h @@ -3,13 +3,14 @@  #define	__need_size_t  #include <stddef.h> +#include <sys/types.h>  /* Disable support for $TMPDIR */  extern int ___path_search (char *tmpl, size_t tmpl_len, const char *dir,  	        const char *pfx /*, int try_tmpdir */) attribute_hidden;  #define __path_search(tmpl, tmpl_len, dir, pfx, try_tmpdir) ___path_search(tmpl, tmpl_len, dir, pfx) -extern int __gen_tempname (char *__tmpl, int __kind) attribute_hidden; +extern int __gen_tempname (char *__tmpl, int __kind, mode_t mode);  /* The __kind argument to __gen_tempname may be one of: */  #define __GT_FILE     0       /* create a file */ diff --git a/libc/misc/pthread/Makefile.in b/libc/misc/pthread/Makefile.in index 36161238d..69cdf104a 100644 --- a/libc/misc/pthread/Makefile.in +++ b/libc/misc/pthread/Makefile.in @@ -10,8 +10,8 @@ subdirs += libc/misc/pthread  MISC_PTHREAD_DIR := $(top_srcdir)libc/misc/pthread  MISC_PTHREAD_OUT := $(top_builddir)libc/misc/pthread -libc-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/unlock.o -libc-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/weaks.o +libc-shared-$(UCLIBC_HAS_TLS) += $(MISC_PTHREAD_OUT)/tsd.os +libc-static-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/weaks.o  objclean-y += CLEAN_libc/misc/pthread diff --git a/libc/misc/pthread/tsd.c b/libc/misc/pthread/tsd.c new file mode 100644 index 000000000..835ee22ce --- /dev/null +++ b/libc/misc/pthread/tsd.c @@ -0,0 +1,10 @@ +/* libpthread sets _dl_error_catch_tsd to point to this function. +   We define it here instead of in libpthread so t here instead of in libpthread so that it doesn't +   need to have a TLS segment of its own just for this one pointer.  */ + +void ** __attribute__ ((const)) +__libc_dl_error_tsd (void) +{ +  static __thread void *data __attribute__ ((tls_model ("initial-exec"))); +  return &data; +} diff --git a/libc/misc/pthread/unlock.c b/libc/misc/pthread/unlock.c deleted file mode 100644 index 04de0df58..000000000 --- a/libc/misc/pthread/unlock.c +++ /dev/null @@ -1,27 +0,0 @@ -/* The weak pthread functions for Linux. -   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. -   This file is part of the GNU C Library. - -   The GNU C Library is free software; you can redistribute it and/or -   modify it under the terms of the GNU Library General Public License as -   published by the Free Software Foundation; either version 2 of the -   License, or (at your option) any later version. - -   The GNU C Library is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -   Library General Public License for more details. - -   You should have received a copy of the GNU Library General Public -   License along with the GNU C Library; see the file COPYING.LIB.  If not, -   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -   Boston, MA 02111-1307, USA.  */ - -#include <pthread.h> -#include <bits/uClibc_mutex.h> - -void attribute_hidden __uclibc_mutex_unlock (void *arg) -{ -	pthread_mutex_t *__mutex = (pthread_mutex_t *)arg; -	__pthread_mutex_unlock(__mutex); -} diff --git a/libc/misc/pthread/weaks.c b/libc/misc/pthread/weaks.c index 580c3eb07..fb1d85fd7 100644 --- a/libc/misc/pthread/weaks.c +++ b/libc/misc/pthread/weaks.c @@ -37,8 +37,4 @@ weak_alias (__pthread_return_0, __pthread_mutex_trylock)  weak_alias (__pthread_return_0, __pthread_mutex_unlock)  weak_alias (__pthread_return_void, _pthread_cleanup_push_defer)  weak_alias (__pthread_return_void, _pthread_cleanup_pop_restore) -#ifdef __UCLIBC_HAS_THREADS_NATIVE__ -weak_alias (__pthread_return_0, __pthread_mutexattr_init) -weak_alias (__pthread_return_0, __pthread_mutexattr_destroy) -weak_alias (__pthread_return_0, __pthread_mutexattr_settype) -#endif + diff --git a/libc/misc/sysvipc/msgq.c b/libc/misc/sysvipc/msgq.c index dac886f7f..27eb1ff92 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(ssize_t, msgrcv, int, msqid, void *, msgp, size_t, msgsz, long int, msgtyp, int, msgflg) -#else -ssize_t msgrcv (int msqid, void *msgp, size_t msgsz, -	long int msgtyp, int msgflg) +#define __NR___syscall_msgrcv __NR_msgrcv +static inline _syscall5(ssize_t, __syscall_msgrcv, int, msqid, void *, msgp, +			size_t, msgsz, long int, msgtyp, int, msgflg) +#endif +static inline ssize_t 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  } +ssize_t 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/misc/utmp/utent.c b/libc/misc/utmp/utent.c index c83f45e73..a678130a3 100644 --- a/libc/misc/utmp/utent.c +++ b/libc/misc/utmp/utent.c @@ -19,6 +19,7 @@  #include <errno.h>  #include <string.h>  #include <utmp.h> +#include <not-cancel.h>  #include <bits/uClibc_mutex.h>  __UCLIBC_MUTEX_STATIC(utmplock, PTHREAD_MUTEX_INITIALIZER); @@ -46,16 +47,16 @@ static const char *static_ut_name = default_file_name;  static_if_threaded void __setutent(void)  {      if (static_fd < 0) { -	static_fd = open(static_ut_name, O_RDWR | O_CLOEXEC); +	static_fd = open_not_cancel_2(static_ut_name, O_RDWR | O_CLOEXEC);  	if (static_fd < 0) { -	    static_fd = open(static_ut_name, O_RDONLY | O_CLOEXEC); +	    static_fd = open_not_cancel_2(static_ut_name, O_RDONLY | O_CLOEXEC);  	    if (static_fd < 0) {  		return; /* static_fd remains < 0 */  	    }  	}  #ifndef __ASSUME_O_CLOEXEC  	/* Make sure the file will be closed on exec()  */ -	fcntl(static_fd, F_SETFD, FD_CLOEXEC); +	fcntl_not_cancel(static_fd, F_SETFD, FD_CLOEXEC);  #endif  	return;      } @@ -81,7 +82,7 @@ static_if_threaded struct utmp *__getutent(void)  	}      } -    if (read(static_fd, &static_utmp, sizeof(static_utmp)) == sizeof(static_utmp)) { +    if (read_not_cancel(static_fd, &static_utmp, sizeof(static_utmp)) == sizeof(static_utmp)) {  	return &static_utmp;      } @@ -103,7 +104,7 @@ void endutent(void)  {      __UCLIBC_MUTEX_LOCK(utmplock);      if (static_fd >= 0) -	close(static_fd); +	close_not_cancel_no_status(static_fd);      static_fd = -1;      __UCLIBC_MUTEX_UNLOCK(utmplock);  } @@ -193,7 +194,7 @@ int utmpname(const char *new_ut_name)      }      if (static_fd >= 0) { -	close(static_fd); +	close_not_cancel_no_status(static_fd);  	static_fd = -1;      }      __UCLIBC_MUTEX_UNLOCK(utmplock); diff --git a/libc/misc/utmp/wtent.c b/libc/misc/utmp/wtent.c index e73d99feb..5ab743d9b 100644 --- a/libc/misc/utmp/wtent.c +++ b/libc/misc/utmp/wtent.c @@ -13,6 +13,7 @@  #include <utmp.h>  #include <fcntl.h>  #include <sys/file.h> +#include <not-cancel.h>  #if 0  /* This is enabled in uClibc/libutil/logwtmp.c */ @@ -36,12 +37,12 @@ void updwtmp(const char *wtmp_file, const struct utmp *lutmp)  {      int fd; -    fd = open(wtmp_file, O_APPEND | O_WRONLY); +    fd = open_not_cancel(wtmp_file, O_APPEND | O_WRONLY, 0);      if (fd >= 0) {  	if (lockf(fd, F_LOCK, 0) == 0) { -	    write(fd, lutmp, sizeof(*lutmp)); +	    write_not_cancel(fd, lutmp, sizeof(struct utmp));  	    lockf(fd, F_ULOCK, 0); -	    close(fd); +	    close_not_cancel_no_status(fd);  	}      }  } diff --git a/libc/signal/Makefile.in b/libc/signal/Makefile.in index 3d989c487..a7e307871 100644 --- a/libc/signal/Makefile.in +++ b/libc/signal/Makefile.in @@ -16,6 +16,10 @@ CSRC-$(UCLIBC_HAS_OBSOLETE_BSD_SIGNAL) += \  CSRC-$(UCLIBC_HAS_OBSOLETE_SYSV_SIGNAL) += sysv_signal.c  CSRC-$(UCLIBC_SUSV4_LEGACY) += sigintr.c +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC-y:=$(filter-out raise.c sigaction.c,$(CSRC-y)) +endif +  ifneq ($(strip $(ARCH_OBJS)),)  CSRC-y := $(filter-out $(notdir $(ARCH_OBJS:.o=.c)),$(CSRC-y))  endif diff --git a/libc/signal/sigpause.c b/libc/signal/sigpause.c index 5f7ed699a..0856ba2e6 100644 --- a/libc/signal/sigpause.c +++ b/libc/signal/sigpause.c @@ -23,6 +23,9 @@  #define __FAVOR_BSD  #include <signal.h>  #include <stddef.h>		/* For NULL.  */ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#endif  #include "sigset-cvt-mask.h" @@ -43,6 +46,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) @@ -54,5 +60,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 d0421f3d3..8fd7ea81f 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 @@ -23,19 +24,86 @@  #include <string.h>  #include <unistd.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 */ @@ -95,4 +163,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/stdio/_fopen.c b/libc/stdio/_fopen.c index 96377ee44..2db27a898 100644 --- a/libc/stdio/_fopen.c +++ b/libc/stdio/_fopen.c @@ -99,7 +99,7 @@ FILE attribute_hidden *_stdio_fopen(intptr_t fname_or_mode,  #ifdef __UCLIBC_HAS_THREADS__  		/* We only initialize the mutex in the non-freopen case. */  		/* stream->__user_locking = _stdio_user_locking; */ -		__stdio_init_mutex(&stream->__lock); +		STDIO_INIT_MUTEX(stream->__lock);  #endif  	} @@ -197,7 +197,7 @@ FILE attribute_hidden *_stdio_fopen(intptr_t fname_or_mode,  #ifdef __UCLIBC_HAS_THREADS__  	/* Even in the freopen case, we reset the user locking flag. */  	stream->__user_locking = _stdio_user_locking; -	/* __stdio_init_mutex(&stream->__lock); */ +	/* STDIO_INIT_MUTEX(stream->__lock); */  #endif  #ifdef __STDIO_HAS_OPENLIST diff --git a/libc/stdio/_scanf.c b/libc/stdio/_scanf.c index 914311877..34c1c9abd 100644 --- a/libc/stdio/_scanf.c +++ b/libc/stdio/_scanf.c @@ -235,7 +235,7 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap)  #ifdef __UCLIBC_HAS_THREADS__  	f.__user_locking = 1;		/* Set user locking. */ -	__stdio_init_mutex(&f.__lock); +	STDIO_INIT_MUTEX(f.__lock);  #endif  	f.__nextopen = NULL; @@ -283,7 +283,7 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap)  #ifdef __UCLIBC_HAS_THREADS__  	f.f.__user_locking = 1;		/* Set user locking. */ -	__stdio_init_mutex(&f.f.__lock); +	STDIO_INIT_MUTEX(f.f.__lock);  #endif  	f.f.__nextopen = NULL; @@ -388,8 +388,10 @@ int vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict format,  {  	FILE f; -	f.__bufstart = f.__bufpos = (unsigned char *) str; -	f.__bufread = f.__bufend = (unsigned char *) (str + wcslen(str)); +	f.__bufstart = +	f.__bufpos = (char *) str; +	f.__bufread = +	f.__bufend = (char *)(str + wcslen(str));  	__STDIO_STREAM_DISABLE_GETC(&f);  	__STDIO_STREAM_DISABLE_PUTC(&f); @@ -414,7 +416,7 @@ int vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict format,  #ifdef __UCLIBC_HAS_THREADS__  	f.__user_locking = 1;		/* Set user locking. */ -	__stdio_init_mutex(&f.__lock); +	STDIO_INIT_MUTEX(f.__lock);  #endif  	f.__nextopen = NULL; diff --git a/libc/stdio/_stdio.c b/libc/stdio/_stdio.c index 3c8d667d2..6c11451fc 100644 --- a/libc/stdio/_stdio.c +++ b/libc/stdio/_stdio.c @@ -74,8 +74,13 @@  #endif  #ifdef __UCLIBC_HAS_THREADS__ +#ifdef __USE_STDIO_FUTEXES__ +#define __STDIO_FILE_INIT_THREADSAFE \ +	2, _LIBC_LOCK_RECURSIVE_INITIALIZER, +#else  #define __STDIO_FILE_INIT_THREADSAFE \  	2, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, +#endif  #else  #define __STDIO_FILE_INIT_THREADSAFE  #endif @@ -152,14 +157,13 @@ FILE *__stdout = _stdio_streams + 1; /* For putchar() macro. */  FILE *_stdio_openlist = _stdio_streams;  # ifdef __UCLIBC_HAS_THREADS__ -__UCLIBC_MUTEX_INIT(_stdio_openlist_add_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); -#ifdef __STDIO_BUFFERS -__UCLIBC_MUTEX_INIT(_stdio_openlist_del_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); +__UCLIBC_IO_MUTEX_INIT(_stdio_openlist_add_lock); +#  ifdef __STDIO_BUFFERS +__UCLIBC_IO_MUTEX_INIT(_stdio_openlist_del_lock);  volatile int _stdio_openlist_use_count = 0;  int _stdio_openlist_del_count = 0; -#endif +#  endif  # endif -  #endif  /**********************************************************************/  #ifdef __UCLIBC_HAS_THREADS__ @@ -167,6 +171,7 @@ int _stdio_openlist_del_count = 0;  /* 2 if threading not initialized and 0 otherwise; */  int _stdio_user_locking = 2; +#ifndef __USE_STDIO_FUTEXES__  void attribute_hidden __stdio_init_mutex(__UCLIBC_MUTEX_TYPE *m)  {  	const __UCLIBC_MUTEX_STATIC(__stdio_mutex_initializer, @@ -174,6 +179,7 @@ void attribute_hidden __stdio_init_mutex(__UCLIBC_MUTEX_TYPE *m)  	memcpy(m, &__stdio_mutex_initializer, sizeof(__stdio_mutex_initializer));  } +#endif  #endif  /**********************************************************************/ @@ -189,10 +195,10 @@ void attribute_hidden _stdio_term(void)  	 * locked, then I suppose there is a chance that a pointer in the  	 * chain might be corrupt due to a partial store.  	 */ -	__stdio_init_mutex(&_stdio_openlist_add_lock); +	STDIO_INIT_MUTEX(_stdio_openlist_add_lock);  #warning check  #ifdef __STDIO_BUFFERS -	__stdio_init_mutex(&_stdio_openlist_del_lock); +	STDIO_INIT_MUTEX(_stdio_openlist_del_lock);  #endif  	/* Next we need to worry about the streams themselves.  If a stream @@ -214,7 +220,7 @@ void attribute_hidden _stdio_term(void)  		}  		ptr->__user_locking = 1; /* Set locking mode to "by caller". */ -		__stdio_init_mutex(&ptr->__lock); /* Shouldn't be necessary, but... */ +		STDIO_INIT_MUTEX(ptr->__lock); /* Shouldn't be necessary, but... */  	}  #endif diff --git a/libc/stdio/_stdio.h b/libc/stdio/_stdio.h index aaa3ad656..ec98f9e0e 100644 --- a/libc/stdio/_stdio.h +++ b/libc/stdio/_stdio.h @@ -24,18 +24,18 @@  #include <bits/uClibc_mutex.h>  #define __STDIO_THREADLOCK_OPENLIST_ADD			\ -        __UCLIBC_MUTEX_LOCK(_stdio_openlist_add_lock) +        __UCLIBC_IO_MUTEX_LOCK(_stdio_openlist_add_lock)  #define __STDIO_THREADUNLOCK_OPENLIST_ADD		\ -        __UCLIBC_MUTEX_UNLOCK(_stdio_openlist_add_lock) +        __UCLIBC_IO_MUTEX_UNLOCK(_stdio_openlist_add_lock)  #ifdef __STDIO_BUFFERS  #define __STDIO_THREADLOCK_OPENLIST_DEL			\ -        __UCLIBC_MUTEX_LOCK(_stdio_openlist_del_lock) +        __UCLIBC_IO_MUTEX_LOCK(_stdio_openlist_del_lock)  #define __STDIO_THREADUNLOCK_OPENLIST_DEL		\ -        __UCLIBC_MUTEX_UNLOCK(_stdio_openlist_del_lock) +        __UCLIBC_IO_MUTEX_UNLOCK(_stdio_openlist_del_lock)  #ifdef __UCLIBC_HAS_THREADS__ diff --git a/libc/stdio/fflush.c b/libc/stdio/fflush.c index 8b918d6bb..d9104a42f 100644 --- a/libc/stdio/fflush.c +++ b/libc/stdio/fflush.c @@ -18,11 +18,11 @@   * when all (lbf) writing streams are flushed. */  #define __MY_STDIO_THREADLOCK(__stream)					\ -        __UCLIBC_MUTEX_CONDITIONAL_LOCK((__stream)->__lock,		\ +        __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK((__stream)->__lock,		\  	(_stdio_user_locking != 2))  #define __MY_STDIO_THREADUNLOCK(__stream)				\ -        __UCLIBC_MUTEX_CONDITIONAL_UNLOCK((__stream)->__lock,		\ +        __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK((__stream)->__lock,		\  	(_stdio_user_locking != 2))  #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS) diff --git a/libc/stdio/tempnam.c b/libc/stdio/tempnam.c index faf7c5ecb..66c905db8 100644 --- a/libc/stdio/tempnam.c +++ b/libc/stdio/tempnam.c @@ -36,7 +36,7 @@ tempnam (const char *dir, const char *pfx)    if (__path_search (buf, FILENAME_MAX, dir, pfx, 1))      return NULL; -  if (__gen_tempname (buf, __GT_NOCREATE)) +  if (__gen_tempname (buf, __GT_NOCREATE, 0))      return NULL;    return strdup (buf); diff --git a/libc/stdio/tmpfile.c b/libc/stdio/tmpfile.c index 2f973c329..c6b2dc8a9 100644 --- a/libc/stdio/tmpfile.c +++ b/libc/stdio/tmpfile.c @@ -18,8 +18,10 @@  #include <features.h>  #include <stdio.h> +#include <sys/stat.h>  #include <unistd.h>  #include "../misc/internals/tempname.h" +#include <not-cancel.h>  /* This returns a new stream opened on a temporary file (generated @@ -34,7 +36,7 @@ FILE * tmpfile (void)      if (__path_search (buf, FILENAME_MAX, NULL, "tmpf", 0))  	return NULL; -    fd = __gen_tempname (buf, __GT_FILE); +    fd = __gen_tempname (buf, __GT_FILE, S_IRUSR | S_IWUSR);      if (fd < 0)  	return NULL; @@ -43,7 +45,7 @@ FILE * tmpfile (void)      (void) remove (buf);      if ((f = fdopen (fd, "w+b")) == NULL) -	close (fd); +	close_not_cancel (fd);      return f;  } diff --git a/libc/stdio/tmpnam.c b/libc/stdio/tmpnam.c index 1f180e08a..323105ba4 100644 --- a/libc/stdio/tmpnam.c +++ b/libc/stdio/tmpnam.c @@ -41,7 +41,7 @@ tmpnam (char *s)  			0))      return NULL; -  if (__builtin_expect (__gen_tempname (tmpbuf, __GT_NOCREATE), 0)) +  if (__builtin_expect (__gen_tempname (tmpbuf, __GT_NOCREATE, 0), 0))      return NULL;    if (s == NULL) diff --git a/libc/stdio/tmpnam_r.c b/libc/stdio/tmpnam_r.c index eec589e39..8f616b273 100644 --- a/libc/stdio/tmpnam_r.c +++ b/libc/stdio/tmpnam_r.c @@ -28,7 +28,7 @@ char * tmpnam_r (char *s)      if (__path_search (s, L_tmpnam, NULL, NULL, 0))  	return NULL; -    if (__gen_tempname (s, __GT_NOCREATE)) +    if (__gen_tempname (s, __GT_NOCREATE, 0))  	return NULL;      return s; diff --git a/libc/stdio/vdprintf.c b/libc/stdio/vdprintf.c index e3405e411..457018bcf 100644 --- a/libc/stdio/vdprintf.c +++ b/libc/stdio/vdprintf.c @@ -49,7 +49,7 @@ int vdprintf(int filedes, const char * __restrict format, va_list arg)   * only because of fflush_unlocked. TODO? */  #if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__)  	f.__user_locking = 1;		/* Set user locking. */ -	__stdio_init_mutex(&f.__lock); +	STDIO_INIT_MUTEX(f.__lock);  #endif  	f.__nextopen = NULL; diff --git a/libc/stdio/vsnprintf.c b/libc/stdio/vsnprintf.c index 07cff3410..31adc52b6 100644 --- a/libc/stdio/vsnprintf.c +++ b/libc/stdio/vsnprintf.c @@ -43,7 +43,7 @@ int vsnprintf(char *__restrict buf, size_t size,  #if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__)  	f.__user_locking = 1;		/* Set user locking. */ -	__stdio_init_mutex(&f.__lock); +	STDIO_INIT_MUTEX(f.__lock);  #endif  	f.__nextopen = NULL; @@ -117,7 +117,7 @@ int vsnprintf(char *__restrict buf, size_t size,  #ifdef __UCLIBC_HAS_THREADS__  	f.f.__user_locking = 1;		/* Set user locking. */ -	__stdio_init_mutex(&f.f.__lock); +	STDIO_INIT_MUTEX(f.f.__lock);  #endif  	f.f.__nextopen = NULL; diff --git a/libc/stdlib/Makefile.in b/libc/stdlib/Makefile.in index 8317a8122..0f174eea5 100644 --- a/libc/stdlib/Makefile.in +++ b/libc/stdlib/Makefile.in @@ -13,7 +13,7 @@ include $(top_srcdir)libc/stdlib/malloc-standard/Makefile.in  CSRC-y := \  	abort.c getenv.c mkdtemp.c realpath.c mkstemp.c \ -	rand.c random.c random_r.c setenv.c system.c div.c ldiv.c lldiv.c \ +	rand.c random.c random_r.c setenv.c div.c ldiv.c lldiv.c \  	getpt.c drand48-iter.c jrand48.c \  	jrand48_r.c lrand48.c lrand48_r.c mrand48.c mrand48_r.c nrand48.c \  	nrand48_r.c rand_r.c srand48.c srand48_r.c seed48.c seed48_r.c \ @@ -65,7 +65,9 @@ STDLIB_SRC := $(patsubst %.c,$(STDLIB_DIR)/%.c,$(CSRC-y))  STDLIB_OBJ := $(patsubst %.c,$(STDLIB_OUT)/%.o,$(CSRC-y))  libc-y += $(STDLIB_OBJ) -libc-static-y += $(STDLIB_OUT)/atexit.o +libc-static-y += $(STDLIB_OUT)/atexit.o $(STDLIB_OUT)/system.o +libc-shared-y += $(STDLIB_OUT)/system.oS +  # this should always be the PIC version, because it could be used in shared libs  libc-nonshared-y += $(STDLIB_OUT)/atexit.os diff --git a/libc/stdlib/malloc/heap.h b/libc/stdlib/malloc/heap.h index c0c5df821..30380791f 100644 --- a/libc/stdlib/malloc/heap.h +++ b/libc/stdlib/malloc/heap.h @@ -16,11 +16,10 @@  /* On multi-threaded systems, the heap includes a lock.  */  #ifdef __UCLIBC_HAS_THREADS__ -# include <pthread.h> -# include <bits/uClibc_pthread.h> +# include <bits/uClibc_mutex.h>  # define HEAP_USE_LOCKING -# define __heap_lock(heap_lock) __pthread_mutex_lock (heap_lock) -# define __heap_unlock(heap_lock) __pthread_mutex_unlock (heap_lock) +# define __heap_lock(heap_lock) __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(*(heap_lock)) +# define __heap_unlock(heap_lock) __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(*(heap_lock))  #else  # define __heap_lock(heap_lock)  # define __heap_unlock(heap_lock) diff --git a/libc/stdlib/malloc/malloc.h b/libc/stdlib/malloc/malloc.h index 2afc3a805..0a4b43b86 100644 --- a/libc/stdlib/malloc/malloc.h +++ b/libc/stdlib/malloc/malloc.h @@ -132,13 +132,12 @@ extern int __malloc_mmb_debug;  /* Locking for multithreaded apps.  */  #ifdef __UCLIBC_HAS_THREADS__ -# include <pthread.h> -# include <bits/uClibc_pthread.h> +# include <bits/uClibc_mutex.h>  # define MALLOC_USE_LOCKING -typedef pthread_mutex_t malloc_mutex_t; -# define MALLOC_MUTEX_INIT	PTHREAD_MUTEX_INITIALIZER +typedef __UCLIBC_MUTEX_TYPE malloc_mutex_t; +# define MALLOC_MUTEX_INIT	__UCLIBC_MUTEX_INITIALIZER  # ifdef MALLOC_USE_SBRK  /* This lock is used to serialize uses of the `sbrk' function (in both @@ -146,8 +145,8 @@ typedef pthread_mutex_t malloc_mutex_t;     things will break if these multiple calls are interleaved with another     thread's use of sbrk!).  */  extern malloc_mutex_t __malloc_sbrk_lock; -#  define __malloc_lock_sbrk()	__pthread_mutex_lock (&__malloc_sbrk_lock) -#  define __malloc_unlock_sbrk() __pthread_mutex_unlock (&__malloc_sbrk_lock) +#  define __malloc_lock_sbrk()	__UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE (__malloc_sbrk_lock) +#  define __malloc_unlock_sbrk() __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE (__malloc_sbrk_lock)  # endif /* MALLOC_USE_SBRK */  #else /* !__UCLIBC_HAS_THREADS__ */ diff --git a/libc/stdlib/mkdtemp.c b/libc/stdlib/mkdtemp.c index fa9ae3b05..2bf15ae06 100644 --- a/libc/stdlib/mkdtemp.c +++ b/libc/stdlib/mkdtemp.c @@ -19,6 +19,7 @@  #include <stdio.h>  #include <stdlib.h> +#include <sys/stat.h>  #include "../misc/internals/tempname.h"  #ifdef __USE_BSD @@ -29,7 +30,7 @@     (This function comes from OpenBSD.) */  char * mkdtemp (char *template)  { -  if (__gen_tempname (template, __GT_DIR)) +  if (__gen_tempname (template, __GT_DIR, S_IRUSR | S_IWUSR | S_IXUSR))      return NULL;    else      return template; diff --git a/libc/stdlib/mkstemp.c b/libc/stdlib/mkstemp.c index c569ceaf5..ce7d7dba0 100644 --- a/libc/stdlib/mkstemp.c +++ b/libc/stdlib/mkstemp.c @@ -18,6 +18,7 @@  #include <stdio.h>  #include <stdlib.h> +#include <sys/stat.h>  #include "../misc/internals/tempname.h"  /* Generate a unique temporary file name from TEMPLATE. @@ -26,5 +27,5 @@     Then open the file and return a fd. */  int mkstemp (char *template)  { -    return __gen_tempname (template, __GT_FILE); +    return __gen_tempname (template, __GT_FILE, S_IRUSR | S_IWUSR);  } diff --git a/libc/stdlib/mkstemp64.c b/libc/stdlib/mkstemp64.c index 02a03f00e..2cdee70a2 100644 --- a/libc/stdlib/mkstemp64.c +++ b/libc/stdlib/mkstemp64.c @@ -18,6 +18,7 @@  #include <stdio.h>  #include <stdlib.h> +#include <sys/stat.h>  #include "../misc/internals/tempname.h"  /* Generate a unique temporary file name from TEMPLATE. @@ -26,5 +27,5 @@     Then open the file and return a fd. */  int mkstemp64 (char *template)  { -    return __gen_tempname (template, __GT_BIGFILE); +    return __gen_tempname (template, __GT_BIGFILE, S_IRUSR | S_IWUSR);  } diff --git a/libc/stdlib/mktemp.c b/libc/stdlib/mktemp.c index f3af1c15c..3c922e328 100644 --- a/libc/stdlib/mktemp.c +++ b/libc/stdlib/mktemp.c @@ -25,7 +25,7 @@   * they are replaced with a string that makes the filename unique.  */  char *mktemp(char *template)  { -	if (__gen_tempname (template, __GT_NOCREATE) < 0) +	if (__gen_tempname (template, __GT_NOCREATE, 0) < 0)  		/* We return the null string if we can't find a unique file name.  */  		template[0] = '\0'; diff --git a/libc/stdlib/system.c b/libc/stdlib/system.c index 99f7970c8..4f54d1df9 100644 --- a/libc/stdlib/system.c +++ b/libc/stdlib/system.c @@ -10,8 +10,18 @@  #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 +/* TODO: the cancellable version breaks on sparc currently, + * need to figure out why still + */ +#if !defined __UCLIBC_HAS_THREADS_NATIVE__ || defined __sparc__  /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */  #include <sys/syscall.h>  #ifndef __NR_vfork @@ -61,4 +71,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/string/Makefile.in b/libc/string/Makefile.in index 9be083dd0..e7f2ccde1 100644 --- a/libc/string/Makefile.in +++ b/libc/string/Makefile.in @@ -18,7 +18,10 @@ STRING_SUBARCH_OUT := $(top_builddir)libc/string/$(TARGET_ARCH)/$(TARGET_SUBARCH  STRING_SUBARCH_SSRC := $(wildcard $(STRING_SUBARCH_OUT)/*.S)  STRING_SUBARCH_SOBJ := $(patsubst $(STRING_SUBARCH_DIR)/%.S,$(STRING_SUBARCH_OUT)/%.o,$(STRING_SUBARCH_SSRC)) -STRING_SUBARCH_OBJS := $(STRING_SUBARCH_SOBJ) +STRING_SUBARCH_CSRC := $(wildcard $(STRING_SUBARCH_OUT)/*.c) +STRING_SUBARCH_COBJ := $(patsubst $(STRING_SUBARCH_DIR)/%.c,$(STRING_SUBARCH_OUT)/%.o,$(STRING_SUBARCH_CSRC)) + +STRING_SUBARCH_OBJS := $(STRING_SUBARCH_SOBJ) $(STRING_SUBARCH_COBJ)  endif  # Collect the arch specific implementation (asm, c files) diff --git a/libc/string/sh/memchr.S b/libc/string/sh/memchr.S new file mode 100644 index 000000000..6b7142f69 --- /dev/null +++ b/libc/string/sh/memchr.S @@ -0,0 +1,30 @@ +/* $Id: memchr.S,v 1.1 2000/04/14 16:49:01 mjd Exp $ + * + * "memchr" implementation of SuperH + * + * Copyright (C) 1999  Niibe Yutaka + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* + * void *memchr(const void *s, int c, size_t n); + */ + +#include <sysdep.h> + +ENTRY(memchr) +	tst	r6,r6 +	bt/s	2f +	 exts.b	r5,r5 +1:	mov.b	@r4,r1 +	cmp/eq	r1,r5 +	bt/s	3f +	 dt	r6 +	bf/s	1b +	 add	#1,r4 +2:	mov	#0,r4 +3:	rts +	 mov	r4,r0 +END(memchr) +libc_hidden_def (memchr) diff --git a/libc/string/sh/sh4/memmove.c b/libc/string/sh/sh4/memmove.c new file mode 100644 index 000000000..4d52db2ca --- /dev/null +++ b/libc/string/sh/sh4/memmove.c @@ -0,0 +1,117 @@ +/* memmove implementation for SH4 + * + * Copyright (C) 2009 STMicroelectronics Ltd. + * + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <string.h> + + +#define FPSCR_SR	(1 << 20) +#define STORE_FPSCR(x)	__asm__ volatile("sts fpscr, %0" : "=r"(x)) +#define LOAD_FPSCR(x)	__asm__ volatile("lds %0, fpscr" : : "r"(x)) + +static void fpu_optimised_copy_fwd(void *dest, const void *src, size_t len) +{ +	char *d = (char *)dest; +	char *s = (char *)src; + +	if (len >= 64) { +		unsigned long fpscr; +		int *s1; +		int *d1; + +		/* Align the dest to 4 byte boundary. */ +		while ((unsigned)d & 0x7) { +			*d++ = *s++; +			len--; +		} + +		s1 = (int *)s; +		d1 = (int *)d; + +		/* check if s is well aligned to use FPU */ +		if (!((unsigned)s1 & 0x7)) { + +			/* Align the dest to cache-line boundary */ +			while ((unsigned)d1 & 0x1c) { +				*d1++ = *s1++; +				len -= 4; +			} + +			/* Use paired single precision load or store mode for +			 * 64-bit tranfering.*/ +			STORE_FPSCR(fpscr); +			LOAD_FPSCR(FPSCR_SR); + +			while (len >= 32) { +				__asm__ volatile ("fmov @%0+,dr0":"+r" (s1)); +				__asm__ volatile ("fmov @%0+,dr2":"+r" (s1)); +				__asm__ volatile ("fmov @%0+,dr4":"+r" (s1)); +				__asm__ volatile ("fmov @%0+,dr6":"+r" (s1)); +				__asm__ +				    volatile ("fmov dr0,@%0"::"r" +					      (d1):"memory"); +				d1 += 2; +				__asm__ +				    volatile ("fmov dr2,@%0"::"r" +					      (d1):"memory"); +				d1 += 2; +				__asm__ +				    volatile ("fmov dr4,@%0"::"r" +					      (d1):"memory"); +				d1 += 2; +				__asm__ +				    volatile ("fmov dr6,@%0"::"r" +					      (d1):"memory"); +				d1 += 2; +				len -= 32; +			} +			LOAD_FPSCR(fpscr); +		} +		s = (char *)s1; +		d = (char *)d1; +		/*TODO: other subcases could be covered here?!?*/ +	} +	/* Go to per-byte copy */ +	while (len > 0) { +		*d++ = *s++; +		len--; +	} +	return; +} + +void *memmove(void *dest, const void *src, size_t len) +{ +	unsigned long int d = (long int)dest; +	unsigned long int s = (long int)src; +	unsigned long int res; + +	if (d >= s) +		res = d - s; +	else +		res = s - d; +	/* +	 * 1) dest and src are not overlap  ==> memcpy (BWD/FDW) +	 * 2) dest and src are 100% overlap ==> memcpy (BWD/FDW) +	 * 3) left-to-right overlap ==>  Copy from the beginning to the end +	 * 4) right-to-left overlap ==>  Copy from the end to the beginning +	 */ + +	if (res == 0)		/* 100% overlap */ +		memcpy(dest, src, len);	/* No overlap */ +	else if (res >= len) +		memcpy(dest, src, len); +	else { +		if (d > s)	/* right-to-left overlap */ +			memcpy(dest, src, len);	/* memcpy is BWD */ +		else		/* cannot use SH4 memcpy for this case */ +			fpu_optimised_copy_fwd(dest, src, len); +	} +	return (dest); +} + +libc_hidden_def(memmove) diff --git a/libc/string/sh/sh4/memset.S b/libc/string/sh/sh4/memset.S new file mode 100644 index 000000000..1a57cb969 --- /dev/null +++ b/libc/string/sh/sh4/memset.S @@ -0,0 +1,146 @@ +/* $Id: memset.S,v 1.1 2000/04/14 16:49:01 mjd Exp $ + * + * "memset" implementation of SuperH + * + * Copyright (C) 1999  Niibe Yutaka + * + * Copyright (c) 2009  STMicroelectronics Ltd + *   Optimised using 64bit data transfer via FPU + *   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* + *            void *memset(void *s, int c, size_t n); + */ + +#include <sysdep.h> + +#ifdef __LITTLE_ENDIAN__ +#define MEMSET_USES_FPU +/* Use paired single precision load or store mode for 64-bit tranfering. + * FPSCR.SZ=1,FPSCR.SZ=0 is well defined on both SH4-200 and SH4-300. + * Currenlty it has been only implemented and tested for little endian mode. */ +.macro FPU_SET_PAIRED_PREC +	sts	fpscr, r3 +	mov	#0x10, r0	! PR=0 SZ=1 +	shll16  r0 +	lds	r0, fpscr +.endm +.macro RESTORE_FPSCR +	lds	r3, fpscr +.endm +#endif + +ENTRY(memset) +	tst	r6,r6 +	bt/s	5f		! if n=0, do nothing +	 add	r6,r4 +	mov	#12,r0 +	cmp/gt	r6,r0 +	bt/s	4f		! if it's too small, set a byte at once +	 mov	r4,r0 +	and	#3,r0 +	cmp/eq	#0,r0 +	bt/s	2f		! It's aligned +	 sub	r0,r6 +1: +	dt	r0 +	bf/s	1b +	 mov.b	r5,@-r4 +2:				! make VVVV +	extu.b	r5,r5 +	swap.b	r5,r0		!   V0 +	or	r0,r5		!   VV +	swap.w	r5,r0		! VV00 +	or	r0,r5		! VVVV + +	! Enough bytes need to be copied +	mov	#0x40, r0	! (MT) +	cmp/gt	r6,r0		! (MT)  64 > len => slow loop + +	bt/s	22f +	 mov	r6,r0 + +	! align the dst to the cache block size if necessary +	mov	r4, r3 +	mov	#~(0x1f), r1 + +	and	r3, r1 +	cmp/eq	r3, r1 + +	bt/s	11f		! dst is already aligned +	 sub	r1, r3		! r3-r1 -> r3 +	shlr2	r3		! number of loops + +10:	mov.l	r5,@-r4 +	dt	r3 +	bf/s	10b +	 add	#-4, r6 + +11:	! dst is 32byte aligned +	mov	r6,r2 +	mov	#-5,r0 +	shld	r0,r2		! number of loops + +#ifdef MEMSET_USES_FPU +	lds	r5, fpul	! (CO) +	fsts	fpul, fr0	! Dr0 will be 'VVVVVVVV' +	fsts	fpul, fr1 + +	FPU_SET_PAIRED_PREC +12: +	add	#-0x20, r6	!(MT) +	fmov	dr0, @-r4 +	fmov	dr0, @-r4 +	fmov	dr0, @-r4 +	dt	r2 +	bf/s	12b		!(BR) +	 fmov	dr0, @-r4 + +	RESTORE_FPSCR +#else +12: +	mov.l	r5,@-r4 +	mov.l	r5,@-r4 +	mov.l	r5,@-r4 +	mov.l	r5,@-r4 +	mov.l	r5,@-r4 +	mov.l	r5,@-r4 +	add	#-0x20, r6 +	mov.l	r5,@-r4 +	dt	r2 +	bf/s	12b +	 mov.l	r5,@-r4 +#endif +	tst	r6,r6 +	bt/s	5f +	 mov	#8, r0 + +	cmp/ge	r0, r6 +	bf/s	4f +	 mov	r6,r0 +22: +	shlr2	r0 +	shlr	r0		! r0 = r6 >> 3 +3: +	dt	r0 +	mov.l	r5,@-r4		! set 8-byte at once +	bf/s	3b +	 mov.l	r5,@-r4 +	! +	mov	#7,r0 +	and	r0,r6 +	tst	r6,r6 +	bt	5f +	! fill bytes +4: +	dt	r6 +	bf/s	4b +	 mov.b	r5,@-r4 +5: +	rts +	 mov	r4,r0 +END(memset) +libc_hidden_def (memset) diff --git a/libc/string/sh/sh4/strcpy.S b/libc/string/sh/sh4/strcpy.S new file mode 100644 index 000000000..0f8278017 --- /dev/null +++ b/libc/string/sh/sh4/strcpy.S @@ -0,0 +1,28 @@ +/* strcpy implementation for SUPERH + * + * Copyright (C) 2009 STMicroelectronics Ltd. + * + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* +	char *strcpy(char *dest, const char *src); + */ + +#include <sysdep.h> + +ENTRY(strcpy) +	mov	r4,r2 +1: +	mov.b	@r5+,r1 +	tst	r1,r1 +	mov.b	r1,@r2 +	bf/s	1b +	 add	#1,r2 + +	rts +	 mov	r4,r0 +END(strcpy) +libc_hidden_def (strcpy) diff --git a/libc/string/sh/sh4/strncpy.S b/libc/string/sh/sh4/strncpy.S new file mode 100644 index 000000000..8a16f39d4 --- /dev/null +++ b/libc/string/sh/sh4/strncpy.S @@ -0,0 +1,43 @@ +/* strncpy implementation for SUPERH + * + * Copyright (C) 2009 STMicroelectronics Ltd. + * + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* +	char *strncpy(char *dest, const char *src, size_t n); + */ + +#include <sysdep.h> + +ENTRY(strncpy) +	mov	#0,r0 +	bra	2f +	 mov	r4,r2 +1: +	mov.b	r1,@(r0,r2) +	add	#1,r0 +2: +	cmp/hs	r6,r0 +	bt	5f +	mov.b	@(r0,r5),r1 +	tst	r1,r1 +	bf/s	1b +	 cmp/hs	r6,r0 +	bra	4f +	 nop +3: +	mov.b	r1,@(r0,r2) +	add	#1,r0 +	cmp/hs	r6,r0 +4: +	bf/s	3b +	 mov	#0,r1 +5: +	rts +	 mov     r2,r0 +END(strncpy) +libc_hidden_def(strncpy) diff --git a/libc/string/sh/strlen.S b/libc/string/sh/strlen.S new file mode 100644 index 000000000..1ccecc17b --- /dev/null +++ b/libc/string/sh/strlen.S @@ -0,0 +1,75 @@ +/* $Id: strlen.S,v 1.2 2001/06/29 14:07:15 gniibe Exp $ + * + * "strlen" implementation of SuperH + * + * Copyright (C) 1999  Kaz Kojima + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* size_t strlen (const char *s)  */ + +#include <sysdep.h> +#include <endian.h> + +ENTRY(strlen) +	mov	r4,r0 +	and	#3,r0 +	tst	r0,r0 +	bt/s	1f +	 mov	#0,r2 + +	add	#-1,r0 +	shll2	r0 +	shll	r0 +	braf	r0 +	 nop + +	mov.b	@r4+,r1 +	tst	r1,r1 +	bt	8f +	add	#1,r2 + +	mov.b	@r4+,r1 +	tst	r1,r1 +	bt	8f +	add	#1,r2 + +	mov.b	@r4+,r1 +	tst	r1,r1 +	bt	8f +	add	#1,r2 + +1: +	mov	#0,r3 +2: +	mov.l	@r4+,r1 +	cmp/str	r3,r1 +	bf/s	2b +	 add	#4,r2 + +	add	#-4,r2 +#ifndef __LITTLE_ENDIAN__ +	swap.b	r1,r1 +	swap.w	r1,r1 +	swap.b	r1,r1 +#endif +	extu.b	r1,r0 +	tst	r0,r0 +	bt/s	8f +	 shlr8	r1 +	add	#1,r2 +	extu.b	r1,r0 +	tst	r0,r0 +	bt/s	8f +	 shlr8	r1 +	add	#1,r2 +	extu.b	r1,r0 +	tst	r0,r0 +	bt	8f +	add	#1,r2 +8: +	rts +	 mov	r2,r0 +END(strlen) +libc_hidden_def (strlen) diff --git a/libc/sysdeps/linux/arm/Makefile.arch b/libc/sysdeps/linux/arm/Makefile.arch index c3c55258a..bec06ff44 100644 --- a/libc/sysdeps/linux/arm/Makefile.arch +++ b/libc/sysdeps/linux/arm/Makefile.arch @@ -5,14 +5,24 @@  # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.  # -CSRC := brk.c ioperm.c iopl.c mmap.c sigaction.c __syscall_error.c +CSRC := brk.c ioperm.c iopl.c mmap.c __syscall_error.c + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +endif  SSRC := \ -	__longjmp.S vfork.S clone.S setjmp.S bsd-setjmp.S \ +	__longjmp.S setjmp.S bsd-setjmp.S \  	bsd-_setjmp.S sigrestorer.S mmap64.S +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +SSRC += libc-aeabi_read_tp.S libc-thumb_atomics.S +else +SSRC += vfork.S clone.S +endif +  ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y) -        CSRC += posix_fadvise.c posix_fadvise64.c +CSRC += posix_fadvise.c posix_fadvise64.c  endif  ifeq ($(CONFIG_ARM_EABI),y) diff --git a/libc/sysdeps/linux/arm/clone.S b/libc/sysdeps/linux/arm/clone.S index d9483735d..fdc05b88b 100644 --- a/libc/sysdeps/linux/arm/clone.S +++ b/libc/sysdeps/linux/arm/clone.S @@ -30,12 +30,12 @@  /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */  .text -.global clone -.type clone,%function +.global __clone +.type __clone,%function  .align 2  #if defined(THUMB1_ONLY)  .thumb_func -clone: +__clone:  	@ sanity check args  	cmp	r0, #0  	beq	__einval @@ -52,9 +52,15 @@ clone:  	@ get flags  	mov	r0, r2  	@ new sp is already in r1 +	@ load remaining arguments off the stack +	stmfd	sp!, {r4} +	ldr	r2, [sp, #4] +	ldr	r3, [sp, #8] +	ldr	r4, [sp, #12]  	DO_CALL (clone)  	movs	a1, a1  	blt	__error +	ldmnefd sp!, {r4}  	beq	1f  	bx	lr  1: @@ -80,7 +86,7 @@ __error:  	POP_RET  .pool  #else -clone: +__clone:  	@ sanity check args  	cmp	r0, #0  	IT(te, ne) @@ -98,9 +104,15 @@ clone:  	@ get flags  	mov	r0, r2  	@ new sp is already in r1 +	@ load remaining arguments off the stack +	stmfd	sp!, {r4} +	ldr	r2, [sp, #4] +	ldr	r3, [sp, #8] +	ldr	r4, [sp, #12]  	DO_CALL (clone)  	movs	a1, a1  	blt	__error +	ldmnefd	sp!, {r4}  	IT(t, ne)  #if defined(__USE_BX__)  	bxne	lr @@ -120,6 +132,7 @@ __error:  	b	__syscall_error  #endif -.size clone,.-clone +.size __clone,.-__clone +weak_alias(__clone, clone)  #endif diff --git a/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S b/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S new file mode 100644 index 000000000..3aa135bf2 --- /dev/null +++ b/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S @@ -0,0 +1 @@ +#include <ldso/ldso/arm/aeabi_read_tp.S> diff --git a/libc/sysdeps/linux/arm/libc-thumb_atomics.S b/libc/sysdeps/linux/arm/libc-thumb_atomics.S new file mode 100644 index 000000000..e7bc8950d --- /dev/null +++ b/libc/sysdeps/linux/arm/libc-thumb_atomics.S @@ -0,0 +1 @@ +#include <ldso/ldso/arm/thumb_atomics.S> diff --git a/libc/sysdeps/linux/arm/sysdep.h b/libc/sysdeps/linux/arm/sysdep.h new file mode 100644 index 000000000..b1ae2fdb0 --- /dev/null +++ b/libc/sysdeps/linux/arm/sysdep.h @@ -0,0 +1,367 @@ +/* Assembler macros for ARM. +   Copyright (C) 1997, 1998, 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LINUX_ARM_SYSDEP_H +#define _LINUX_ARM_SYSDEP_H 1 + +#include <common/sysdep.h> + +#include <sys/syscall.h> +/* For Linux we can use the system call table in the header file +	/usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ +#undef SYS_ify +#define SWI_BASE  (0x900000) +#define SYS_ify(syscall_name)	(__NR_##syscall_name) + +#ifdef	__ASSEMBLER__ + +/* Syntactic details of assembler.  */ + +#define ALIGNARG(log2) log2 +/* For ELF we need the `.type' directive to make shared libs work right.  */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,%##typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +/* In ELF C symbols are asm symbols.  */ +#undef	NO_UNDERSCORES +#define NO_UNDERSCORES + +#define PLTJMP(_x)	_x##(PLT) + +/* APCS-32 doesn't preserve the condition codes across function call. */ +#ifdef __APCS_32__ +#define LOADREGS(cond, base, reglist...)\ +	ldm##cond	base,reglist +#ifdef __USE_BX__ +#define RETINSTR(cond, reg)	\ +	bx##cond	reg +#define DO_RET(_reg)		\ +	bx _reg +#else +#define RETINSTR(cond, reg)	\ +	mov##cond	pc, reg +#define DO_RET(_reg)		\ +	mov pc, _reg +#endif +#else  /* APCS-26 */ +#define LOADREGS(cond, base, reglist...)	\ +	ldm##cond	base,reglist^ +#define RETINSTR(cond, reg)	\ +	mov##cond##s	pc, reg +#define DO_RET(_reg)		\ +	movs pc, _reg +#endif + +/* Define an entry point visible from C.  */ +#define	ENTRY(name)						\ +  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);			\ +  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function)		\ +  .align ALIGNARG(4);						\ +  name##:							\ +  CALL_MCOUNT + +#undef	END +#define END(name)						\ +  ASM_SIZE_DIRECTIVE(name) + +/* If compiled for profiling, call `mcount' at the start of each function.  */ +#ifdef	PROF +#define CALL_MCOUNT			\ +	str	lr,[sp, #-4]!	;	\ +	bl	PLTJMP(mcount)	;	\ +	ldr	lr, [sp], #4	; +#else +#define CALL_MCOUNT		/* Do nothing.  */ +#endif + +#ifdef	NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore +   on this system, the asm identifier `syscall_error' intrudes on the +   C name space.  Make sure we use an innocuous name.  */ +#define	syscall_error	__syscall_error +#define mcount		_mcount +#endif +/* Linux uses a negative return value to indicate syscall errors, +   unlike most Unices, which use the condition codes' carry flag. + +   Since version 2.1 the return value of a system call might be +   negative even if the call succeeded.  E.g., the `lseek' system call +   might return a large offset.  Therefore we must not anymore test +   for < 0, but test for a real error by making sure the value in R0 +   is a real error number.  Linus said he will make sure the no syscall +   returns a value in -1 .. -4095 as a valid result so we can safely +   test with -4095.  */ + +#undef	PSEUDO +#define	PSEUDO(name, syscall_name, args)				\ +  .text;								\ +  ENTRY (name);								\ +    DO_CALL (syscall_name, args);					\ +    cmn r0, $4096; + +#define PSEUDO_RET							\ +    RETINSTR(cc, lr);							\ +    b PLTJMP(SYSCALL_ERROR) +#undef ret +#define ret PSEUDO_RET + +#undef	PSEUDO_END +#define	PSEUDO_END(name)						\ +  SYSCALL_ERROR_HANDLER							\ +  END (name) + +#undef	PSEUDO_NOERRNO +#define	PSEUDO_NOERRNO(name, syscall_name, args)			\ +  .text;								\ +  ENTRY (name);								\ +    DO_CALL (syscall_name, args); + +#define PSEUDO_RET_NOERRNO						\ +    DO_RET (lr); + +#undef ret_NOERRNO +#define ret_NOERRNO PSEUDO_RET_NOERRNO + +#undef	PSEUDO_END_NOERRNO +#define	PSEUDO_END_NOERRNO(name)					\ +  END (name) + +/* The function has to return the error code.  */ +#undef	PSEUDO_ERRVAL +#define	PSEUDO_ERRVAL(name, syscall_name, args) \ +  .text;								\ +  ENTRY (name)								\ +    DO_CALL (syscall_name, args);					\ +    rsb r0, r0, #0 + +#undef	PSEUDO_END_ERRVAL +#define	PSEUDO_END_ERRVAL(name) \ +  END (name) + +#define ret_ERRVAL PSEUDO_RET_NOERRNO + +#if NOT_IN_libc +# define SYSCALL_ERROR __local_syscall_error +# ifdef RTLD_PRIVATE_ERRNO +#  define SYSCALL_ERROR_HANDLER					\ +__local_syscall_error:						\ +       ldr     r1, 1f;						\ +       rsb     r0, r0, #0;					\ +0:     str     r0, [pc, r1];					\ +       mvn     r0, #0;						\ +       DO_RET(lr);						\ +1:     .word C_SYMBOL_NAME(rtld_errno) - 0b - 8; +# else +#  define SYSCALL_ERROR_HANDLER					\ +__local_syscall_error:						\ +	str	lr, [sp, #-4]!;					\ +	str	r0, [sp, #-4]!;					\ +	bl	PLTJMP(C_SYMBOL_NAME(__errno_location)); 	\ +	ldr	r1, [sp], #4;					\ +	rsb	r1, r1, #0;					\ +	str	r1, [r0];					\ +	mvn	r0, #0;						\ +	ldr	pc, [sp], #4; +# endif +#else +# define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */ +# define SYSCALL_ERROR __syscall_error +#endif + +/* Linux takes system call args in registers: +	syscall number	in the SWI instruction +	arg 1		r0 +	arg 2		r1 +	arg 3		r2 +	arg 4		r3 +	arg 5		r4	(this is different from the APCS convention) +	arg 6		r5 +	arg 7		r6 + +   The compiler is going to form a call by coming here, through PSEUDO, with +   arguments +	syscall number	in the DO_CALL macro +	arg 1		r0 +	arg 2		r1 +	arg 3		r2 +	arg 4		r3 +	arg 5		[sp] +	arg 6		[sp+4] +	arg 7		[sp+8] + +   We need to shuffle values between R4..R6 and the stack so that the +   caller's v1..v3 and stack frame are not corrupted, and the kernel +   sees the right arguments. + +*/ + +#undef	DO_CALL +#if defined(__ARM_EABI__) +#define DO_CALL(syscall_name, args)		\ +    DOARGS_##args				\ +    mov ip, r7;					\ +    ldr r7, =SYS_ify (syscall_name);		\ +    swi 0x0;					\ +    mov r7, ip;					\ +    UNDOARGS_##args +#else +#define DO_CALL(syscall_name, args)		\ +    DOARGS_##args				\ +    swi SYS_ify (syscall_name); 		\ +    UNDOARGS_##args +#endif + +#define DOARGS_0 /* nothing */ +#define DOARGS_1 /* nothing */ +#define DOARGS_2 /* nothing */ +#define DOARGS_3 /* nothing */ +#define DOARGS_4 /* nothing */ +#define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4]; +#define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5}; +#define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6}; + +#define UNDOARGS_0 /* nothing */ +#define UNDOARGS_1 /* nothing */ +#define UNDOARGS_2 /* nothing */ +#define UNDOARGS_3 /* nothing */ +#define UNDOARGS_4 /* nothing */ +#define UNDOARGS_5 ldr r4, [sp], $4; +#define UNDOARGS_6 ldmfd sp!, {r4, r5}; +#define UNDOARGS_7 ldmfd sp!, {r4, r5, r6}; + +#else /* not __ASSEMBLER__ */ +/* Define a macro which expands into the inline wrapper code for a system +   call.  */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...)				\ +  ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args);	\ +     if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))	\ +       {								\ +	 __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, ));		\ +	 _sys_result = (unsigned int) -1;				\ +       }								\ +     (int) _sys_result; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) do { } while (0) + +#undef INTERNAL_SYSCALL_RAW +#if defined(__thumb__) +/* Hide the use of r7 from the compiler, this would be a lot + * easier but for the fact that the syscalls can exceed 255. + * For the moment the LOAD_ARG_7 is sacrificed. + * We can't use push/pop inside the asm because that breaks + * unwinding (ie. thread cancellation). + */ +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...)		\ +  ({ unsigned int _sys_result;					\ +    {								\ +      int _sys_buf[2];						\ +      register int _a1 __asm__ ("a1");				\ +      register int *_v3 __asm__ ("v3") = _sys_buf;		\ +      LOAD_ARGS_##nr (args)					\ +      *_v3 = (int) (name);					\ +      __asm__ __volatile__ ("str	r7, [v3, #4]\n"		\ +                    "\tldr      r7, [v3]\n"			\ +                    "\tswi      0       @ syscall " #name "\n"	\ +                    "\tldr      r7, [v3, #4]"			\ +                   : "=r" (_a1)					\ +                    : "r" (_v3) ASM_ARGS_##nr			\ +                    : "memory");				\ +      _sys_result = _a1;					\ +    }								\ +    (int) _sys_result; }) +#elif defined(__ARM_EABI__) +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...)		\ +  ({unsigned int _sys_result;					\ +     {								\ +       register int _a1 __asm__ ("r0"), _nr __asm__ ("r7");	\ +       LOAD_ARGS_##nr (args)					\ +       _nr = name;						\ +       __asm__ __volatile__ ("swi	0x0 @ syscall " #name	\ +		     : "=r" (_a1)				\ +		     : "r" (_nr) ASM_ARGS_##nr			\ +		     : "memory");				\ +       _sys_result = _a1;					\ +     }								\ +     (int) _sys_result; }) +#else /* !defined(__ARM_EABI__) */ +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...)		\ +  ({ unsigned int _sys_result;					\ +     {								\ +       register int _a1 __asm__ ("a1");				\ +       LOAD_ARGS_##nr (args)					\ +       __asm__ __volatile__ ("swi	%1 @ syscall " #name	\ +		     : "=r" (_a1)				\ +		     : "i" (name) ASM_ARGS_##nr			\ +		     : "memory");				\ +       _sys_result = _a1;					\ +     }								\ +     (int) _sys_result; }) +#endif + +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...)		\ +	INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args) + +#undef INTERNAL_SYSCALL_ARM +#define INTERNAL_SYSCALL_ARM(name, err, nr, args...)		\ +	INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args) + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err) \ +  ((unsigned int) (val) >= 0xfffff001u) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err)	(-(val)) + +#if defined(__ARM_EABI__) +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)		\ +	INTERNAL_SYSCALL_RAW(number, err, nr, args) +#else +/* We can't implement non-constant syscalls directly since the syscall +   number is normally encoded in the instruction.  So use SYS_syscall.  */ +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)		\ +	INTERNAL_SYSCALL_NCS_##nr (number, err, args) + +#define INTERNAL_SYSCALL_NCS_0(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 1, number, args) +#define INTERNAL_SYSCALL_NCS_1(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 2, number, args) +#define INTERNAL_SYSCALL_NCS_2(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 3, number, args) +#define INTERNAL_SYSCALL_NCS_3(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 4, number, args) +#define INTERNAL_SYSCALL_NCS_4(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 5, number, args) +#define INTERNAL_SYSCALL_NCS_5(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 6, number, args) +#endif + +#endif	/* __ASSEMBLER__ */ + +/* Pointer mangling is not yet supported for ARM.  */ +#define PTR_MANGLE(var) (void) (var) +#define PTR_DEMANGLE(var) (void) (var) + +#endif /* linux/arm/sysdep.h */ diff --git a/libc/sysdeps/linux/arm/vfork.S b/libc/sysdeps/linux/arm/vfork.S index 42595b026..17d6a4db0 100644 --- a/libc/sysdeps/linux/arm/vfork.S +++ b/libc/sysdeps/linux/arm/vfork.S @@ -12,6 +12,15 @@  #include <bits/errno.h>  #include <sys/syscall.h> +#ifndef SAVE_PID +#define SAVE_PID +#endif + +#ifndef RESTORE_PID +#define RESTORE_PID +#endif + +  #ifdef __NR_fork  .text  .global	__vfork @@ -23,7 +32,9 @@  .thumb_func  __vfork:  #ifdef __NR_vfork +	SAVE_PID  	DO_CALL (vfork) +	RESTORE_PID  	ldr		r1, =0xfffff000  	cmp		r0, r1  	bcs		1f @@ -57,7 +68,9 @@ __error:  __vfork:  #ifdef __NR_vfork +	SAVE_PID  	DO_CALL (vfork) +	RESTORE_PID  	cmn	r0, #4096  	IT(t, cc)  #if defined(__USE_BX__) diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in index 172feb162..a6fa6d091 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -34,6 +34,17 @@ CSRC := $(filter-out capget.c capset.c inotify.c ioperm.c iopl.c madvise.c \  	sync_file_range.c sysctl.c sysinfo.c timerfd.c uselib.c vhangup.c,$(CSRC))  endif +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC := $(filter-out fork.c getpid.c raise.c open.c close.c read.c write.c, $(CSRC)) +ifeq ($(TARGET_ARCH),arm) +CSRC := $(filter-out vfork.c, $(CSRC)) +else ifeq ($(TARGET_ARCH),x86_64) +CSRC := $(filter-out vfork.c, $(CSRC)) +else +CSRC := $(filter-out waitpid.c, $(CSRC)) +endif +endif +  ifneq ($(UCLIBC_BSD_SPECIFIC),y)  # we need these internally: getdomainname.c  CSRC := $(filter-out mincore.c setdomainname.c,$(CSRC)) @@ -75,6 +86,18 @@ ifneq ($(UCLIBC_SV4_DEPRECATED),y)  CSRC := $(filter-out ustat.c,$(CSRC))  endif +ifeq ($(TARGET_ARCH),sh) +CSRC := $(filter-out longjmp.c vfork.c,$(CSRC)) +endif + +ifeq ($(TARGET_ARCH),sparc) +CSRC := $(filter-out vfork.c,$(CSRC)) +endif + +ifeq ($(TARGET_ARCH),i386) +CSRC := $(filter-out vfork.c,$(CSRC)) +endif +  # fails for some reason  ifneq ($(strip $(ARCH_OBJS)),)  CSRC := $(filter-out $(notdir $(ARCH_OBJS:.o=.c)) $(ARCH_OBJ_FILTEROUT),$(CSRC)) diff --git a/libc/sysdeps/linux/common/__rt_sigtimedwait.c b/libc/sysdeps/linux/common/__rt_sigtimedwait.c index f9ec0eabf..79b94adef 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 attribute_hidden __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,5 @@ int sigtimedwait(const sigset_t * set, siginfo_t * info,  	return -1;  }  #endif -libc_hidden_def(sigwaitinfo) -libc_hidden_def(sigtimedwait) +weak_alias(__sigtimedwait,sigtimedwait) +libc_hidden_weak(sigtimedwait) diff --git a/libc/sysdeps/linux/common/__rt_sigwaitinfo.c b/libc/sysdeps/linux/common/__rt_sigwaitinfo.c new file mode 100644 index 000000000..c8953bfbc --- /dev/null +++ b/libc/sysdeps/linux/common/__rt_sigwaitinfo.c @@ -0,0 +1,102 @@ +/* vi: set sw=4 ts=4: */ +/* + * __rt_sigwaitinfo() for uClibc + * + * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com> + * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org> + * + * GNU Library General Public License (LGPL) version 2 or later. + */ + +#include <sys/syscall.h> +#include <signal.h> +#include <string.h> + +libc_hidden_proto(memcpy) + +#ifdef __NR_rt_sigtimedwait + +#include <string.h> + +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#  include <sysdep-cancel.h> + +static int do_sigwaitinfo(const sigset_t *set, siginfo_t *info) +{ +#  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, +								 NULL, _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; +} + +/* Return any pending signal or wait for one for the given time.  */ +int __sigwaitinfo(const sigset_t *set, siginfo_t *info) +{ +	if(SINGLE_THREAD_P) +		return do_sigwaitinfo(set, info); + +	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_sigwaitinfo(set, info); + +	LIBC_CANCEL_RESET(oldtype); + +	return result; +} +# else +#  define __need_NULL +#  include <stddef.h> +#  define __NR___rt_sigwaitinfo __NR_rt_sigtimedwait +static _syscall4(int, __rt_sigwaitinfo, const sigset_t *, set, +				 siginfo_t *, info, const struct timespec *, timeout, +				 size_t, setsize); + +int attribute_hidden __sigwaitinfo(const sigset_t * set, siginfo_t * info) +{ +	return __rt_sigwaitinfo(set, info, NULL, _NSIG / 8); +} +# endif +#else +int attribute_hidden __sigwaitinfo(const sigset_t * set, siginfo_t * info) +{ +	if (set == NULL) +		__set_errno(EINVAL); +	else +		__set_errno(ENOSYS); +	return -1; +} +#endif +libc_hidden_proto(sigwaitinfo) +weak_alias (__sigwaitinfo, sigwaitinfo) +libc_hidden_weak(sigwaitinfo) diff --git a/libc/sysdeps/linux/common/__syscall_fcntl.c b/libc/sysdeps/linux/common/__syscall_fcntl.c index 355b22b00..4e3bc23df 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, ...) +#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); -	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/_exit.c b/libc/sysdeps/linux/common/_exit.c index 6cece0878..51117d109 100644 --- a/libc/sysdeps/linux/common/_exit.c +++ b/libc/sysdeps/linux/common/_exit.c @@ -12,13 +12,23 @@  #include <unistd.h>  #include <sys/types.h>  #include <sys/syscall.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep.h> +#endif  void attribute_noreturn _exit(int status)  {  	/* The loop is added only to keep gcc happy. */  	while(1) +	{ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# ifdef __NR_exit_group +		INLINE_SYSCALL(exit_group, 1, status); +# endif +#endif  		INLINE_SYSCALL(exit, 1, status); +	}  }  libc_hidden_def(_exit)  weak_alias(_exit,_Exit) 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/bits/uClibc_mutex.h b/libc/sysdeps/linux/common/bits/uClibc_mutex.h index 14aeb9c80..3e3d0066a 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_mutex.h +++ b/libc/sysdeps/linux/common/bits/uClibc_mutex.h @@ -22,6 +22,9 @@  #define __UCLIBC_MUTEX_STATIC(M,I)			static pthread_mutex_t M = I  #define __UCLIBC_MUTEX_EXTERN(M)			extern pthread_mutex_t M +#define __UCLIBC_MUTEX_INIT_VAR(M)								\ +		((M) = (pthread_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +  #define __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(M)								\  		__pthread_mutex_lock(&(M)) @@ -29,12 +32,13 @@  		__pthread_mutex_unlock(&(M))  #define __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE(M)								\ -		__pthread_mutex_trylock(&(M)) +		__pthread_mutex_trylock,(&(M))  #define __UCLIBC_MUTEX_CONDITIONAL_LOCK(M,C)								\  	do {												\  		struct _pthread_cleanup_buffer __infunc_pthread_cleanup_buffer;				\ -		if (C) {										\ +		int __infunc_need_locking = (C);							\ +		if (__infunc_need_locking) {								\  			_pthread_cleanup_push_defer(&__infunc_pthread_cleanup_buffer,			\  					   (void (*) (void *))__pthread_mutex_unlock,			\  										&(M));			\ @@ -43,7 +47,7 @@  		((void)0)  #define __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M,C)								\ -		if (C) {										\ +		if (__infunc_need_locking) {								\  			_pthread_cleanup_pop_restore(&__infunc_pthread_cleanup_buffer,1);		\  		}											\  	} while (0) @@ -62,7 +66,55 @@  #define __UCLIBC_MUTEX_UNLOCK(M)									\          __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) -#else +#ifdef __USE_STDIO_FUTEXES__ + +#include <bits/stdio-lock.h> + +#define __UCLIBC_IO_MUTEX(M)			_IO_lock_t M +#define __UCLIBC_IO_MUTEX_LOCK(M) 		_IO_lock_lock(M) +#define __UCLIBC_IO_MUTEX_UNLOCK(M) 	_IO_lock_unlock(M) +#define __UCLIBC_IO_MUTEX_TRYLOCK(M) 	_IO_lock_trylock(M) +#define __UCLIBC_IO_MUTEX_INIT(M) 	_IO_lock_t M = _IO_lock_initializer +#define __UCLIBC_IO_MUTEX_EXTERN(M)		extern _IO_lock_t M + +#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C)		\ +	if (C) {										\ +		_IO_lock_lock(M);							\ +	} + +#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C)	\ +	if (C) {										\ +		_IO_lock_unlock(M);							\ +	} + +#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V)			\ +		__UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,((A=(V))) == 0) + +#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A)			\ +		__UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,((A) == 0)) + +#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M)		_IO_lock_lock(M) +#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M) 	_IO_lock_unlock(M) + +#else /* of __USE_STDIO_FUTEXES__ */ + +#define __UCLIBC_IO_MUTEX(M)                        __UCLIBC_MUTEX(M) +#define __UCLIBC_IO_MUTEX_LOCK(M)                   __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_UNLOCK(M)                 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) +#define __UCLIBC_IO_MUTEX_TRYLOCK(M)                __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_INIT(M)                   __UCLIBC_MUTEX_INIT(M, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +#define __UCLIBC_IO_MUTEX_EXTERN(M)                 __UCLIBC_MUTEX_EXTERN(M) +#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V)          __UCLIBC_MUTEX_AUTO_LOCK(M,A,V) +#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A)          __UCLIBC_MUTEX_AUTO_UNLOCK(M,A) +#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M)     __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M)   __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C)     __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C)   __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) + +#endif /* of __USE_STDIO_FUTEXES__ */ + + +#else /* of __UCLIBC_HAS_THREADS__ */  #define __UCLIBC_MUTEX(M)				void *__UCLIBC_MUTEX_DUMMY_ ## M  #define __UCLIBC_MUTEX_INIT(M,I)			extern void *__UCLIBC_MUTEX_DUMMY_ ## M @@ -83,6 +135,22 @@  #define __UCLIBC_MUTEX_LOCK(M)				((void)0)  #define __UCLIBC_MUTEX_UNLOCK(M)			((void)0) -#endif +#define __UCLIBC_IO_MUTEX(M)                        __UCLIBC_MUTEX(M) +#define __UCLIBC_IO_MUTEX_LOCK(M)                   __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_UNLOCK(M)                 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) +#define __UCLIBC_IO_MUTEX_TRYLOCK(M)                __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_INIT(M)                   __UCLIBC_MUTEX_INIT(M, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +#define __UCLIBC_IO_MUTEX_EXTERN(M)                 __UCLIBC_MUTEX_EXTERN(M) +#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V)          __UCLIBC_MUTEX_AUTO_LOCK(M,A,V) +#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A)          __UCLIBC_MUTEX_AUTO_UNLOCK(M,A) +#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M)     __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M)   __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C)     __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C)   __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) + +#endif /* of __UCLIBC_HAS_THREADS__ */ + +#define __UCLIBC_IO_MUTEX_TRYLOCK_CANCEL_UNSAFE(M)	\ +		__UCLIBC_IO_MUTEX_TRYLOCK(M)  #endif /* _UCLIBC_MUTEX_H */ diff --git a/libc/sysdeps/linux/common/bits/uClibc_pthread.h b/libc/sysdeps/linux/common/bits/uClibc_pthread.h index 1d6209f5e..15aa1deed 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_pthread.h +++ b/libc/sysdeps/linux/common/bits/uClibc_pthread.h @@ -28,6 +28,9 @@  #endif  #if defined _LIBC && (defined IS_IN_libc || defined NOT_IN_libc) + +struct _pthread_cleanup_buffer; +  /* Threading functions internal to uClibc.  Make these thread functions   * weak so that we can elide them from single-threaded processes.  */  extern int weak_function __pthread_mutex_init (pthread_mutex_t *__mutex, @@ -35,16 +38,14 @@ extern int weak_function __pthread_mutex_init (pthread_mutex_t *__mutex,  extern int weak_function __pthread_mutex_destroy (pthread_mutex_t *__mutex);  extern int weak_function __pthread_mutex_lock (pthread_mutex_t *__mutex);  extern int weak_function __pthread_mutex_unlock (pthread_mutex_t *__mutex); -extern void __uclibc_mutex_unlock (void *) attribute_hidden;  extern int weak_function __pthread_mutex_trylock (pthread_mutex_t *__mutex); -# ifndef __UCLIBC_HAS_THREADS_NATIVE__  extern void weak_function _pthread_cleanup_push_defer (  		struct _pthread_cleanup_buffer *__buffer,  		void (*__routine) (void *), void *__arg);  extern void weak_function _pthread_cleanup_pop_restore (  		struct _pthread_cleanup_buffer *__buffer,  		int __execute); -# endif +  #endif  #endif diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h index 3631ef79f..a8cf4eb56 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h +++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h @@ -134,26 +134,26 @@          __UCLIBC_MUTEX_AUTO_LOCK_VAR(__infunc_user_locking)  #define __STDIO_AUTO_THREADLOCK(__stream)					\ -        __UCLIBC_MUTEX_AUTO_LOCK((__stream)->__lock, __infunc_user_locking,	\ +        __UCLIBC_IO_MUTEX_AUTO_LOCK((__stream)->__lock, __infunc_user_locking,	\  	(__stream)->__user_locking)  #define __STDIO_AUTO_THREADUNLOCK(__stream)					\ -        __UCLIBC_MUTEX_AUTO_UNLOCK((__stream)->__lock, __infunc_user_locking) +        __UCLIBC_IO_MUTEX_AUTO_UNLOCK((__stream)->__lock, __infunc_user_locking)  #define __STDIO_ALWAYS_THREADLOCK(__stream)					\ -        __UCLIBC_MUTEX_LOCK((__stream)->__lock) +        __UCLIBC_IO_MUTEX_LOCK((__stream)->__lock)  #define __STDIO_ALWAYS_THREADUNLOCK(__stream)					\ -        __UCLIBC_MUTEX_UNLOCK((__stream)->__lock) +        __UCLIBC_IO_MUTEX_UNLOCK((__stream)->__lock)  #define __STDIO_ALWAYS_THREADLOCK_CANCEL_UNSAFE(__stream)			\ -        __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE((__stream)->__lock) +        __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE((__stream)->__lock)  #define __STDIO_ALWAYS_THREADTRYLOCK_CANCEL_UNSAFE(__stream)			\ -        __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE((__stream)->__lock) +        __UCLIBC_IO_MUTEX_TRYLOCK_CANCEL_UNSAFE((__stream)->__lock)  #define __STDIO_ALWAYS_THREADUNLOCK_CANCEL_UNSAFE(__stream)			\ -        __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE((__stream)->__lock) +        __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE((__stream)->__lock)  #ifdef __UCLIBC_HAS_THREADS__  #define __STDIO_SET_USER_LOCKING(__stream)	((__stream)->__user_locking = 1) @@ -161,6 +161,14 @@  #define __STDIO_SET_USER_LOCKING(__stream)		((void)0)  #endif +#ifdef __UCLIBC_HAS_THREADS__ +#ifdef __USE_STDIO_FUTEXES__ +#define STDIO_INIT_MUTEX(M) _IO_lock_init(M) +#else +#define STDIO_INIT_MUTEX(M) __stdio_init_mutex(& M) +#endif +#endif +  /**********************************************************************/  #define __STDIO_IOFBF 0		/* Fully buffered.  */ @@ -275,7 +283,7 @@ struct __STDIO_FILE_STRUCT {  #endif  #ifdef __UCLIBC_HAS_THREADS__  	int __user_locking; -	__UCLIBC_MUTEX(__lock); +	__UCLIBC_IO_MUTEX(__lock);  #endif  /* Everything after this is unimplemented... and may be trashed. */  #if __STDIO_BUILTIN_BUF_SIZE > 0 @@ -351,9 +359,9 @@ extern void _stdio_term(void) attribute_hidden;  extern struct __STDIO_FILE_STRUCT *_stdio_openlist;  #ifdef __UCLIBC_HAS_THREADS__ -__UCLIBC_MUTEX_EXTERN(_stdio_openlist_add_lock); +__UCLIBC_IO_MUTEX_EXTERN(_stdio_openlist_add_lock);  #ifdef __STDIO_BUFFERS -__UCLIBC_MUTEX_EXTERN(_stdio_openlist_del_lock); +__UCLIBC_IO_MUTEX_EXTERN(_stdio_openlist_del_lock);  extern volatile int _stdio_openlist_use_count; /* _stdio_openlist_del_lock */  extern int _stdio_openlist_del_count; /* _stdio_openlist_del_lock */  #endif 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/libgcc_s.h b/libc/sysdeps/linux/common/libgcc_s.h new file mode 100644 index 000000000..e74a1034c --- /dev/null +++ b/libc/sysdeps/linux/common/libgcc_s.h @@ -0,0 +1,2 @@ +/* Name of libgcc_s library provided by gcc.  */ +#define LIBGCC_S_SO "libgcc_s.so.1" 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..0be59c511 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/not-cancel.h b/libc/sysdeps/linux/common/not-cancel.h new file mode 100644 index 000000000..9418417b4 --- /dev/null +++ b/libc/sysdeps/linux/common/not-cancel.h @@ -0,0 +1,60 @@ +/* Uncancelable versions of cancelable interfaces.  Linux version. +   Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> + +/* Uncancelable open.  */ +#define open_not_cancel(name, flags, mode) \ +   INLINE_SYSCALL (open, 3, (const char *) (name), (flags), (mode)) +#define open_not_cancel_2(name, flags) \ +   INLINE_SYSCALL (open, 2, (const char *) (name), (flags)) + +/* Uncancelable close.  */ +#define close_not_cancel(fd) \ +  INLINE_SYSCALL (close, 1, fd) +#define close_not_cancel_no_status(fd) \ +  (void) ({ INTERNAL_SYSCALL_DECL (err);				      \ +	    INTERNAL_SYSCALL (close, err, 1, (fd)); }) + +/* Uncancelable read.  */ +#define read_not_cancel(fd, buf, n) \ +  INLINE_SYSCALL (read, 3, (fd), (buf), (n)) + +/* Uncancelable write.  */ +#define write_not_cancel(fd, buf, n) \ +  INLINE_SYSCALL (write, 3, (fd), (buf), (n)) + +/* Uncancelable writev.  */ +#define writev_not_cancel_no_status(fd, iov, n) \ +  (void) ({ INTERNAL_SYSCALL_DECL (err);				      \ +	    INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); }) + +/* Uncancelable fcntl.  */ +#define fcntl_not_cancel(fd, cmd, val) \ +  __fcntl_nocancel (fd, cmd, val) + +/* Uncancelable waitpid.  */ +#ifdef __NR_waitpid +# define waitpid_not_cancel(pid, stat_loc, options) \ +  INLINE_SYSCALL (waitpid, 3, pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ +  INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif 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..132ffa856 100644 --- a/libc/sysdeps/linux/common/pause.c +++ b/libc/sysdeps/linux/common/pause.c @@ -10,18 +10,31 @@  #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 52f6c76b4..3895e0da7 100644 --- a/libc/sysdeps/linux/common/poll.c +++ b/libc/sysdeps/linux/common/poll.c @@ -21,30 +21,33 @@  #include <sys/poll.h>  #include <bits/kernel-features.h> -#if defined __ASSUME_POLL_SYSCALL && defined __NR_poll +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif -_syscall3(int, poll, struct pollfd *, fds, -	unsigned long int, nfds, int, timeout) +libc_hidden_proto(poll) -#elif defined(__NR_ppoll) && defined __UCLIBC_LINUX_SPECIFIC__ +#if defined __ASSUME_POLL_SYSCALL && defined __NR_poll + +#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> @@ -54,6 +57,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 @@ -221,10 +227,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/sysdep.h b/libc/sysdeps/linux/common/sysdep.h index cd5b2f1e3..dae74d7c5 100644 --- a/libc/sysdeps/linux/common/sysdep.h +++ b/libc/sysdeps/linux/common/sysdep.h @@ -137,3 +137,23 @@  # endif  #endif /* __ASSEMBLER__ */ + +/* Values used for encoding parameter of cfi_personality and cfi_lsda.  */ +#define DW_EH_PE_absptr		0x00 +#define DW_EH_PE_omit		0xff +#define DW_EH_PE_uleb128	0x01 +#define DW_EH_PE_udata2		0x02 +#define DW_EH_PE_udata4		0x03 +#define DW_EH_PE_udata8		0x04 +#define DW_EH_PE_sleb128	0x09 +#define DW_EH_PE_sdata2		0x0a +#define DW_EH_PE_sdata4		0x0b +#define DW_EH_PE_sdata8		0x0c +#define DW_EH_PE_signed		0x08 +#define DW_EH_PE_pcrel		0x10 +#define DW_EH_PE_textrel	0x20 +#define DW_EH_PE_datarel	0x30 +#define DW_EH_PE_funcrel	0x40 +#define DW_EH_PE_aligned	0x50 +#define DW_EH_PE_indirect	0x80 + 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/sysdeps/linux/i386/Makefile.arch b/libc/sysdeps/linux/i386/Makefile.arch index 2bf2b7607..668cca742 100644 --- a/libc/sysdeps/linux/i386/Makefile.arch +++ b/libc/sysdeps/linux/i386/Makefile.arch @@ -5,8 +5,17 @@  # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.  # -CSRC := brk.c sigaction.c __syscall_error.c +CSRC := brk.c __syscall_error.c + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +endif  SSRC := \ -	__longjmp.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ +	__longjmp.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \  	sync_file_range.S syscall.S mmap.S mmap64.S posix_fadvise64.S + + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +SSRC += vfork.S clone.S +endif diff --git a/libc/sysdeps/linux/i386/bits/syscalls.h b/libc/sysdeps/linux/i386/bits/syscalls.h index 0427d91cd..9184bd6c3 100644 --- a/libc/sysdeps/linux/i386/bits/syscalls.h +++ b/libc/sysdeps/linux/i386/bits/syscalls.h @@ -23,7 +23,7 @@  		"int	$0x80\n\t"                              \  		RESTOREARGS_##nr                                \  		: "=a" (resultvar)                              \ -		: "i" (name) ASMFMT_##nr(args) : "memory", "cc" \ +		: "g" (name) ASMFMT_##nr(args) : "memory", "cc" \  	); \  	(int) resultvar; \  }) diff --git a/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h b/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h index deeec03d5..536e9c155 100644 --- a/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h @@ -37,7 +37,7 @@  #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__  /* define if target supports CFI pseudo ops */ -#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ +#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__  /* define if target supports IEEE signed zero floats */  #define __UCLIBC_HAVE_SIGNED_ZERO__ diff --git a/libc/sysdeps/linux/i386/clone.S b/libc/sysdeps/linux/i386/clone.S index 14fc25ca1..a7de3fe27 100644 --- a/libc/sysdeps/linux/i386/clone.S +++ b/libc/sysdeps/linux/i386/clone.S @@ -79,7 +79,10 @@ clone:  	movl	%eax,8(%ecx)  	/* Don't leak any information.  */  	movl	$0,4(%ecx) +#ifndef RESET_PID  	movl	$0,(%ecx) +#endif +  	/* Do the system call */  	pushl	%ebx @@ -90,6 +93,10 @@ clone:  	movl	FLAGS+12(%esp),%ebx  	movl	CTID+12(%esp),%edi  	movl	$__NR_clone,%eax +#ifdef RESET_PID +	/* Remember the flag value.  */ +	movl	%ebx, (%ecx) +#endif  	int	$0x80  	popl	%edi  	popl	%esi @@ -121,3 +128,4 @@ __error:  	jmp __syscall_error  .size clone,.-clone +weak_alias(clone, __clone) diff --git a/libc/sysdeps/linux/i386/sigaction.c b/libc/sysdeps/linux/i386/sigaction.c index 602f759a4..de0c75ded 100644 --- a/libc/sysdeps/linux/i386/sigaction.c +++ b/libc/sysdeps/linux/i386/sigaction.c @@ -41,12 +41,6 @@ int __libc_sigaction(int sig, const struct sigaction *act, struct sigaction *oac  {  	struct sigaction kact; -#ifdef SIGCANCEL -	if (sig == SIGCANCEL) { -		__set_errno(EINVAL); -		return -1; -	} -#endif  	if (act) {  		memcpy(&kact, act, sizeof(kact));  		kact.sa_flags |= SA_RESTORER; @@ -69,12 +63,6 @@ int __libc_sigaction(int sig, const struct sigaction *act, struct sigaction *oac  	int result;  	struct old_kernel_sigaction kact, koact; -#ifdef SIGCANCEL -	if (sig == SIGCANCEL) { -		__set_errno(EINVAL); -		return -1; -	} -#endif  	if (act) {  		kact.k_sa_handler = act->sa_handler;  		kact.sa_mask = act->sa_mask.__val[0]; diff --git a/libc/sysdeps/linux/i386/sysdep.h b/libc/sysdeps/linux/i386/sysdep.h new file mode 100644 index 000000000..ff67e8a08 --- /dev/null +++ b/libc/sysdeps/linux/i386/sysdep.h @@ -0,0 +1,460 @@ +/* Copyright (C) 1992,1993,1995-2000,2002-2006,2007 +	Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper, <drepper@gnu.org>, August 1995. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LINUX_I386_SYSDEP_H +#define _LINUX_I386_SYSDEP_H 1 + +#include <sys/syscall.h> +#include <common/sysdep.h> + +#ifdef	__ASSEMBLER__ + +/* Syntactic details of assembler.  */ + +/* ELF uses byte-counts for .align, most others use log2 of count of bytes.  */ +#define ALIGNARG(log2) 1<<log2 +/* For ELF we need the `.type' directive to make shared libs work right.  */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name; + +/* In ELF C symbols are asm symbols.  */ +#undef	NO_UNDERSCORES +#define NO_UNDERSCORES + +/* Define an entry point visible from C. + +   There is currently a bug in gdb which prevents us from specifying +   incomplete stabs information.  Fake some entries here which specify +   the current source file.  */ +#define	ENTRY(name)							      \ +  STABS_CURRENT_FILE1("")						      \ +  STABS_CURRENT_FILE(name)						      \ +  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				      \ +  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function)			      \ +  .align ALIGNARG(4);							      \ +  STABS_FUN(name)							      \ +  C_LABEL(name)								      \ +  cfi_startproc;							      \ +  CALL_MCOUNT + +#undef	END +#define END(name)							      \ +  cfi_endproc;								      \ +  ASM_SIZE_DIRECTIVE(name)						      \ +  STABS_FUN_END(name) + +#ifdef HAVE_CPP_ASM_DEBUGINFO +/* Disable that goop, because we just pass -g through to the assembler +   and it generates proper line number information directly.  */ +# define STABS_CURRENT_FILE1(name) +# define STABS_CURRENT_FILE(name) +# define STABS_FUN(name) +# define STABS_FUN_END(name) +#else +/* Remove the following two lines once the gdb bug is fixed.  */ +#define STABS_CURRENT_FILE(name)					      \ +  STABS_CURRENT_FILE1 (#name) +#define STABS_CURRENT_FILE1(name)					      \ +  1: .stabs name,100,0,0,1b; +/* Emit stabs definition lines.  We use F(0,1) and define t(0,1) as `int', +   the same way gcc does it.  */ +#define STABS_FUN(name) STABS_FUN2(name, name##:F(0,1)) +#define STABS_FUN2(name, namestr)					      \ +  .stabs "int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,0,0;		      \ +  .stabs #namestr,36,0,0,name; +#define STABS_FUN_END(name)						      \ +  1: .stabs "",36,0,0,1b-name; +#endif + +/* If compiled for profiling, call `mcount' at the start of each function.  */ +#ifdef	PROF +/* The mcount code relies on a normal frame pointer being on the stack +   to locate our caller, so push one just for its benefit.  */ +#define CALL_MCOUNT \ +  pushl %ebp; cfi_adjust_cfa_offset (4); movl %esp, %ebp; \ +  cfi_def_cfa_register (ebp); call JUMPTARGET(mcount); \ +  popl %ebp; cfi_def_cfa (esp, 4); +#else +#define CALL_MCOUNT		/* Do nothing.  */ +#endif + +#ifdef	NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore +   on this system, the asm identifier `syscall_error' intrudes on the +   C name space.  Make sure we use an innocuous name.  */ +#define	syscall_error	__syscall_error +#define mcount		_mcount +#endif + +#undef JUMPTARGET +#ifdef __PIC__ +#define JUMPTARGET(name)	name##@PLT +#define SYSCALL_PIC_SETUP \ +    pushl %ebx;								      \ +    cfi_adjust_cfa_offset (4);						      \ +    call 0f;								      \ +0:  popl %ebx;								      \ +    cfi_adjust_cfa_offset (-4);						      \ +    addl $_GLOBAL_OFFSET_TABLE+[.-0b], %ebx; + + +# define SETUP_PIC_REG(reg) \ +  .ifndef __x86.get_pc_thunk.reg;					      \ +  .section .gnu.linkonce.t.__x86.get_pc_thunk.reg,"ax",@progbits;	      \ +  .globl __x86.get_pc_thunk.reg;					      \ +  .hidden __x86.get_pc_thunk.reg;					      \ +  .type __x86.get_pc_thunk.reg,@function;				      \ +__x86.get_pc_thunk.reg:						      \ +  movl (%esp), %e##reg;							      \ +  ret;									      \ +  .size __x86.get_pc_thunk.reg, . - __x86.get_pc_thunk.reg;		      \ +  .previous;								      \ +  .endif;								      \ +  call __x86.get_pc_thunk.reg + +# define LOAD_PIC_REG(reg) \ +  SETUP_PIC_REG(reg); addl $_GLOBAL_OFFSET_TABLE_, %e##reg + +#else +#define JUMPTARGET(name)	name +#define SYSCALL_PIC_SETUP	/* Nothing.  */ +#endif + +/* Local label name for asm code. */ +#ifndef L +#ifdef HAVE_ELF +#define L(name)		.L##name +#else +#define L(name)		name +#endif +#endif + +#endif	/* __ASSEMBLER__ */ + +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +/* For Linux we can use the system call table in the header file +	/usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ +#undef SYS_ify +#define SYS_ify(syscall_name)	__NR_##syscall_name + +#if defined USE_DL_SYSINFO \ +    && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define I386_USE_SYSENTER	1 +#else +# undef I386_USE_SYSENTER +#endif + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, +   unlike most Unices, which use the condition codes' carry flag. + +   Since version 2.1 the return value of a system call might be +   negative even if the call succeeded.  E.g., the `lseek' system call +   might return a large offset.  Therefore we must not anymore test +   for < 0, but test for a real error by making sure the value in %eax +   is a real error number.  Linus said he will make sure the no syscall +   returns a value in -1 .. -4095 as a valid result so we can savely +   test with -4095.  */ + +/* We don't want the label for the error handle to be global when we define +   it here.  */ +#ifdef __PIC__ +# define SYSCALL_ERROR_LABEL 0f +#else +# define SYSCALL_ERROR_LABEL syscall_error +#endif + +#undef	PSEUDO +#define	PSEUDO(name, syscall_name, args)				      \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args);					      \ +    cmpl $-4095, %eax;							      \ +    jae SYSCALL_ERROR_LABEL;						      \ +  L(pseudo_end): + +#undef	PSEUDO_END +#define	PSEUDO_END(name)						      \ +  SYSCALL_ERROR_HANDLER							      \ +  END (name) + +#undef	PSEUDO_NOERRNO +#define	PSEUDO_NOERRNO(name, syscall_name, args)			      \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args) + +#undef	PSEUDO_END_NOERRNO +#define	PSEUDO_END_NOERRNO(name)					      \ +  END (name) + +#define ret_NOERRNO ret + +/* The function has to return the error code.  */ +#undef	PSEUDO_ERRVAL +#define	PSEUDO_ERRVAL(name, syscall_name, args) \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args);					      \ +    negl %eax + +#undef	PSEUDO_END_ERRVAL +#define	PSEUDO_END_ERRVAL(name) \ +  END (name) + +#define ret_ERRVAL ret + +#ifndef __PIC__ +# define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */ +#else + +# ifdef RTLD_PRIVATE_ERRNO +#  define SYSCALL_ERROR_HANDLER						      \ +0:SETUP_PIC_REG(cx);							      \ +  addl $_GLOBAL_OFFSET_TABLE_, %ecx;					      \ +  xorl %edx, %edx;							      \ +  subl %eax, %edx;							      \ +  movl %edx, rtld_errno@GOTOFF(%ecx);					      \ +  orl $-1, %eax;							      \ +  jmp L(pseudo_end); + +# elif defined _LIBC_REENTRANT + +#  if USE___THREAD +#   ifndef NOT_IN_libc +#    define SYSCALL_ERROR_ERRNO __libc_errno +#   else +#    define SYSCALL_ERROR_ERRNO errno +#   endif +#   define SYSCALL_ERROR_HANDLER					      \ +0:SETUP_PIC_REG (cx);							      \ +  addl $_GLOBAL_OFFSET_TABLE_, %ecx;					      \ +  movl SYSCALL_ERROR_ERRNO@GOTNTPOFF(%ecx), %ecx;			      \ +  xorl %edx, %edx;							      \ +  subl %eax, %edx;							      \ +  SYSCALL_ERROR_HANDLER_TLS_STORE (%edx, %ecx);				      \ +  orl $-1, %eax;							      \ +  jmp L(pseudo_end); +#   ifndef NO_TLS_DIRECT_SEG_REFS +#    define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff)		      \ +  movl src, %gs:(destoff) +#   else +#    define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff)		      \ +  addl %gs:0, destoff;							      \ +  movl src, (destoff) +#   endif +#  else +#   define SYSCALL_ERROR_HANDLER					      \ +0:pushl %ebx;								      \ +  cfi_adjust_cfa_offset (4);						      \ +  cfi_rel_offset (ebx, 0);						      \ +  SETUP_PIC_REG (bx);							      \ +  addl $_GLOBAL_OFFSET_TABLE_, %ebx;					      \ +  xorl %edx, %edx;							      \ +  subl %eax, %edx;							      \ +  pushl %edx;								      \ +  cfi_adjust_cfa_offset (4);						      \ +  call __errno_location@PLT;					              \ +  popl %ecx;								      \ +  cfi_adjust_cfa_offset (-4);						      \ +  popl %ebx;								      \ +  cfi_adjust_cfa_offset (-4);						      \ +  cfi_restore (ebx);							      \ +  movl %ecx, (%eax);							      \ +  orl $-1, %eax;							      \ +  jmp L(pseudo_end); +/* A quick note: it is assumed that the call to `__errno_location' does +   not modify the stack!  */ +#  endif +# else +/* Store (- %eax) into errno through the GOT.  */ +#  define SYSCALL_ERROR_HANDLER						      \ +0:SETUP_PIC_REG(cx);							      \ +  addl $_GLOBAL_OFFSET_TABLE_, %ecx;					      \ +  xorl %edx, %edx;							      \ +  subl %eax, %edx;							      \ +  movl errno@GOT(%ecx), %ecx;						      \ +  movl %edx, (%ecx);							      \ +  orl $-1, %eax;							      \ +  jmp L(pseudo_end); +# endif	/* _LIBC_REENTRANT */ +#endif	/* __PIC__ */ + + +/* The original calling convention for system calls on Linux/i386 is +   to use int $0x80.  */ +#ifdef I386_USE_SYSENTER +# ifdef SHARED +#  define ENTER_KERNEL call *%gs:SYSINFO_OFFSET +# else +#  define ENTER_KERNEL call *_dl_sysinfo +# endif +#else +# define ENTER_KERNEL int $0x80 +#endif + +/* Linux takes system call arguments in registers: + +	syscall number	%eax	     call-clobbered +	arg 1		%ebx	     call-saved +	arg 2		%ecx	     call-clobbered +	arg 3		%edx	     call-clobbered +	arg 4		%esi	     call-saved +	arg 5		%edi	     call-saved +	arg 6		%ebp	     call-saved + +   The stack layout upon entering the function is: + +	24(%esp)	Arg# 6 +	20(%esp)	Arg# 5 +	16(%esp)	Arg# 4 +	12(%esp)	Arg# 3 +	 8(%esp)	Arg# 2 +	 4(%esp)	Arg# 1 +	  (%esp)	Return address + +   (Of course a function with say 3 arguments does not have entries for +   arguments 4, 5, and 6.) + +   The following code tries hard to be optimal.  A general assumption +   (which is true according to the data books I have) is that + +	2 * xchg	is more expensive than	pushl + movl + popl + +   Beside this a neat trick is used.  The calling conventions for Linux +   tell that among the registers used for parameters %ecx and %edx need +   not be saved.  Beside this we may clobber this registers even when +   they are not used for parameter passing. + +   As a result one can see below that we save the content of the %ebx +   register in the %edx register when we have less than 3 arguments +   (2 * movl is less expensive than pushl + popl). + +   Second unlike for the other registers we don't save the content of +   %ecx and %edx when we have more than 1 and 2 registers resp. + +   The code below might look a bit long but we have to take care for +   the pipelined processors (i586).  Here the `pushl' and `popl' +   instructions are marked as NP (not pairable) but the exception is +   two consecutive of these instruction.  This gives no penalty on +   other processors though.  */ + +#undef	DO_CALL +#define DO_CALL(syscall_name, args)			      		      \ +    PUSHARGS_##args							      \ +    DOARGS_##args							      \ +    movl $SYS_ify (syscall_name), %eax;					      \ +    ENTER_KERNEL							      \ +    POPARGS_##args + +#define PUSHARGS_0	/* No arguments to push.  */ +#define	DOARGS_0	/* No arguments to frob.  */ +#define	POPARGS_0	/* No arguments to pop.  */ +#define	_PUSHARGS_0	/* No arguments to push.  */ +#define _DOARGS_0(n)	/* No arguments to frob.  */ +#define	_POPARGS_0	/* No arguments to pop.  */ + +#define PUSHARGS_1	movl %ebx, %edx; L(SAVEBX1): PUSHARGS_0 +#define	DOARGS_1	_DOARGS_1 (4) +#define	POPARGS_1	POPARGS_0; movl %edx, %ebx; L(RESTBX1): +#define	_PUSHARGS_1	pushl %ebx; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (ebx, 0); L(PUSHBX1): _PUSHARGS_0 +#define _DOARGS_1(n)	movl n(%esp), %ebx; _DOARGS_0(n-4) +#define	_POPARGS_1	_POPARGS_0; popl %ebx; cfi_adjust_cfa_offset (-4); \ +			cfi_restore (ebx); L(POPBX1): + +#define PUSHARGS_2	PUSHARGS_1 +#define	DOARGS_2	_DOARGS_2 (8) +#define	POPARGS_2	POPARGS_1 +#define _PUSHARGS_2	_PUSHARGS_1 +#define	_DOARGS_2(n)	movl n(%esp), %ecx; _DOARGS_1 (n-4) +#define	_POPARGS_2	_POPARGS_1 + +#define PUSHARGS_3	_PUSHARGS_2 +#define DOARGS_3	_DOARGS_3 (16) +#define POPARGS_3	_POPARGS_3 +#define _PUSHARGS_3	_PUSHARGS_2 +#define _DOARGS_3(n)	movl n(%esp), %edx; _DOARGS_2 (n-4) +#define _POPARGS_3	_POPARGS_2 + +#define PUSHARGS_4	_PUSHARGS_4 +#define DOARGS_4	_DOARGS_4 (24) +#define POPARGS_4	_POPARGS_4 +#define _PUSHARGS_4	pushl %esi; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (esi, 0); L(PUSHSI1): _PUSHARGS_3 +#define _DOARGS_4(n)	movl n(%esp), %esi; _DOARGS_3 (n-4) +#define _POPARGS_4	_POPARGS_3; popl %esi; cfi_adjust_cfa_offset (-4); \ +			cfi_restore (esi); L(POPSI1): + +#define PUSHARGS_5	_PUSHARGS_5 +#define DOARGS_5	_DOARGS_5 (32) +#define POPARGS_5	_POPARGS_5 +#define _PUSHARGS_5	pushl %edi; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (edi, 0); L(PUSHDI1): _PUSHARGS_4 +#define _DOARGS_5(n)	movl n(%esp), %edi; _DOARGS_4 (n-4) +#define _POPARGS_5	_POPARGS_4; popl %edi; cfi_adjust_cfa_offset (-4); \ +			cfi_restore (edi); L(POPDI1): + +#define PUSHARGS_6	_PUSHARGS_6 +#define DOARGS_6	_DOARGS_6 (40) +#define POPARGS_6	_POPARGS_6 +#define _PUSHARGS_6	pushl %ebp; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (ebp, 0); L(PUSHBP1): _PUSHARGS_5 +#define _DOARGS_6(n)	movl n(%esp), %ebp; _DOARGS_5 (n-4) +#define _POPARGS_6	_POPARGS_5; popl %ebp; cfi_adjust_cfa_offset (-4); \ +			cfi_restore (ebp); L(POPBP1): + +#endif	/* __ASSEMBLER__ */ + + +/* Pointer mangling support.  */ +#if defined NOT_IN_libc && defined IS_IN_rtld +/* We cannot use the thread descriptor because in ld.so we use setjmp +   earlier than the descriptor is initialized.  Using a global variable +   is too complicated here since we have no PC-relative addressing mode.  */ +#else +# ifdef __ASSEMBLER__ +#  define PTR_MANGLE(reg)	xorl %gs:POINTER_GUARD, reg;		      \ +				roll $9, reg +#  define PTR_DEMANGLE(reg)	rorl $9, reg;				      \ +				xorl %gs:POINTER_GUARD, reg +# else +#  define PTR_MANGLE(var)	__asm__ ("xorl %%gs:%c2, %0\n"		      \ +				     "roll $9, %0"			      \ +				     : "=r" (var)			      \ +				     : "0" (var),			      \ +				       "i" (offsetof (tcbhead_t,	      \ +						      pointer_guard))) +#  define PTR_DEMANGLE(var)	__asm__ ("rorl $9, %0\n"			      \ +				     "xorl %%gs:%c2, %0"		      \ +				     : "=r" (var)			      \ +				     : "0" (var),			      \ +				       "i" (offsetof (tcbhead_t,	      \ +						      pointer_guard))) +# endif +#endif + +#endif /* linux/i386/sysdep.h */ diff --git a/libc/sysdeps/linux/i386/vfork.S b/libc/sysdeps/linux/i386/vfork.S index 8005ff1d2..c9db2f48c 100644 --- a/libc/sysdeps/linux/i386/vfork.S +++ b/libc/sysdeps/linux/i386/vfork.S @@ -18,9 +18,19 @@  __vfork:  	popl %ecx + +#ifdef SAVE_PID +	SAVE_PID +#endif +  	movl $__NR_vfork,%eax  	int $0x80  	pushl %ecx + +#ifdef RESTORE_PID +	RESTORE_PID +#endif +  	cmpl $-4095,%eax  	jae __syscall_error  	ret diff --git a/libc/sysdeps/linux/mips/Makefile.arch b/libc/sysdeps/linux/mips/Makefile.arch index 2570a6988..73e64991c 100644 --- a/libc/sysdeps/linux/mips/Makefile.arch +++ b/libc/sysdeps/linux/mips/Makefile.arch @@ -7,11 +7,15 @@  CSRC := \  	__longjmp.c  brk.c setjmp_aux.c mmap.c __syscall_error.c \ -	cacheflush.c pread_write.c sysmips.c _test_and_set.c sigaction.c \ +	cacheflush.c pread_write.c sysmips.c _test_and_set.c \  	readahead.c  ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y) -        CSRC += posix_fadvise.c posix_fadvise64.c +CSRC += posix_fadvise.c posix_fadvise64.c +endif + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c  endif  SSRC := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S syscall.S pipe.S diff --git a/libc/sysdeps/linux/mips/clone.S b/libc/sysdeps/linux/mips/clone.S index 15fa29558..a53d5c492 100644 --- a/libc/sysdeps/linux/mips/clone.S +++ b/libc/sysdeps/linux/mips/clone.S @@ -132,3 +132,4 @@ L(__thread_start):          jal             _exit  #endif  	.end  __thread_start +weak_alias(clone, __clone) diff --git a/libc/sysdeps/linux/mips/sys/asm.h b/libc/sysdeps/linux/mips/sys/asm.h index 79d143975..d424ed3b1 100644 --- a/libc/sysdeps/linux/mips/sys/asm.h +++ b/libc/sysdeps/linux/mips/sys/asm.h @@ -472,4 +472,20 @@ symbol		=	value  # define MTC0	dmtc0  #endif +/* The MIPS archtectures do not have a uniform memory model.  Particular +   platforms may provide additional guarantees - for instance, the R4000 +   LL and SC instructions implicitly perform a SYNC, and the 4K promises +   strong ordering. + +   However, in the absence of those guarantees, we must assume weak ordering +   and SYNC explicitly where necessary. + +   Some obsolete MIPS processors may not support the SYNC instruction.  This +   applies to "true" MIPS I processors; most of the processors which compile +   using MIPS I implement parts of MIPS II.  */ + +#ifndef MIPS_SYNC +# define MIPS_SYNC      sync +#endif +  #endif /* sys/asm.h */ diff --git a/libc/sysdeps/linux/mips/sys/regdef.h b/libc/sysdeps/linux/mips/sys/regdef.h index 9d2c4c1c4..2d94130af 100644 --- a/libc/sysdeps/linux/mips/sys/regdef.h +++ b/libc/sysdeps/linux/mips/sys/regdef.h @@ -20,6 +20,8 @@  #ifndef _SYS_REGDEF_H  #define _SYS_REGDEF_H +#include <sgidefs.h> +  /*   * Symbolic register names for 32 bit ABI   */ diff --git a/libc/sysdeps/linux/mips/syscall_error.S b/libc/sysdeps/linux/mips/syscall_error.S new file mode 100644 index 000000000..1e348ad4a --- /dev/null +++ b/libc/sysdeps/linux/mips/syscall_error.S @@ -0,0 +1,82 @@ +/* Copyright (C) 1992, 1993, 1994, 1997, 1998, 1999, 2000, 2002, 2003 +   Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Brendan Kehoe (brendan@zen.org). + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sys/asm.h> +#include <sysdep.h> +#include <bits/errno.h> + +#ifdef __UCLIBC_HAS_THREADS__ + +LOCALSZ= 3 +FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK +RAOFF= FRAMESZ-(1*SZREG) +GPOFF= FRAMESZ-(2*SZREG) +V0OFF= FRAMESZ-(3*SZREG) + +ENTRY(__syscall_error) +#ifdef __PIC__ +	.set noat +	SETUP_GPX (AT) +	.set at +#endif +	PTR_SUBU sp, FRAMESZ +	.set noat +	SETUP_GPX64(GPOFF,AT) +	.set at +#ifdef __PIC__ +	SAVE_GP(GPOFF) +#endif +	REG_S	v0, V0OFF(sp) +	REG_S	ra, RAOFF(sp) + +	/* Find our per-thread errno address  */ +	jal	__errno_location + +	/* Store the error value.  */ +	REG_L	t0, V0OFF(sp) +	sw	t0, 0(v0) + +	/* And just kick back a -1.  */ +	REG_L	ra, RAOFF(sp) +	RESTORE_GP64 +	PTR_ADDU sp, FRAMESZ +	li	v0, -1 +	j	ra +	END(__syscall_error) + +#else /* __UCLIBC_HAS_THREADS__ */ + + +ENTRY(__syscall_error) +#ifdef __PIC__ +	SETUP_GPX (AT) +#endif +	SETUP_GPX64 (t9, AT) + +	/* Store it in errno... */ +	sw v0, errno + +	/* And just kick back a -1.  */ +	li v0, -1 + +	RESTORE_GP64 +	j ra +	END(__syscall_error) +#endif  /* __UCLIBC_HAS_THREADS__ */ diff --git a/libc/sysdeps/linux/mips/sysdep.h b/libc/sysdeps/linux/mips/sysdep.h new file mode 100644 index 000000000..56d159073 --- /dev/null +++ b/libc/sysdeps/linux/mips/sysdep.h @@ -0,0 +1,391 @@ +/* Copyright (C) 1992, 1995, 1997, 1999, 2000, 2002, 2003, 2004 +   Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Brendan Kehoe (brendan@zen.org). + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LINUX_MIPS_SYSDEP_H +#define _LINUX_MIPS_SYSDEP_H 1 + +#include <sgidefs.h> +#include <common/sysdep.h> + +/* For Linux we can use the system call table in the header file +   /usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ + +#undef SYS_ify +#ifdef __STDC__ +# define SYS_ify(syscall_name)	__NR_##syscall_name +#else +# define SYS_ify(syscall_name)	__NR_/**/syscall_name +#endif + +#ifdef __ASSEMBLER__ + +#include <regdef.h> + +#define ENTRY(name) 					\ +  .globl name;						\ +  .align 2;						\ +  .ent name,0;						\ +  name##: + +#undef END +#define	END(function)					\ +		.end	function;			\ +		.size	function,.-function + +#define ret	j ra ; nop + +#undef PSEUDO_END +#define PSEUDO_END(sym) .end sym; .size sym,.-sym + +#define PSEUDO_NOERRNO(name, syscall_name, args)	\ +  .align 2;						\ +  ENTRY(name)						\ +  .set noreorder;					\ +  li v0, SYS_ify(syscall_name);				\ +  syscall + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(sym) .end sym; .size sym,.-sym + +#define ret_NOERRNO ret + +#define PSEUDO_ERRVAL(name, syscall_name, args)		\ +  .align 2;						\ +  ENTRY(name)						\ +  .set noreorder;					\ +  li v0, SYS_ify(syscall_name);				\ +  syscall + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(sym) .end sym; .size sym,.-sym + +#define ret_ERRVAL ret + +#define r0	v0 +#define r1	v1 +/* The mips move insn is d,s.  */ +#define MOVE(x,y)	move y , x + +#if _MIPS_SIM == _ABIO32 +# define L(label) $L ## label +#else +# define L(label) .L ## label +#endif + +/* Note that while it's better structurally, going back to call __syscall_error +   can make things confusing if you're debugging---it looks like it's jumping +   backwards into the previous fn.  */ + +#ifdef __PIC__ +#define PSEUDO(name, syscall_name, args) 		\ +  .align 2;						\ +  99: la t9,__syscall_error;				\ +  jr t9;						\ +  ENTRY(name)						\ +  .set noreorder;					\ +  .cpload t9;						\ +  li v0, SYS_ify(syscall_name);				\ +  syscall;						\ +  .set reorder;						\ +  bne a3, zero, 99b;					\ +L(syse1): +#else +#define PSEUDO(name, syscall_name, args) 		\ +  .set noreorder;					\ +  .align 2;						\ +  99: j __syscall_error;				\ +  nop;							\ +  ENTRY(name)						\ +  .set noreorder;					\ +  li v0, SYS_ify(syscall_name);				\ +  syscall;						\ +  .set reorder;						\ +  bne a3, zero, 99b;					\ +L(syse1): +#endif + +/* We don't want the label for the error handler to be visible in the symbol +   table when we define it here.  */ +#ifdef __PIC__ +# define SYSCALL_ERROR_LABEL 99b +#endif + +#else   /* ! __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system +   call.  */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...)				\ +  ({ INTERNAL_SYSCALL_DECL(err);					\ +     long result_var = INTERNAL_SYSCALL (name, err, nr, args);		\ +     if ( INTERNAL_SYSCALL_ERROR_P (result_var, err) )			\ +       {								\ +	 __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err));	\ +	 result_var = -1L;						\ +       }								\ +     result_var; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) long err + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err)   ((long) (err)) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err)     (val) + +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...) \ +	internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t",	\ +			      "i" (SYS_ify (name)), err, args) + +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ +	internal_syscall##nr (= number, , "r" (__v0), err, args) +#undef internal_syscall0 +#define internal_syscall0(ncs_init, cs_init, input, err, dummy...)	\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set reorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input								\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall1 +#define internal_syscall1(ncs_init, cs_init, input, err, arg1)		\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set reorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input, "r" (__a0)						\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall2 +#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2)	\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set\treorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1)					\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall3 +#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set\treorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall4 +#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +/* We need to use a frame pointer for the functions in which we +   adjust $sp around the syscall, or debug information and unwind +   information will be $sp relative and thus wrong during the syscall.  As +   of GCC 3.4.3, this is sufficient.  */ +#define FORCE_FRAME_POINTER alloca (4) + +#undef internal_syscall5 +#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5)\ +({									\ +	long _sys_result;						\ +									\ +	FORCE_FRAME_POINTER;						\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	"subu\t$29, 32\n\t"						\ +	"sw\t%6, 16($29)\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	"addiu\t$29, 32\n\t"						\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\ +	  "r" ((long)arg5)						\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall6 +#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6)\ +({									\ +	long _sys_result;						\ +									\ +	FORCE_FRAME_POINTER;						\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	"subu\t$29, 32\n\t"						\ +	"sw\t%6, 16($29)\n\t"						\ +	"sw\t%7, 20($29)\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	"addiu\t$29, 32\n\t"						\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\ +	  "r" ((long)arg5), "r" ((long)arg6)				\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall7 +#define internal_syscall7(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ +({									\ +	long _sys_result;						\ +									\ +	FORCE_FRAME_POINTER;						\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	"subu\t$29, 32\n\t"						\ +	"sw\t%6, 16($29)\n\t"						\ +	"sw\t%7, 20($29)\n\t"						\ +	"sw\t%8, 24($29)\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	"addiu\t$29, 32\n\t"						\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\ +	  "r" ((long)arg5), "r" ((long)arg6), "r" ((long)arg7)		\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef __SYSCALL_CLOBBERS +#define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \ +	"$14", "$15", "$24", "$25", "memory" + +/* Pointer mangling is not yet supported for MIPS.  */ +#define PTR_MANGLE(var) (void) (var) +#define PTR_DEMANGLE(var) (void) (var) + +#endif  /* __ASSEMBLER__ */ +#endif /* _LINUX_MIPS_SYSDEP_H */ diff --git a/libc/sysdeps/linux/mips/vfork.S b/libc/sysdeps/linux/mips/vfork.S new file mode 100644 index 000000000..8400df052 --- /dev/null +++ b/libc/sysdeps/linux/mips/vfork.S @@ -0,0 +1,97 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* vfork() is just a special case of clone().  */ + +#include <sys/asm.h> +#include <sysdep.h> + +#ifndef SAVE_PID +#define SAVE_PID +#endif + +#ifndef RESTORE_PID +#define RESTORE_PID +#endif + + +/* int vfork() */ + +	.text +LOCALSZ= 1 +FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK +GPOFF= FRAMESZ-(1*SZREG) +NESTED(__vfork,FRAMESZ,sp) +#ifdef __PIC__ +	SETUP_GP +#endif +	PTR_SUBU sp, FRAMESZ +	SETUP_GP64 (a5, __vfork) +#ifdef __PIC__ +	SAVE_GP (GPOFF) +#endif +#ifdef PROF +# if (_MIPS_SIM != _ABIO32) +	PTR_S		a5, GPOFF(sp) +# endif +	.set		noat +	move		$1, ra +# if (_MIPS_SIM == _ABIO32) +	subu		sp,sp,8 +# endif +	jal		_mcount +	.set		at +# if (_MIPS_SIM != _ABIO32) +	PTR_L		a5, GPOFF(sp) +# endif +#endif + +	PTR_ADDU	sp, FRAMESZ + +	SAVE_PID + +	li		a0, 0x4112	/* CLONE_VM | CLONE_VFORK | SIGCHLD */ +	move		a1, sp + +	/* Do the system call */ +	li		v0,__NR_clone +	syscall + +	RESTORE_PID + +	bnez		a3,L(error) + +	/* Successful return from the parent or child.  */ +	RESTORE_GP64 +	j		ra +	nop + +	/* Something bad happened -- no child created.  */ +L(error): +#ifdef __PIC__ +	PTR_LA		t9, __syscall_error +	RESTORE_GP64 +	jr		t9 +#else +	RESTORE_GP64 +	j		__syscall_error +#endif +	END(__vfork) + +.weak vfork; +	vfork = __vfork diff --git a/libc/sysdeps/linux/sh/Makefile.arch b/libc/sysdeps/linux/sh/Makefile.arch index 31beda111..3e32e1095 100644 --- a/libc/sysdeps/linux/sh/Makefile.arch +++ b/libc/sysdeps/linux/sh/Makefile.arch @@ -7,6 +7,6 @@  #  CSRC := \ -	mmap.c pipe.c __init_brk.c brk.c sbrk.c pread_write.c cacheflush.c +	mmap.c pipe.c __init_brk.c brk.c sbrk.c pread_write.c longjmp.c cacheflush.c -SSRC := setjmp.S __longjmp.S vfork.S clone.S ___fpscr_values.S +SSRC := setjmp.S __longjmp.S ___fpscr_values.S diff --git a/libc/sysdeps/linux/sh/bits/atomic.h b/libc/sysdeps/linux/sh/bits/atomic.h index 6bb7255c5..a099b43a8 100644 --- a/libc/sysdeps/linux/sh/bits/atomic.h +++ b/libc/sysdeps/linux/sh/bits/atomic.h @@ -54,6 +54,10 @@ typedef uintmax_t uatomic_max_t;      Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in      Japanese). +    Niibe Yutaka, "gUSA: User Space Atomicity with Little Kernel +    Modification", LinuxTag 2003, Rome. +    http://www.semmel.ch/Linuxtag-DVD/talks/170/paper.html (in English). +      B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for      Uniprocessors",  Proceedings of the Fifth Architectural Support for      Programming Languages and Operating Systems (ASPLOS), pp. 223-233, @@ -65,56 +69,44 @@ typedef uintmax_t uatomic_max_t;        r1:     saved stack pointer  */ -#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ -  ({ __typeof (*(mem)) __result; \ -     __asm__ __volatile__ ("\ +/* Avoid having lots of different versions of compare and exchange, +   by having this one complicated version. Parameters: +      bwl:     b, w or l for 8, 16 and 32 bit versions. +      version: val or bool, depending on whether the result is the +               previous value or a bool indicating whether the transfer +               did happen (note this needs inverting before being +               returned in atomic_compare_and_exchange_bool). +*/ + +#define __arch_compare_and_exchange_n(mem, newval, oldval, bwl, version) \ +  ({ signed long __result; \ +     __asm __volatile ("\  	.align 2\n\  	mova 1f,r0\n\  	nop\n\  	mov r15,r1\n\  	mov #-8,r15\n\ -     0: mov.b @%1,%0\n\ +     0: mov." #bwl " @%1,%0\n\  	cmp/eq %0,%3\n\  	bf 1f\n\ -	mov.b %2,@%1\n\ -     1: mov r1,r15"\ -	: "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \ -	: "r0", "r1", "t", "memory"); \ +	mov." #bwl " %2,@%1\n\ +     1: mov r1,r15\n\ +     .ifeqs \"bool\",\"" #version "\"\n\ +        movt %0\n\ +     .endif\n"					\ +	: "=&r" (__result)			\ +	: "r" (mem), "r" (newval), "r" (oldval)	\ +	: "r0", "r1", "t", "memory");		\       __result; }) +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ +  __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, val) +  #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ -  ({ __typeof (*(mem)) __result; \ -     __asm__ __volatile__ ("\ -	.align 2\n\ -	mova 1f,r0\n\ -	nop\n\ -	mov r15,r1\n\ -	mov #-8,r15\n\ -     0: mov.w @%1,%0\n\ -	cmp/eq %0,%3\n\ -	bf 1f\n\ -	mov.w %2,@%1\n\ -     1: mov r1,r15"\ -	: "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \ -	: "r0", "r1", "t", "memory"); \ -     __result; }) +  __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, val)  #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ -  ({ __typeof (*(mem)) __result; \ -     __asm__ __volatile__ ("\ -	.align 2\n\ -	mova 1f,r0\n\ -	nop\n\ -	mov r15,r1\n\ -	mov #-8,r15\n\ -     0: mov.l @%1,%0\n\ -	cmp/eq %0,%3\n\ -	bf 1f\n\ -	mov.l %2,@%1\n\ -     1: mov r1,r15"\ -	: "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \ -	: "r0", "r1", "t", "memory"); \ -     __result; }) +  __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, val)  /* XXX We do not really need 64-bit compare-and-exchange.  At least     not in the moment.  Using it would mean causing portability @@ -122,298 +114,180 @@ typedef uintmax_t uatomic_max_t;     such an operation.  So don't define any code for now.  */  # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ -  (abort (), (__typeof (*mem)) 0) +  (abort (), 0) + +/* For "bool" routines, return if the exchange did NOT occur */ + +#define __arch_compare_and_exchange_bool_8_acq(mem, newval, oldval) \ +  (! __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, bool)) + +#define __arch_compare_and_exchange_bool_16_acq(mem, newval, oldval) \ +  (! __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, bool)) + +#define __arch_compare_and_exchange_bool_32_acq(mem, newval, oldval) \ +  (! __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, bool)) + +# define __arch_compare_and_exchange_bool_64_acq(mem, newval, oldval) \ +  (abort (), 0) + +/* Similar to the above, have one template which can be used in a +   number of places. This version returns both the old and the new +   values of the location. Parameters: +      bwl:     b, w or l for 8, 16 and 32 bit versions. +      oper:    The instruction to perform on the old value. +   Note old is not sign extended, so should be an unsigned long. +*/ + +#define __arch_operate_old_new_n(mem, value, old, new, bwl, oper)	\ +  (void) ({ __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	mov r15,r1\n\ +	nop\n\ +	mov #-8,r15\n\ +     0: mov." #bwl " @%2,%0\n\ +	mov %0,%1\n\ +	" #oper " %3,%1\n\ +	mov." #bwl " %1,@%2\n\ +     1: mov r1,r15"			\ +	: "=&r" (old), "=&r"(new)	\ +	: "r" (mem), "r" (value)	\ +	: "r0", "r1", "memory");	\ +    }) + +#define __arch_exchange_and_add_8_int(mem, value)			\ +  ({ int32_t __value = (value), __new, __old;				\ +    __arch_operate_old_new_n((mem), __value, __old, __new, b, add);	\ +    __old; }) + +#define __arch_exchange_and_add_16_int(mem, value)			\ +  ({ int32_t __value = (value), __new, __old;				\ +    __arch_operate_old_new_n((mem), __value, __old, __new, w, add);	\ +    __old; }) + +#define __arch_exchange_and_add_32_int(mem, value)			\ +  ({ int32_t __value = (value), __new, __old;				\ +    __arch_operate_old_new_n((mem), __value, __old, __new, l, add);	\ +    __old; }) + +#define __arch_exchange_and_add_64_int(mem, value)			\ +  (abort (), 0)  #define atomic_exchange_and_add(mem, value) \ -  ({ __typeof (*(mem)) __result, __tmp, __value = (value); \ -     if (sizeof (*(mem)) == 1) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.b @%2,%0\n\ -	  add %0,%1\n\ -	  mov.b %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "memory"); \ -     else if (sizeof (*(mem)) == 2) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.w @%2,%0\n\ -	  add %0,%1\n\ -	  mov.w %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "memory"); \ -     else if (sizeof (*(mem)) == 4) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.l @%2,%0\n\ -	  add %0,%1\n\ -	  mov.l %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "memory"); \ -     else \ -       { \ -	 __typeof (mem) memp = (mem); \ -	 do \ -	   __result = *memp; \ -	 while (__arch_compare_and_exchange_val_64_acq \ -		 (memp,	__result + __value, __result) == __result); \ -	 (void) __value; \ -       } \ -     __result; }) +  __atomic_val_bysize (__arch_exchange_and_add, int, mem, value) + + +/* Again, another template. We get a slight optimisation when the old value +   does not need to be returned. Parameters: +      bwl:     b, w or l for 8, 16 and 32 bit versions. +      oper:    The instruction to perform on the old value. +*/ + +#define __arch_operate_new_n(mem, value, bwl, oper)	 \ +  ({ int32_t __value = (value), __new; \ +     __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	mov r15,r1\n\ +	mov #-6,r15\n\ +     0: mov." #bwl " @%1,%0\n\ +	" #oper " %2,%0\n\ +	mov." #bwl " %0,@%1\n\ +     1: mov r1,r15"			\ +	: "=&r" (__new)			\ +	: "r" (mem), "r" (__value)	\ +	: "r0", "r1", "memory");	\ +     __new;				\ +  }) + +#define __arch_add_8_int(mem, value)		\ +  __arch_operate_new_n(mem, value, b, add) + +#define __arch_add_16_int(mem, value)		\ +  __arch_operate_new_n(mem, value, w, add) + +#define __arch_add_32_int(mem, value)		\ +  __arch_operate_new_n(mem, value, l, add) + +#define __arch_add_64_int(mem, value)		\ +  (abort (), 0)  #define atomic_add(mem, value) \ -  (void) ({ __typeof (*(mem)) __tmp, __value = (value); \ -	    if (sizeof (*(mem)) == 1) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.b @%1,r2\n\ -		add r2,%0\n\ -		mov.b %0,@%1\n\ -	     1: mov r1,r15"\ -		: "=&r" (__tmp) : "r" (mem), "0" (__value) \ -		: "r0", "r1", "r2", "memory"); \ -	    else if (sizeof (*(mem)) == 2) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.w @%1,r2\n\ -		add r2,%0\n\ -		mov.w %0,@%1\n\ -	     1: mov r1,r15"\ -		: "=&r" (__tmp) : "r" (mem), "0" (__value) \ -		: "r0", "r1", "r2", "memory"); \ -	    else if (sizeof (*(mem)) == 4) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.l @%1,r2\n\ -		add r2,%0\n\ -		mov.l %0,@%1\n\ -	     1: mov r1,r15"\ -		: "=&r" (__tmp) : "r" (mem), "0" (__value) \ -		: "r0", "r1", "r2", "memory"); \ -	    else \ -	      { \ -		__typeof (*(mem)) oldval; \ -		__typeof (mem) memp = (mem); \ -		do \ -		  oldval = *memp; \ -		while (__arch_compare_and_exchange_val_64_acq \ -			(memp, oldval + __value, oldval) == oldval); \ -		(void) __value; \ -	      } \ -	    }) +  ((void) __atomic_val_bysize (__arch_add, int, mem, value)) + + +#define __arch_add_negative_8_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, b, add) < 0) + +#define __arch_add_negative_16_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, w, add) < 0) + +#define __arch_add_negative_32_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, l, add) < 0) + +#define __arch_add_negative_64_int(mem, value)		\ +  (abort (), 0)  #define atomic_add_negative(mem, value) \ -  ({ unsigned char __result; \ -     __typeof (*(mem)) __tmp, __value = (value); \ -     if (sizeof (*(mem)) == 1) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.b @%2,r2\n\ -	  add r2,%1\n\ -	  mov.b %1,@%2\n\ -       1: mov r1,r15\n\ -	  shal %1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else if (sizeof (*(mem)) == 2) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.w @%2,r2\n\ -	  add r2,%1\n\ -	  mov.w %1,@%2\n\ -       1: mov r1,r15\n\ -	  shal %1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else if (sizeof (*(mem)) == 4) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.l @%2,r2\n\ -	  add r2,%1\n\ -	  mov.l %1,@%2\n\ -       1: mov r1,r15\n\ -	  shal %1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else \ -       abort (); \ -     __result; }) +  __atomic_bool_bysize (__arch_add_negative, int, mem, value) + + +#define __arch_add_zero_8_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, b, add) == 0) + +#define __arch_add_zero_16_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, w, add) == 0) + +#define __arch_add_zero_32_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, l, add) == 0) + +#define __arch_add_zero_64_int(mem, value)		\ +  (abort (), 0)  #define atomic_add_zero(mem, value) \ -  ({ unsigned char __result; \ -     __typeof (*(mem)) __tmp, __value = (value); \ -     if (sizeof (*(mem)) == 1) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.b @%2,r2\n\ -	  add r2,%1\n\ -	  mov.b %1,@%2\n\ -       1: mov r1,r15\n\ -	  tst %1,%1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else if (sizeof (*(mem)) == 2) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.w @%2,r2\n\ -	  add r2,%1\n\ -	  mov.w %1,@%2\n\ -       1: mov r1,r15\n\ -	  tst %1,%1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else if (sizeof (*(mem)) == 4) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.l @%2,r2\n\ -	  add r2,%1\n\ -	  mov.l %1,@%2\n\ -       1: mov r1,r15\n\ -	  tst %1,%1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else \ -       abort (); \ -     __result; }) +  __atomic_bool_bysize (__arch_add_zero, int, mem, value) +  #define atomic_increment_and_test(mem) atomic_add_zero((mem), 1)  #define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1) -#define atomic_bit_set(mem, bit) \ -  (void) ({ unsigned int __mask = 1 << (bit); \ -	    if (sizeof (*(mem)) == 1) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.b @%0,r2\n\ -		or %1,r2\n\ -		mov.b r2,@%0\n\ -	     1: mov r1,r15"\ -		: : "r" (mem), "r" (__mask) \ -		: "r0", "r1", "r2", "memory"); \ -	    else if (sizeof (*(mem)) == 2) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.w @%0,r2\n\ -		or %1,r2\n\ -		mov.w r2,@%0\n\ -	     1: mov r1,r15"\ -		: : "r" (mem), "r" (__mask) \ -		: "r0", "r1", "r2", "memory"); \ -	    else if (sizeof (*(mem)) == 4) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.l @%0,r2\n\ -		or %1,r2\n\ -		mov.l r2,@%0\n\ -	     1: mov r1,r15"\ -		: : "r" (mem), "r" (__mask) \ -		: "r0", "r1", "r2", "memory"); \ -	    else \ -	      abort (); \ -	    }) - -#define atomic_bit_test_set(mem, bit) \ -  ({ unsigned int __mask = 1 << (bit); \ -     unsigned int __result = __mask; \ -     if (sizeof (*(mem)) == 1) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  nop\n\ -	  mov r15,r1\n\ -	  mov #-8,r15\n\ -       0: mov.b @%2,r2\n\ -	  or r2,%1\n\ -	  and r2,%0\n\ -	  mov.b %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__mask) \ -	: "r" (mem), "0" (__result), "1" (__mask) \ -	: "r0", "r1", "r2", "memory"); \ -     else if (sizeof (*(mem)) == 2) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  nop\n\ -	  mov r15,r1\n\ -	  mov #-8,r15\n\ -       0: mov.w @%2,r2\n\ -	  or r2,%1\n\ -	  and r2,%0\n\ -	  mov.w %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__mask) \ -	: "r" (mem), "0" (__result), "1" (__mask) \ -	: "r0", "r1", "r2", "memory"); \ -     else if (sizeof (*(mem)) == 4) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  nop\n\ -	  mov r15,r1\n\ -	  mov #-8,r15\n\ -       0: mov.l @%2,r2\n\ -	  or r2,%1\n\ -	  and r2,%0\n\ -	  mov.l %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__mask) \ -	: "r" (mem), "0" (__result), "1" (__mask) \ -	: "r0", "r1", "r2", "memory"); \ -     else \ -       abort (); \ -     __result; }) + +#define __arch_bit_set_8_int(mem, value)		\ +  __arch_operate_new_n(mem, 1<<(value), b, or) + +#define __arch_bit_set_16_int(mem, value)		\ +  __arch_operate_new_n(mem, 1<<(value), w, or) + +#define __arch_bit_set_32_int(mem, value)		\ +  __arch_operate_new_n(mem, 1<<(value), l, or) + +#define __arch_bit_set_64_int(mem, value)		\ +  (abort (), 0) + +#define __arch_add_64_int(mem, value)			\ +  (abort (), 0) + +#define atomic_bit_set(mem, value) \ +  ((void) __atomic_val_bysize (__arch_bit_set, int, mem, value)) + + +#define __arch_bit_test_set_8_int(mem, value)				\ +  ({ int32_t __value = 1<<(value), __new, __old;			\ +    __arch_operate_old_new_n((mem), __value, __old, __new, b, or);	\ +    __old & __value; }) + +#define __arch_bit_test_set_16_int(mem, value)				\ +  ({ int32_t __value = 1<<(value), __new, __old;			\ +    __arch_operate_old_new_n((mem), __value, __old, __new, w, or);	\ +    __old & __value; }) + +#define __arch_bit_test_set_32_int(mem, value)				\ +  ({ int32_t __value = 1<<(value), __new, __old;			\ +    __arch_operate_old_new_n((mem), __value, __old, __new, l, or);	\ +    __old & __value; }) + +#define __arch_bit_test_set_64_int(mem, value)	\ +  (abort (), 0) + +#define atomic_bit_test_set(mem, value) \ +  __atomic_val_bysize (__arch_bit_test_set, int, mem, value) diff --git a/libc/sysdeps/linux/sh/clone.S b/libc/sysdeps/linux/sh/clone.S index 3d18b6dd0..423a6c2f1 100644 --- a/libc/sysdeps/linux/sh/clone.S +++ b/libc/sysdeps/linux/sh/clone.S @@ -1,4 +1,4 @@ -/* Copyright (C) 1999, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1999, 2000, 2003, 2004, 2007 Free Software Foundation, Inc.     This file is part of the GNU C Library.     The GNU C Library is free software; you can redistribute it and/or @@ -20,93 +20,94 @@     and invokes a function in the right context after its all over.  */  #include <features.h> -#include <sys/syscall.h> -#define _ERRNO_H +#include <asm/unistd.h> +#include <sysdep.h> +#define _ERRNO_H	1  #include <bits/errno.h> -#include <bits/sysnum.h> - - -#ifdef __PIC__ -#define PLTJMP(_x)	_x@PLT -#else -#define PLTJMP(_x)	_x +#ifdef RESET_PID +#include <tcb-offsets.h>  #endif +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, +	     pid_t *ptid, void *tls, pid_t *ctid); */ - -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ - -        .text - -.text -.align 4 -.type	clone,@function -.globl	clone; -clone: +	.text +ENTRY(__clone)  	/* sanity check arguments.  */  	tst	r4, r4 -	bt	0f -	tst	r5, r5 -	bf/s	1f -	 mov	#+__NR_clone, r3 -0:		 -	bra __syscall_error -	 mov	#-EINVAL, r4 - +	bt/s	0f +	 tst	r5, r5 +	bf	1f +0: +	bra	.Lsyscall_error +	 mov	#-EINVAL,r0  1:  	/* insert the args onto the new stack */  	mov.l	r7, @-r5  	/* save the function pointer as the 0th element */  	mov.l	r4, @-r5 -	 +  	/* do the system call */  	mov	r6, r4 -	trapa	#(__SH_SYSCALL_TRAP_BASE + 2) +	mov.l	@r15, r6 +	mov.l	@(8,r15), r7 +	mov.l	@(4,r15), r0 +	mov	#+SYS_ify(clone), r3 +	trapa	#0x15  	mov     r0, r1 -#ifdef __sh2__ -/* 12 arithmetic shifts for the crappy sh2, because shad doesn't exist!	 */ -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -#else		  	mov	#-12, r2  	shad	r2, r1 -#endif -	not	r1, r1			/* r1=0 means r0 = -1 to -4095 */ -	tst	r1, r1			/* i.e. error in linux */ -	bf/s	2f -	 tst	r0, r0 -        bra __syscall_error -	 mov	r0, r4 - -2: -	bt	3f +	not	r1, r1			// r1=0 means r0 = -1 to -4095 +	tst	r1, r1			// i.e. error in linux +	bf	.Lclone_end +.Lsyscall_error: +	SYSCALL_ERROR_HANDLER +.Lclone_end: +	tst	r0, r0 +	bt	2f +.Lpseudo_end:  	rts  	 nop +2: +	/* terminate the stack frame */ +	mov	#0, r14 +#ifdef RESET_PID +	mov	r4, r0 +	shlr16	r0 +	tst	#1, r0			// CLONE_THREAD = (1 << 16) +	bf/s	4f +	 mov	r4, r0 +	/* new pid */ +	shlr8	r0 +	tst	#1, r0			// CLONE_VM = (1 << 8) +	bf/s	3f +	 mov	#-1, r0 +	mov	#+SYS_ify(getpid), r3 +	trapa	#0x15  3: +	stc	gbr, r1 +	mov.w	.Lpidoff, r2 +	add	r1, r2 +	mov.l	r0, @r2 +	mov.w	.Ltidoff, r2 +	add	r1, r2 +	mov.l	r0, @r2 +4: +#endif  	/* thread starts */  	mov.l	@r15, r1  	jsr	@r1  	 mov.l	@(4,r15), r4  	/* we are done, passing the return value through r0  */ -	mov.l	.L1, r1 -#ifdef __PIC__ +	mov.l	.L3, r1 +#ifdef SHARED  	mov.l	r12, @-r15  	sts.l	pr, @-r15  	mov	r0, r4 -	mova	.LG, r0  /* .LG from syscall_error.S */ +	mova	.LG, r0  	mov.l	.LG, r12  	add	r0, r12 -	mova	.L1, r0 +	mova	.L3, r0  	add	r0, r1  	jsr	@r1  	 nop @@ -118,8 +119,16 @@ clone:  	 mov	r0, r4  #endif  	.align	2 -.L1: -	.long	PLTJMP( HIDDEN_JUMPTARGET(_exit)) -.size clone,.-clone; +.LG: +	.long	_GLOBAL_OFFSET_TABLE_ +.L3: +	.long	PLTJMP(C_SYMBOL_NAME(_exit)) +#ifdef RESET_PID +.Lpidoff: +	.word	PID - TLS_PRE_TCB_SIZE +.Ltidoff: +	.word	TID - TLS_PRE_TCB_SIZE +#endif +PSEUDO_END (__clone) -#include "syscall_error.S" +weak_alias (__clone, clone) diff --git a/libc/sysdeps/linux/sh/longjmp.c b/libc/sysdeps/linux/sh/longjmp.c new file mode 100644 index 000000000..dd0616d8a --- /dev/null +++ b/libc/sysdeps/linux/sh/longjmp.c @@ -0,0 +1,56 @@ +/* Copyright (C) 1991, 92, 94, 95, 97, 98, 2000 Free Software Foundation, Inc. +   Copyright (C) 2001 Hewlett-Packard Australia + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU Library General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more + details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Derived in part from the Linux-8086 C library, the GNU C Library, and several + other sundry sources.  Files within this library are copyright by their + respective copyright holders. +*/ + +#include <stddef.h> +#include <setjmp.h> +#include <signal.h> + +libc_hidden_proto(sigprocmask) + +extern int __longjmp(char *env, int val); +libc_hidden_proto(__longjmp) + +extern void _longjmp_unwind (jmp_buf env, int val); + + +/* Set the signal mask to the one specified in ENV, and jump +   to the position specified in ENV, causing the setjmp +   call there to return VAL, or 1 if VAL is 0.  */ +void __libc_siglongjmp (sigjmp_buf env, int val) +{ +  /* Perform any cleanups needed by the frames being unwound.  */ + +  _longjmp_unwind (env, val); + +  if (env[0].__mask_was_saved) +    /* Restore the saved signal mask.  */ +    (void) sigprocmask (SIG_SETMASK, &env[0].__saved_mask, +			  (sigset_t *) NULL); + +  /* Call the machine-dependent function to restore machine state.  */ +  __longjmp ((char *) env[0].__jmpbuf, val ?: 1); +} + +__asm__(".weak longjmp; longjmp = __libc_siglongjmp"); +__asm__(".weak _longjmp; _longjmp = __libc_siglongjmp"); +__asm__(".weak siglongjmp; siglongjmp = __libc_siglongjmp"); +strong_alias(__libc_siglongjmp, __libc_longjmp) diff --git a/libc/sysdeps/linux/sh/pread_write.c b/libc/sysdeps/linux/sh/pread_write.c index 84a28e766..86feb9cce 100644 --- a/libc/sysdeps/linux/sh/pread_write.c +++ b/libc/sysdeps/linux/sh/pread_write.c @@ -18,6 +18,13 @@  #include <stdint.h>  #include <endian.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif + +  #ifdef __NR_pread64             /* Newer kernels renamed but it's the same.  */  # ifdef __NR_pread  #  error "__NR_pread and __NR_pread64 both defined???" @@ -33,7 +40,15 @@ static __inline__ _syscall6(ssize_t, __syscall_pread, int, fd, void *, buf,  ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset)  { -	return(__syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset))); +	if (SINGLE_THREAD_P) +		return(__syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset))); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	ssize_t result = __syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif  }  weak_alias(__libc_pread,pread) @@ -43,7 +58,16 @@ ssize_t __libc_pread64(int fd, void *buf, size_t count, off64_t offset)  {  	uint32_t low = offset & 0xffffffff;  	uint32_t high = offset >> 32; -	return(__syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low))); + +	if (SINGLE_THREAD_P) +		return __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	ssize_t result = __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif  }  weak_alias(__libc_pread64,pread64)  # endif /* __UCLIBC_HAS_LFS__  */ @@ -66,7 +90,16 @@ static __inline__ _syscall6(ssize_t, __syscall_pwrite, int, fd, const void *, bu  ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset)  { -	return(__syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset))); +	if (SINGLE_THREAD_P) +		return __syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	ssize_t result = __syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif +  }  weak_alias(__libc_pwrite,pwrite) @@ -76,7 +109,16 @@ ssize_t __libc_pwrite64(int fd, const void *buf, size_t count, off64_t offset)  {  	uint32_t low = offset & 0xffffffff;  	uint32_t high = offset >> 32; -	return(__syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low))); + +	if (SINGLE_THREAD_P) +		return __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	ssize_t result = __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif  }  weak_alias(__libc_pwrite64,pwrite64)  # endif /* __UCLIBC_HAS_LFS__  */ diff --git a/libc/sysdeps/linux/sh/setjmp.S b/libc/sysdeps/linux/sh/setjmp.S index 00475a008..0a81424e1 100644 --- a/libc/sysdeps/linux/sh/setjmp.S +++ b/libc/sysdeps/linux/sh/setjmp.S @@ -77,7 +77,7 @@ __sigsetjmp_intern:  	mov.l	r9, @-r4  	mov.l	r8, @-r4 -#ifdef __PIC__ +#ifdef __HAVE_SHARED__  	mov.l	.LG, r2  	mova	.LG, r0  	add	r0, r2 diff --git a/libc/sysdeps/linux/sh/syscall_error.S b/libc/sysdeps/linux/sh/syscall_error.S index f55dd535a..737950308 100644 --- a/libc/sysdeps/linux/sh/syscall_error.S +++ b/libc/sysdeps/linux/sh/syscall_error.S @@ -3,7 +3,7 @@ __syscall_error:  	/* Call errno_location, store '-r4' in errno and return -1 */  	mov.l	r12, @-r15  	sts.l	pr, @-r15 -#ifdef __PIC__ +#ifdef SHARED  	mova	.LG, r0  	mov.l	.LG, r12  	add	r0, r12 @@ -27,7 +27,7 @@ __syscall_error:  	.align	4 -#ifdef __PIC__ +#ifdef SHARED  1:	.long   __errno_location@GOT  .LG:	.long	_GLOBAL_OFFSET_TABLE_  #else diff --git a/libc/sysdeps/linux/sh/sysdep.h b/libc/sysdeps/linux/sh/sysdep.h index 6f182cd0e..bd6234292 100644 --- a/libc/sysdeps/linux/sh/sysdep.h +++ b/libc/sysdeps/linux/sh/sysdep.h @@ -144,7 +144,7 @@  #define ret_ERRVAL ret -#ifndef PIC +#ifndef __PIC__  # define SYSCALL_ERROR_HANDLER	\  	mov.l 0f,r1; \  	jmp @r1; \ @@ -246,7 +246,7 @@       0: .long _GLOBAL_OFFSET_TABLE_; \       1: .long errno@GOT  # endif	/* _LIBC_REENTRANT */ -#endif	/* PIC */ +#endif	/* __PIC__ */  # ifdef __SH4__  #  define SYSCALL_INST_PAD \ @@ -273,5 +273,24 @@      .align 2;				\   1: .long SYS_ify (syscall_name);	\   2: -  #endif	/* __ASSEMBLER__ */ + +/* Pointer mangling support.  */ +#if defined NOT_IN_libc && defined IS_IN_rtld +/* We cannot use the thread descriptor because in ld.so we use setjmp +   earlier than the descriptor is initialized.  Using a global variable +   is too complicated here since we have no PC-relative addressing mode.  */ +#else +# ifdef __ASSEMBLER__ +#  define PTR_MANGLE(reg, tmp) \ +     stc gbr,tmp; mov.l @(POINTER_GUARD,tmp),tmp; xor tmp,reg +#  define PTR_MANGLE2(reg, tmp)	xor tmp,reg +#  define PTR_DEMANGLE(reg, tmp)	PTR_MANGLE (reg, tmp) +#  define PTR_DEMANGLE2(reg, tmp)	PTR_MANGLE2 (reg, tmp) +# else +#  define PTR_MANGLE(var) \ +     (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ()) +#  define PTR_DEMANGLE(var)	PTR_MANGLE (var) +# endif +#endif + diff --git a/libc/sysdeps/linux/sparc/Makefile.arch b/libc/sysdeps/linux/sparc/Makefile.arch index ffae27bc7..8a624205a 100644 --- a/libc/sysdeps/linux/sparc/Makefile.arch +++ b/libc/sysdeps/linux/sparc/Makefile.arch @@ -5,8 +5,15 @@  # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.  # -CSRC := brk.c __syscall_error.c qp_ops.c sigaction.c +CSRC := brk.c __syscall_error.c qp_ops.c  SSRC := \ -	__longjmp.S fork.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ +	__longjmp.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \  	syscall.S urem.S udiv.S umul.S sdiv.S rem.S pipe.S + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +SSRC += fork.S vfork.S +endif + + diff --git a/libc/sysdeps/linux/sparc/bits/atomic.h b/libc/sysdeps/linux/sparc/bits/atomic.h new file mode 100644 index 000000000..f625eb92a --- /dev/null +++ b/libc/sysdeps/linux/sparc/bits/atomic.h @@ -0,0 +1,329 @@ +/* Atomic operations.  sparc32 version. +   Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_ATOMIC_H +#define _BITS_ATOMIC_H	1 + +#include <stdint.h> + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +typedef int16_t atomic16_t; +typedef uint16_t uatomic16_t; +typedef int_fast16_t atomic_fast16_t; +typedef uint_fast16_t uatomic_fast16_t; + +typedef int32_t atomic32_t; +typedef uint32_t uatomic32_t; +typedef int_fast32_t atomic_fast32_t; +typedef uint_fast32_t uatomic_fast32_t; + +typedef int64_t atomic64_t; +typedef uint64_t uatomic64_t; +typedef int_fast64_t atomic_fast64_t; +typedef uint_fast64_t uatomic_fast64_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + + +/* We have no compare and swap, just test and set. +   The following implementation contends on 64 global locks +   per library and assumes no variable will be accessed using atomic.h +   macros from two different libraries.  */ + +__make_section_unallocated +  (".gnu.linkonce.b.__sparc32_atomic_locks, \"aw\", %nobits"); + +volatile unsigned char __sparc32_atomic_locks[64] +  __attribute__ ((nocommon, section (".gnu.linkonce.b.__sparc32_atomic_locks" +				     __sec_comment), +		  visibility ("hidden"))); + +#define __sparc32_atomic_do_lock(addr) \ +  do								      \ +    {								      \ +      unsigned int __old_lock;					      \ +      unsigned int __idx = (((long) addr >> 2) ^ ((long) addr >> 12)) \ +			   & 63;				      \ +      do							      \ +	__asm __volatile ("ldstub %1, %0"			      \ +			  : "=r" (__old_lock),			      \ +			    "=m" (__sparc32_atomic_locks[__idx])      \ +			  : "m" (__sparc32_atomic_locks[__idx])	      \ +			  : "memory");				      \ +      while (__old_lock);					      \ +    }								      \ +  while (0) + +#define __sparc32_atomic_do_unlock(addr) \ +  do								      \ +    {								      \ +      __sparc32_atomic_locks[(((long) addr >> 2)		      \ +			      ^ ((long) addr >> 12)) & 63] = 0;	      \ +      __asm __volatile ("" ::: "memory");			      \ +    }								      \ +  while (0) + +#define __sparc32_atomic_do_lock24(addr) \ +  do								      \ +    {								      \ +      unsigned int __old_lock;					      \ +      do							      \ +	__asm __volatile ("ldstub %1, %0"			      \ +			  : "=r" (__old_lock), "=m" (*(addr))	      \ +			  : "m" (*(addr))			      \ +			  : "memory");				      \ +      while (__old_lock);					      \ +    }								      \ +  while (0) + +#define __sparc32_atomic_do_unlock24(addr) \ +  do								      \ +    {								      \ +      *(char *) (addr) = 0;					      \ +      __asm __volatile ("" ::: "memory");			      \ +    }								      \ +  while (0) + + +#ifndef SHARED +# define __v9_compare_and_exchange_val_32_acq(mem, newval, oldval) \ +({									      \ +  register __typeof (*(mem)) __acev_tmp __asm ("%g6");			      \ +  register __typeof (mem) __acev_mem __asm ("%g1") = (mem);		      \ +  register __typeof (*(mem)) __acev_oldval __asm ("%g5");		      \ +  __acev_tmp = (newval);						      \ +  __acev_oldval = (oldval);						      \ +  /* .word 0xcde05005 is cas [%g1], %g5, %g6.  Can't use cas here though,     \ +     because as will then mark the object file as V8+ arch.  */		      \ +  __asm __volatile (".word 0xcde05005"					      \ +		    : "+r" (__acev_tmp), "=m" (*__acev_mem)		      \ +		    : "r" (__acev_oldval), "m" (*__acev_mem),		      \ +		      "r" (__acev_mem) : "memory");			      \ +  __acev_tmp; }) +#endif + +/* The only basic operation needed is compare and exchange.  */ +#define __v7_compare_and_exchange_val_acq(mem, newval, oldval) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +     __typeof (*mem) __acev_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock (__acev_memp);			      \ +     __acev_ret = *__acev_memp;					      \ +     if (__acev_ret == (oldval))				      \ +       *__acev_memp = __acev_newval;				      \ +     __sparc32_atomic_do_unlock (__acev_memp);			      \ +     __acev_ret; }) + +#define __v7_compare_and_exchange_bool_acq(mem, newval, oldval) \ +  ({ __typeof (mem) __aceb_memp = (mem);			      \ +     int __aceb_ret;						      \ +     __typeof (*mem) __aceb_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock (__aceb_memp);			      \ +     __aceb_ret = 0;						      \ +     if (*__aceb_memp == (oldval))				      \ +       *__aceb_memp = __aceb_newval;				      \ +     else							      \ +       __aceb_ret = 1;						      \ +     __sparc32_atomic_do_unlock (__aceb_memp);			      \ +     __aceb_ret; }) + +#define __v7_exchange_acq(mem, newval) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +     __typeof (*mem) __acev_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock (__acev_memp);			      \ +     __acev_ret = *__acev_memp;					      \ +     *__acev_memp = __acev_newval;				      \ +     __sparc32_atomic_do_unlock (__acev_memp);			      \ +     __acev_ret; }) + +#define __v7_exchange_and_add(mem, value) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +								      \ +     __sparc32_atomic_do_lock (__acev_memp);			      \ +     __acev_ret = *__acev_memp;					      \ +     *__acev_memp = __acev_ret + (value);			      \ +     __sparc32_atomic_do_unlock (__acev_memp);			      \ +     __acev_ret; }) + +/* Special versions, which guarantee that top 8 bits of all values +   are cleared and use those bits as the ldstub lock.  */ +#define __v7_compare_and_exchange_val_24_acq(mem, newval, oldval) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +     __typeof (*mem) __acev_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock24 (__acev_memp);			      \ +     __acev_ret = *__acev_memp & 0xffffff;			      \ +     if (__acev_ret == (oldval))				      \ +       *__acev_memp = __acev_newval;				      \ +     else							      \ +       __sparc32_atomic_do_unlock24 (__acev_memp);		      \ +     __asm __volatile ("" ::: "memory");			      \ +     __acev_ret; }) + +#define __v7_exchange_24_rel(mem, newval) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +     __typeof (*mem) __acev_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock24 (__acev_memp);			      \ +     __acev_ret = *__acev_memp & 0xffffff;			      \ +     *__acev_memp = __acev_newval;				      \ +     __asm __volatile ("" ::: "memory");			      \ +     __acev_ret; }) + +#ifdef SHARED + +/* When dynamically linked, we assume pre-v9 libraries are only ever +   used on pre-v9 CPU.  */ +# define __atomic_is_v9 0 + +# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ +  __v7_compare_and_exchange_val_acq (mem, newval, oldval) + +# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ +  __v7_compare_and_exchange_bool_acq (mem, newval, oldval) + +# define atomic_exchange_acq(mem, newval) \ +  __v7_exchange_acq (mem, newval) + +# define atomic_exchange_and_add(mem, value) \ +  __v7_exchange_and_add (mem, value) + +# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ +  ({								      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     __v7_compare_and_exchange_val_24_acq (mem, newval, oldval); }) + +# define atomic_exchange_24_rel(mem, newval) \ +  ({								      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     __v7_exchange_24_rel (mem, newval); }) + +#else + + + +/* +   Here's what we'd like to do: + +   In libc.a/libpthread.a etc. we don't know if we'll be run on +   pre-v9 or v9 CPU.  To be interoperable with dynamically linked +   apps on v9 CPUs e.g. with process shared primitives, use cas insn +   on v9 CPUs and ldstub on pre-v9. + +   However, we have no good way to test at run time that I know of, +   so resort to the lowest common denominator (v7 ops) -austinf + */ +#define __atomic_is_v9 0 + +# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ +  ({								      \ +     __typeof (*mem) __acev_wret;				      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       __acev_wret						      \ +	 = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ +     else							      \ +       __acev_wret						      \ +	 = __v7_compare_and_exchange_val_acq (mem, newval, oldval);   \ +     __acev_wret; }) + +# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ +  ({								      \ +     int __acev_wret;						      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       {							      \ +	 __typeof (oldval) __acev_woldval = (oldval);		      \ +	 __acev_wret						      \ +	   = __v9_compare_and_exchange_val_32_acq (mem, newval,	      \ +						   __acev_woldval)    \ +	     != __acev_woldval;					      \ +       }							      \ +     else							      \ +       __acev_wret						      \ +	 = __v7_compare_and_exchange_bool_acq (mem, newval, oldval);  \ +     __acev_wret; }) + +# define atomic_exchange_rel(mem, newval) \ +  ({								      \ +     __typeof (*mem) __acev_wret;				      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       {							      \ +	 __typeof (mem) __acev_wmemp = (mem);			      \ +	 __typeof (*(mem)) __acev_wval = (newval);		      \ +	 do							      \ +	   __acev_wret = *__acev_wmemp;				      \ +	 while (__builtin_expect				      \ +		  (__v9_compare_and_exchange_val_32_acq (__acev_wmemp,\ +							 __acev_wval, \ +							 __acev_wret) \ +		   != __acev_wret, 0));				      \ +       }							      \ +     else							      \ +       __acev_wret = __v7_exchange_acq (mem, newval);		      \ +     __acev_wret; }) + +# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ +  ({								      \ +     __typeof (*mem) __acev_wret;				      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       __acev_wret						      \ +	 = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ +     else							      \ +       __acev_wret						      \ +	 = __v7_compare_and_exchange_val_24_acq (mem, newval, oldval);\ +     __acev_wret; }) + +# define atomic_exchange_24_rel(mem, newval) \ +  ({								      \ +     __typeof (*mem) __acev_w24ret;				      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       __acev_w24ret = atomic_exchange_rel (mem, newval);	      \ +     else							      \ +       __acev_w24ret = __v7_exchange_24_rel (mem, newval);	      \ +     __acev_w24ret; }) + +#endif + +#endif	/* bits/atomic.h */ diff --git a/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h b/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h index 1dbfa2b55..2d8cdd78b 100644 --- a/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h @@ -36,7 +36,7 @@  #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__  /* define if target supports CFI pseudo ops */ -#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ +#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__  /* define if target supports IEEE signed zero floats */  #define __UCLIBC_HAVE_SIGNED_ZERO__ diff --git a/libc/sysdeps/linux/sparc/clone.S b/libc/sysdeps/linux/sparc/clone.S index 0e41ee0cb..2b6609531 100644 --- a/libc/sysdeps/linux/sparc/clone.S +++ b/libc/sysdeps/linux/sparc/clone.S @@ -1,4 +1,5 @@ -/* Copyright (C) 1996, 1997, 1998, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2007 +   Free Software Foundation, Inc.     This file is part of the GNU C Library.     Contributed by Richard Henderson (rth@tamu.edu). @@ -20,47 +21,87 @@  /* clone() is even more special than fork() as it mucks with stacks     and invokes a function in the right context after its all over.  */ -#include <features.h> +#include <asm/errno.h>  #include <asm/unistd.h> +#include <tcb-offsets.h> +#include <sysdep.h> -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ +#define CLONE_VM	0x00000100 +#define CLONE_THREAD	0x00010000 -.text -.global clone -.type   clone,%function -.align 4 +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, +	     pid_t *ptid, void *tls, pid_t *ctid); */ -clone: +	.text +ENTRY (__clone)  	save	%sp,-96,%sp +	cfi_def_cfa_register(%fp) +	cfi_window_save +	cfi_register(%o7, %i7)  	/* sanity check arguments */ -	tst	%i0 -	be	__error -	orcc	%i1,%g0,%o1 -	be	__error -	mov	%i2,%o0 +	orcc	%i0,%g0,%g2 +	be	.Leinval +	 orcc	%i1,%g0,%o1 +	be	.Leinval +	 mov	%i2,%o0 + +	/* The child_stack is the top of the stack, allocate one +	   whole stack frame from that as this is what the kernel +	   expects.  */ +	sub	%o1, 96, %o1 +	mov	%i3, %g3 +	mov	%i2, %g4 + +	/* ptid */ +	mov	%i4,%o2 +	/* tls */ +	mov	%i5,%o3 +	/* ctid */ +	ld	[%fp+92],%o4  	/* Do the system call */  	set	__NR_clone,%g1  	ta	0x10 -	bcs	__error -	tst	%o1 +	bcs	.Lerror +	 tst	%o1  	bne	__thread_start -	nop -	ret -	restore %o0,%g0,%o0 - -__error: -	jmp __syscall_error +	 nop +	jmpl	%i7 + 8, %g0 +	 restore %o0,%g0,%o0 -.size clone,.-clone - -.type __thread_start,%function +.Leinval: +	mov	EINVAL, %o0 +.Lerror: +	call	__errno_location +	 mov	%o0, %i0 +	st	%i0,[%o0] +	jmpl	%i7 + 8, %g0 +	 restore %g0,-1,%o0 +END(__clone) +	.type	__thread_start,@function  __thread_start: -	call	%i0 -	mov	%i3,%o0 -	call	HIDDEN_JUMPTARGET(_exit),0 -	nop +#ifdef RESET_PID +	sethi	%hi(CLONE_THREAD), %l0 +	andcc	%g4, %l0, %g0 +	bne	1f +	 andcc	%g4, CLONE_VM, %g0 +	bne,a	2f +	 mov	-1,%o0 +	set	__NR_getpid,%g1 +	ta	0x10 +2: +	st	%o0,[%g7 + PID] +	st	%o0,[%g7 + TID] +1: +#endif +	mov	%g0, %fp	/* terminate backtrace */ +	call	%g2 +	 mov	%g3,%o0 +	call	exit,0 +	 nop + +	.size	__thread_start, .-__thread_start -.size __thread_start,.-__thread_start +weak_alias (__clone, clone) diff --git a/libc/sysdeps/linux/sparc/sigaction.c b/libc/sysdeps/linux/sparc/sigaction.c index 7140fd3a4..a22ac40af 100644 --- a/libc/sysdeps/linux/sparc/sigaction.c +++ b/libc/sysdeps/linux/sparc/sigaction.c @@ -34,8 +34,7 @@ _syscall5(int, rt_sigaction, int, a, int, b, int, c, int, d, int, e);  static void __rt_sigreturn_stub(void);  static void __sigreturn_stub(void); -libc_hidden_proto(sigaction) -int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) +int __libc_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)  {  	int ret;  	struct sigaction kact, koact; @@ -66,8 +65,10 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)  	return ret;  } -libc_hidden_def(sigaction) -weak_alias(sigaction,__libc_sigaction) +#ifndef LIBC_SIGACTION +weak_alias(__libc_sigaction,sigaction) +libc_hidden_weak(sigaction) +#endif  static void  __rt_sigreturn_stub(void) diff --git a/libc/sysdeps/linux/sparc/sparcv9/clone.S b/libc/sysdeps/linux/sparc/sparcv9/clone.S new file mode 100644 index 000000000..9d101e239 --- /dev/null +++ b/libc/sysdeps/linux/sparc/sparcv9/clone.S @@ -0,0 +1,102 @@ +/* Copyright (C) 1997, 2000, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Richard Henderson (rth@tamu.edu). + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* clone() is even more special than fork() as it mucks with stacks +   and invokes a function in the right context after its all over.  */ + +#include <asm/errno.h> +#include <asm/unistd.h> +#include <tcb-offsets.h> +#include <sysdep.h> + +#define CLONE_VM	0x00000100 +#define CLONE_THREAD	0x00010000 + +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, +	     pid_t *ptid, void *tls, pid_t *ctid); */ + +	.register	%g2,#scratch +	.register	%g3,#scratch + +	.text + +ENTRY (__clone) +	save	%sp, -192, %sp +	cfi_def_cfa_register(%fp) +	cfi_window_save +	cfi_register(%o7, %i7) + +	/* sanity check arguments */ +	brz,pn	%i0, 99f		/* fn non-NULL? */ +	 mov	%i0, %g2 +	brz,pn	%i1, 99f		/* child_stack non-NULL? */ +	 mov	%i2, %o0		/* clone flags */ + +	/* The child_stack is the top of the stack, allocate one +	   whole stack frame from that as this is what the kernel +	   expects.  Also, subtract STACK_BIAS.  */ +	sub	%i1, 192 + 0x7ff, %o1 +	mov	%i3, %g3 +	mov	%i2, %g4 + +	mov	%i4,%o2			/* PTID */ +	mov	%i5,%o3			/* TLS */ +	ldx	[%fp+0x7ff+176],%o4	/* CTID */ + +	/* Do the system call */ +	set	__NR_clone, %g1 +	ta	0x6d +	bcs,pn	%xcc, 98f +	 nop +	brnz,pn	%o1, __thread_start +	 nop +	jmpl	%i7 + 8, %g0 +	 restore %o0, %g0, %o0 +99:	mov	EINVAL, %o0 +98:	call	HIDDEN_JUMPTARGET(__errno_location) +	 mov	%o0, %i0 +	st	%i0, [%o0] +	jmpl	%i7 + 8, %g0 +	 restore %g0,-1,%o0 +END(__clone) + +	.type __thread_start,@function +__thread_start: +#ifdef RESET_PID +	sethi	%hi(CLONE_THREAD), %l0 +	andcc	%g4, %l0, %g0 +	bne,pt	%icc, 1f +	 andcc	%g4, CLONE_VM, %g0 +	bne,a,pn %icc, 2f +	 mov	-1,%o0 +	set	__NR_getpid,%g1 +	ta	0x6d +2:	st	%o0,[%g7 + PID] +	st	%o0,[%g7 + TID] +1: +#endif +	mov	%g0, %fp	/* terminate backtrace */ +	call	%g2 +	 mov	%g3,%o0 +	call	HIDDEN_JUMPTARGET(_exit),0 +	 nop + +	.size	__thread_start, .-__thread_start + +weak_alias (__clone, clone) diff --git a/libc/sysdeps/linux/sparc/sysdep.h b/libc/sysdeps/linux/sparc/sysdep.h new file mode 100644 index 000000000..cf3e3afd1 --- /dev/null +++ b/libc/sysdeps/linux/sparc/sysdep.h @@ -0,0 +1,69 @@ +#ifndef _LINUX_SPARC_SYSDEP_H +#define _LINUX_SPARC_SYSDEP_H 1 + +#include <common/sysdep.h> + +#undef ENTRY +#undef END + +#ifdef __ASSEMBLER__ + +#define LOADSYSCALL(x) mov __NR_##x, %g1 + +#define ENTRY(name)                 \ +    .align 4;                       \ +    .global C_SYMBOL_NAME(name);    \ +    .type   name, @function;        \ +C_LABEL(name)                       \ +    cfi_startproc; + +#define END(name)                   \ +    cfi_endproc;                    \ +    .size name, . - name + +#define LOC(name) .L##name + +	/* If the offset to __syscall_error fits into a signed 22-bit +	 * immediate branch offset, the linker will relax the call into +	 * a normal branch. +	 */ +#undef PSEUDO +#undef PSEUDO_END +#undef PSEUDO_NOERRNO +#undef PSEUDO_ERRVAL + +#define PSEUDO(name, syscall_name, args)	\ +	.text;					\ +	.globl		__syscall_error;	\ +ENTRY(name);					\ +	LOADSYSCALL(syscall_name);		\ +	ta		0x10;			\ +	bcc		1f;			\ +	 mov		%o7, %g1;		\ +	call		__syscall_error;	\ +	 mov		%g1, %o7;		\ +1: + +#define PSEUDO_NOERRNO(name, syscall_name, args)\ +	.text;					\ +ENTRY(name);					\ +	LOADSYSCALL(syscall_name);		\ +	ta		0x10; + +#define PSEUDO_ERRVAL(name, syscall_name, args)	\ +	.text;					\ +ENTRY(name);					\ +	LOADSYSCALL(syscall_name);		\ +	ta		0x10; + +#define PSEUDO_END(name)			\ +	END(name) + + +#endif /* __ASSEMBLER__ */ + +/* Pointer mangling is not yet supported for SPARC.  */ +#define PTR_MANGLE(var) (void) (var) +#define PTR_DEMANGLE(var) (void) (var) + +#endif diff --git a/libc/sysdeps/linux/x86_64/Makefile.arch b/libc/sysdeps/linux/x86_64/Makefile.arch index 044f97f95..de7ce7285 100644 --- a/libc/sysdeps/linux/x86_64/Makefile.arch +++ b/libc/sysdeps/linux/x86_64/Makefile.arch @@ -5,7 +5,15 @@  # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.  # -CSRC := brk.c sigaction.c __syscall_error.c mmap.c +CSRC := brk.c __syscall_error.c mmap.c + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +endif  SSRC := \ -	__longjmp.S vfork.S setjmp.S syscall.S bsd-setjmp.S bsd-_setjmp.S clone.S +	__longjmp.S setjmp.S syscall.S bsd-setjmp.S bsd-_setjmp.S + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +SSRC += vfork.S clone.S +endif diff --git a/libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h b/libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h index 748e544bb..1d966aee4 100644 --- a/libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h @@ -36,7 +36,7 @@  #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__  /* define if target supports CFI pseudo ops */ -#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ +#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__  /* define if target supports IEEE signed zero floats */  #define __UCLIBC_HAVE_SIGNED_ZERO__ diff --git a/libc/sysdeps/linux/x86_64/clone.S b/libc/sysdeps/linux/x86_64/clone.S index dc5eeb0a0..8c66ce547 100644 --- a/libc/sysdeps/linux/x86_64/clone.S +++ b/libc/sysdeps/linux/x86_64/clone.S @@ -109,6 +109,8 @@ clone:  	call	*%rax  	/* Call exit with return value from function call. */  	movq	%rax, %rdi -	call	HIDDEN_JUMPTARGET(_exit) +	movl	$__NR_exit, %eax +	syscall  .size clone,.-clone +weak_alias(clone, __clone) diff --git a/libc/sysdeps/linux/x86_64/sigaction.c b/libc/sysdeps/linux/x86_64/sigaction.c index d1adbc4be..91df04e9f 100644 --- a/libc/sysdeps/linux/x86_64/sigaction.c +++ b/libc/sysdeps/linux/x86_64/sigaction.c @@ -70,13 +70,6 @@ __libc_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)  	int result;  	struct old_kernel_sigaction kact, koact; -#ifdef SIGCANCEL -	if (sig == SIGCANCEL) { -		__set_errno(EINVAL); -		return -1; -	} -#endif -  	if (act) {  		kact.k_sa_handler = act->sa_handler;  		kact.sa_mask = act->sa_mask.__val[0]; diff --git a/libc/sysdeps/linux/x86_64/sysdep.h b/libc/sysdeps/linux/x86_64/sysdep.h new file mode 100644 index 000000000..09bb9268b --- /dev/null +++ b/libc/sysdeps/linux/x86_64/sysdep.h @@ -0,0 +1,349 @@ +/* Copyright (C) 2001-2005, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LINUX_X86_64_SYSDEP_H +#define _LINUX_X86_64_SYSDEP_H 1 + +/* There is some commonality.  */ +#include <sys/syscall.h> +#include <common/sysdep.h> + +#ifdef	__ASSEMBLER__ + +/* Syntactic details of assembler.  */ + +#ifdef HAVE_ELF + +/* ELF uses byte-counts for .align, most others use log2 of count of bytes.  */ +#define ALIGNARG(log2) 1<<log2 +/* For ELF we need the `.type' directive to make shared libs work right.  */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name; + +/* In ELF C symbols are asm symbols.  */ +#undef	NO_UNDERSCORES +#define NO_UNDERSCORES + +#else + +#define ALIGNARG(log2) log2 +#define ASM_TYPE_DIRECTIVE(name,type)	/* Nothing is specified.  */ +#define ASM_SIZE_DIRECTIVE(name)	/* Nothing is specified.  */ + +#endif + + +/* Define an entry point visible from C.  */ +#define	ENTRY(name)							      \ +  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				      \ +  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function)			      \ +  .align ALIGNARG(4);							      \ +  C_LABEL(name)								      \ +  cfi_startproc;							      \ +  CALL_MCOUNT + +#undef	END +#define END(name)							      \ +  cfi_endproc;								      \ +  ASM_SIZE_DIRECTIVE(name) + +/* If compiled for profiling, call `mcount' at the start of each function.  */ +#ifdef	PROF +/* The mcount code relies on a normal frame pointer being on the stack +   to locate our caller, so push one just for its benefit.  */ +#define CALL_MCOUNT                                                          \ +  pushq %rbp;                                                                \ +  cfi_adjust_cfa_offset(8);                                                  \ +  movq %rsp, %rbp;                                                           \ +  cfi_def_cfa_register(%rbp);                                                \ +  call JUMPTARGET(mcount);                                                   \ +  popq %rbp;                                                                 \ +  cfi_def_cfa(rsp,8); +#else +#define CALL_MCOUNT		/* Do nothing.  */ +#endif + +#ifdef	NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore +   on this system, the asm identifier `syscall_error' intrudes on the +   C name space.  Make sure we use an innocuous name.  */ +#define	syscall_error	__syscall_error +#define mcount		_mcount +#endif + +#define	PSEUDO(name, syscall_name, args)				      \ +lose:									      \ +  jmp JUMPTARGET(syscall_error)						      \ +  .globl syscall_error;							      \ +  ENTRY (name)								      \ +  DO_CALL (syscall_name, args);						      \ +  jb lose + +#undef	PSEUDO_END +#define	PSEUDO_END(name)						      \ +  END (name) + +#undef JUMPTARGET +#ifdef __PIC__ +#define JUMPTARGET(name)	name##@PLT +#else +#define JUMPTARGET(name)	name +#endif + +/* Local label name for asm code. */ +#ifndef L +# ifdef HAVE_ELF +/* ELF-like local names start with `.L'.  */ +#  define L(name)	.L##name +# else +#  define L(name)	name +# endif +#endif + +#endif	/* __ASSEMBLER__ */ + +/* For Linux we can use the system call table in the header file +	/usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ +#undef SYS_ify +#define SYS_ify(syscall_name)	__NR_##syscall_name + +/* This is a kludge to make syscalls.list find these under the names +   pread and pwrite, since some kernel headers define those names +   and some define the *64 names for the same system calls.  */ +#if !defined __NR_pread && defined __NR_pread64 +# define __NR_pread __NR_pread64 +#endif +#if !defined __NR_pwrite && defined __NR_pwrite64 +# define __NR_pwrite __NR_pwrite64 +#endif + +/* This is to help the old kernel headers where __NR_semtimedop is not +   available.  */ +#ifndef __NR_semtimedop +# define __NR_semtimedop 220 +#endif + + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, +   unlike most Unices, which use the condition codes' carry flag. + +   Since version 2.1 the return value of a system call might be +   negative even if the call succeeded.	 E.g., the `lseek' system call +   might return a large offset.	 Therefore we must not anymore test +   for < 0, but test for a real error by making sure the value in %eax +   is a real error number.  Linus said he will make sure the no syscall +   returns a value in -1 .. -4095 as a valid result so we can savely +   test with -4095.  */ + +/* We don't want the label for the error handle to be global when we define +   it here.  */ +# ifdef __PIC__ +#  define SYSCALL_ERROR_LABEL 0f +# else +#  define SYSCALL_ERROR_LABEL syscall_error +# endif + +# undef	PSEUDO +# define PSEUDO(name, syscall_name, args)				      \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args);					      \ +    cmpq $-4095, %rax;							      \ +    jae SYSCALL_ERROR_LABEL;						      \ +  L(pseudo_end): + +# undef	PSEUDO_END +# define PSEUDO_END(name)						      \ +  SYSCALL_ERROR_HANDLER							      \ +  END (name) + +# undef	PSEUDO_NOERRNO +# define PSEUDO_NOERRNO(name, syscall_name, args) \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args) + +# undef	PSEUDO_END_NOERRNO +# define PSEUDO_END_NOERRNO(name) \ +  END (name) + +# define ret_NOERRNO ret + +# undef	PSEUDO_ERRVAL +# define PSEUDO_ERRVAL(name, syscall_name, args) \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args);					      \ +    negq %rax + +# undef	PSEUDO_END_ERRVAL +# define PSEUDO_END_ERRVAL(name) \ +  END (name) + +# define ret_ERRVAL ret + +# ifndef __PIC__ +#  define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */ +# elif defined(RTLD_PRIVATE_ERRNO) +#  define SYSCALL_ERROR_HANDLER			\ +0:						\ +  leaq rtld_errno(%rip), %rcx;			\ +  xorl %edx, %edx;				\ +  subq %rax, %rdx;				\ +  movl %edx, (%rcx);				\ +  orq $-1, %rax;				\ +  jmp L(pseudo_end); +# elif USE___THREAD +#  ifndef NOT_IN_libc +#   define SYSCALL_ERROR_ERRNO __libc_errno +#  else +#   define SYSCALL_ERROR_ERRNO errno +#  endif +#  define SYSCALL_ERROR_HANDLER			\ +0:						\ +  movq SYSCALL_ERROR_ERRNO@GOTTPOFF(%rip), %rcx;\ +  xorl %edx, %edx;				\ +  subq %rax, %rdx;				\ +  movl %edx, %fs:(%rcx);			\ +  orq $-1, %rax;				\ +  jmp L(pseudo_end); +# elif defined _LIBC_REENTRANT +/* Store (- %rax) into errno through the GOT. +   Note that errno occupies only 4 bytes.  */ +#  define SYSCALL_ERROR_HANDLER			\ +0:						\ +  xorl %edx, %edx;				\ +  subq %rax, %rdx;				\ +  pushq %rdx;					\ +  cfi_adjust_cfa_offset(8);			\ +  call __errno_location@PLT;		\ +  popq %rdx;					\ +  cfi_adjust_cfa_offset(-8);			\ +  movl %edx, (%rax);				\ +  orq $-1, %rax;				\ +  jmp L(pseudo_end); + +/* A quick note: it is assumed that the call to `__errno_location' does +   not modify the stack!  */ +# else /* Not _LIBC_REENTRANT.  */ +#  define SYSCALL_ERROR_HANDLER			\ +0:movq errno@GOTPCREL(%RIP), %rcx;		\ +  xorl %edx, %edx;				\ +  subq %rax, %rdx;				\ +  movl %edx, (%rcx);				\ +  orq $-1, %rax;				\ +  jmp L(pseudo_end); +# endif	/* __PIC__ */ + +/* The Linux/x86-64 kernel expects the system call parameters in +   registers according to the following table: + +    syscall number	rax +    arg 1		rdi +    arg 2		rsi +    arg 3		rdx +    arg 4		r10 +    arg 5		r8 +    arg 6		r9 + +    The Linux kernel uses and destroys internally these registers: +    return address from +    syscall		rcx +    eflags from syscall	r11 + +    Normal function call, including calls to the system call stub +    functions in the libc, get the first six parameters passed in +    registers and the seventh parameter and later on the stack.  The +    register use is as follows: + +     system call number	in the DO_CALL macro +     arg 1		rdi +     arg 2		rsi +     arg 3		rdx +     arg 4		rcx +     arg 5		r8 +     arg 6		r9 + +    We have to take care that the stack is aligned to 16 bytes.  When +    called the stack is not aligned since the return address has just +    been pushed. + + +    Syscalls of more than 6 arguments are not supported.  */ + +# undef	DO_CALL +# define DO_CALL(syscall_name, args)		\ +    DOARGS_##args				\ +    movl $SYS_ify (syscall_name), %eax;		\ +    syscall; + +# define DOARGS_0 /* nothing */ +# define DOARGS_1 /* nothing */ +# define DOARGS_2 /* nothing */ +# define DOARGS_3 /* nothing */ +# define DOARGS_4 movq %rcx, %r10; +# define DOARGS_5 DOARGS_4 +# define DOARGS_6 DOARGS_5 + +#endif	/* __ASSEMBLER__ */ + + +/* Pointer mangling support.  */ +#if defined NOT_IN_libc && defined IS_IN_rtld +/* We cannot use the thread descriptor because in ld.so we use setjmp +   earlier than the descriptor is initialized.  */ +# ifdef __ASSEMBLER__ +#  define PTR_MANGLE(reg)	xorq __pointer_chk_guard_local(%rip), reg;    \ +				rolq $17, reg +#  define PTR_DEMANGLE(reg)	rorq $17, reg;				      \ +				xorq __pointer_chk_guard_local(%rip), reg +# else +#  define PTR_MANGLE(reg)	__asm__ ("xorq __pointer_chk_guard_local(%%rip), %0\n" \ +				     "rolq $17, %0"			      \ +				     : "=r" (reg) : "0" (reg)) +#  define PTR_DEMANGLE(reg)	__asm__ ("rorq $17, %0\n"			      \ +				     "xorq __pointer_chk_guard_local(%%rip), %0" \ +				     : "=r" (reg) : "0" (reg)) +# endif +#else +# ifdef __ASSEMBLER__ +#  define PTR_MANGLE(reg)	xorq %fs:POINTER_GUARD, reg;		      \ +				rolq $17, reg +#  define PTR_DEMANGLE(reg)	rorq $17, reg;				      \ +				xorq %fs:POINTER_GUARD, reg +# else +#  define PTR_MANGLE(var)	__asm__ ("xorq %%fs:%c2, %0\n"		      \ +				     "rolq $17, %0"			      \ +				     : "=r" (var)			      \ +				     : "0" (var),			      \ +				       "i" (offsetof (tcbhead_t,	      \ +						      pointer_guard))) +#  define PTR_DEMANGLE(var)	__asm__ ("rorq $17, %0\n"			      \ +				     "xorq %%fs:%c2, %0"		      \ +				     : "=r" (var)			      \ +				     : "0" (var),			      \ +				       "i" (offsetof (tcbhead_t,	      \ +						      pointer_guard))) +# endif +#endif + +#endif /* linux/x86_64/sysdep.h */ diff --git a/libc/sysdeps/linux/x86_64/vfork.S b/libc/sysdeps/linux/x86_64/vfork.S index 2dadbbfe0..97c9c5b67 100644 --- a/libc/sysdeps/linux/x86_64/vfork.S +++ b/libc/sysdeps/linux/x86_64/vfork.S @@ -1,4 +1,4 @@ -/* Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2002, 2004, 2008 Free Software Foundation, Inc.     This file is part of the GNU C Library.     The GNU C Library is free software; you can redistribute it and/or @@ -31,7 +31,7 @@  .text  .global __vfork  .hidden __vfork -.type	__vfork,%function +.type   __vfork,%function  __vfork: @@ -39,6 +39,10 @@ __vfork:  	   is preserved by the syscall and that we're allowed to destroy. */  	popq	%rdi +#ifdef SAVE_PID +	SAVE_PID +#endif +  	/* Stuff the syscall number in RAX and enter into the kernel.  */  	movl	$__NR_vfork, %eax  	syscall @@ -46,6 +50,10 @@ __vfork:  	/* Push back the return PC.  */  	pushq	%rdi +#ifdef RESTORE_PID +	RESTORE_PID +#endif +  	cmpl	$-4095, %eax  	jae __syscall_error		/* Branch forward if it failed.  */ 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) diff --git a/libc/unistd/daemon.c b/libc/unistd/daemon.c index 741672ec0..c3b563179 100644 --- a/libc/unistd/daemon.c +++ b/libc/unistd/daemon.c @@ -46,6 +46,20 @@  #include <paths.h>  #include <signal.h>  #include <unistd.h> +#include <not-cancel.h> +#include <errno.h> + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sys/stat.h> +#endif + +#ifdef __UCLIBC_HAS_LFS__ +#define STAT stat64 +#define FSTAT fstat64 +#else +#define STAT stat +#define FSTAT fstat +#endif  #if defined __USE_BSD || (defined __USE_XOPEN && !defined __USE_UNIX98) @@ -97,15 +111,40 @@ int daemon(int nochdir, int noclose)  	if (setsid() == -1)  		return -1; +#ifndef __UCLIBC_HAS_THREADS_NATIVE__ +	/* Make certain we are not a session leader, or else we +	 * might reacquire a controlling terminal */ +	if (fork()) +		_exit(0); +#endif +  	if (!nochdir)  		chdir("/"); -	if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR)) != -1) { -		dup2(fd, STDIN_FILENO); -		dup2(fd, STDOUT_FILENO); -		dup2(fd, STDERR_FILENO); -		if (fd > 2) -			close(fd); +	if (!noclose) +	{ +		struct STAT st; + +		if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1 +			&& (__builtin_expect (FSTAT (fd, &st), 0) == 0)) +		{ +			if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0) { +				dup2(fd, STDIN_FILENO); +				dup2(fd, STDOUT_FILENO); +				dup2(fd, STDERR_FILENO); +				if (fd > 2) +					close(fd); +			} else { +				/* We must set an errno value since no +				   function call actually failed.  */ +				close_not_cancel_no_status (fd); +				__set_errno (ENODEV); +				return -1; +			} +		} else { +			close_not_cancel_no_status (fd); +			return -1; +		}  	}  	return 0;  } diff --git a/libc/unistd/sysconf.c b/libc/unistd/sysconf.c index af4389bad..b7cb4946f 100644 --- a/libc/unistd/sysconf.c +++ b/libc/unistd/sysconf.c @@ -34,10 +34,10 @@  #ifdef __UCLIBC_HAS_REGEX__  #include <regex.h>  #endif - -#ifdef HAVE_LINUX_CPUMASK_H -# include <linux/cpumask.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep.h>  #endif +  #ifndef num_present_cpus  # define num_present_cpus() (1)  #endif @@ -906,13 +906,32 @@ long int sysconf(int name)  #endif      case _SC_MONOTONIC_CLOCK: -#if defined __UCLIBC_HAS_REALTIME__ && defined __NR_clock_getres -      /* Check using the clock_getres system call.  */ +#ifdef __NR_clock_getres +    /* Check using the clock_getres system call.  */ +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +    { +      struct timespec ts; +      INTERNAL_SYSCALL_DECL (err); +      int r; +      r = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); +      return INTERNAL_SYSCALL_ERROR_P (r, err) ? -1 : _POSIX_VERSION; +    } +# else        if (clock_getres(CLOCK_MONOTONIC, NULL) >= 0)          return _POSIX_VERSION; + +      RETURN_NEG_1; +# endif  #endif +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +    case _SC_THREAD_CPUTIME: +# if _POSIX_THREAD_CPUTIME > 0 +      return _POSIX_THREAD_CPUTIME; +# else        RETURN_NEG_1; +# endif +#endif      }  }  libc_hidden_def(sysconf)  | 
