summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
Diffstat (limited to 'libc')
-rw-r--r--libc/Makefile.in4
-rw-r--r--libc/inet/getaddrinfo.c3
-rw-r--r--libc/inet/hostid.c13
-rw-r--r--libc/inet/if_index.c17
-rw-r--r--libc/inet/socketcalls.c247
-rw-r--r--libc/misc/Makefile.in1
-rw-r--r--libc/misc/dirent/closedir.c3
-rw-r--r--libc/misc/dirent/opendir.c10
-rw-r--r--libc/misc/internals/__uClibc_main.c110
-rw-r--r--libc/misc/internals/tempname.c14
-rw-r--r--libc/misc/internals/tempname.h3
-rw-r--r--libc/misc/pthread/Makefile.in1
-rw-r--r--libc/misc/pthread/tsd.c10
-rw-r--r--libc/misc/sysvipc/msgq.c53
-rw-r--r--libc/misc/utmp/utent.c13
-rw-r--r--libc/misc/utmp/wtent.c7
-rw-r--r--libc/signal/Makefile.in4
-rw-r--r--libc/signal/sigpause.c19
-rw-r--r--libc/signal/sigwait.c83
-rw-r--r--libc/stdio/_fopen.c4
-rw-r--r--libc/stdio/_scanf.c12
-rw-r--r--libc/stdio/_stdio.c22
-rw-r--r--libc/stdio/_stdio.h8
-rw-r--r--libc/stdio/fflush.c4
-rw-r--r--libc/stdio/tempnam.c2
-rw-r--r--libc/stdio/tmpfile.c6
-rw-r--r--libc/stdio/tmpnam.c2
-rw-r--r--libc/stdio/tmpnam_r.c2
-rw-r--r--libc/stdio/vdprintf.c2
-rw-r--r--libc/stdio/vsnprintf.c4
-rw-r--r--libc/stdlib/Makefile.in6
-rw-r--r--libc/stdlib/mkdtemp.c3
-rw-r--r--libc/stdlib/mkstemp.c3
-rw-r--r--libc/stdlib/mkstemp64.c3
-rw-r--r--libc/stdlib/mktemp.c2
-rw-r--r--libc/stdlib/system.c204
-rw-r--r--libc/string/Makefile.in5
-rw-r--r--libc/string/sh/memchr.S30
-rw-r--r--libc/string/sh/sh4/memmove.c117
-rw-r--r--libc/string/sh/sh4/memset.S146
-rw-r--r--libc/string/sh/sh4/strcpy.S28
-rw-r--r--libc/string/sh/sh4/strncpy.S43
-rw-r--r--libc/string/sh/strlen.S75
-rw-r--r--libc/sysdeps/linux/arm/Makefile.arch16
-rw-r--r--libc/sysdeps/linux/arm/clone.S23
-rw-r--r--libc/sysdeps/linux/arm/libc-aeabi_read_tp.S1
-rw-r--r--libc/sysdeps/linux/arm/libc-thumb_atomics.S1
-rw-r--r--libc/sysdeps/linux/arm/sysdep.h367
-rw-r--r--libc/sysdeps/linux/arm/vfork.S13
-rw-r--r--libc/sysdeps/linux/common/Makefile.in23
-rw-r--r--libc/sysdeps/linux/common/__rt_sigtimedwait.c100
-rw-r--r--libc/sysdeps/linux/common/__rt_sigwaitinfo.c102
-rw-r--r--libc/sysdeps/linux/common/__syscall_fcntl.c88
-rw-r--r--libc/sysdeps/linux/common/__syscall_rt_sigaction.c4
-rw-r--r--libc/sysdeps/linux/common/_exit.c10
-rw-r--r--libc/sysdeps/linux/common/bits/kernel_sigaction.h4
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_mutex.h68
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_stdio.h28
-rw-r--r--libc/sysdeps/linux/common/fsync.c27
-rw-r--r--libc/sysdeps/linux/common/ioctl.c30
-rw-r--r--libc/sysdeps/linux/common/libgcc_s.h2
-rw-r--r--libc/sysdeps/linux/common/msync.c29
-rw-r--r--libc/sysdeps/linux/common/nanosleep.c33
-rw-r--r--libc/sysdeps/linux/common/not-cancel.h60
-rw-r--r--libc/sysdeps/linux/common/open64.c19
-rw-r--r--libc/sysdeps/linux/common/pause.c31
-rw-r--r--libc/sysdeps/linux/common/poll.c48
-rw-r--r--libc/sysdeps/linux/common/pselect.c35
-rw-r--r--libc/sysdeps/linux/common/readv.c38
-rw-r--r--libc/sysdeps/linux/common/select.c57
-rw-r--r--libc/sysdeps/linux/common/sigprocmask.c65
-rw-r--r--libc/sysdeps/linux/common/sigsuspend.c34
-rw-r--r--libc/sysdeps/linux/common/sysdep.h20
-rw-r--r--libc/sysdeps/linux/common/wait.c34
-rw-r--r--libc/sysdeps/linux/common/waitpid.c29
-rw-r--r--libc/sysdeps/linux/common/writev.c36
-rw-r--r--libc/sysdeps/linux/i386/Makefile.arch13
-rw-r--r--libc/sysdeps/linux/i386/bits/syscalls.h2
-rw-r--r--libc/sysdeps/linux/i386/bits/uClibc_arch_features.h2
-rw-r--r--libc/sysdeps/linux/i386/clone.S8
-rw-r--r--libc/sysdeps/linux/i386/sysdep.h460
-rw-r--r--libc/sysdeps/linux/i386/vfork.S10
-rw-r--r--libc/sysdeps/linux/mips/Makefile.arch8
-rw-r--r--libc/sysdeps/linux/mips/clone.S1
-rw-r--r--libc/sysdeps/linux/mips/sys/asm.h16
-rw-r--r--libc/sysdeps/linux/mips/sys/regdef.h2
-rw-r--r--libc/sysdeps/linux/mips/syscall_error.S82
-rw-r--r--libc/sysdeps/linux/mips/sysdep.h391
-rw-r--r--libc/sysdeps/linux/mips/vfork.S97
-rw-r--r--libc/sysdeps/linux/sh/Makefile.arch4
-rw-r--r--libc/sysdeps/linux/sh/bits/atomic.h516
-rw-r--r--libc/sysdeps/linux/sh/clone.S135
-rw-r--r--libc/sysdeps/linux/sh/longjmp.c56
-rw-r--r--libc/sysdeps/linux/sh/pread_write.c50
-rw-r--r--libc/sysdeps/linux/sh/setjmp.S2
-rw-r--r--libc/sysdeps/linux/sh/syscall_error.S4
-rw-r--r--libc/sysdeps/linux/sh/sysdep.h25
-rw-r--r--libc/sysdeps/linux/sparc/Makefile.arch11
-rw-r--r--libc/sysdeps/linux/sparc/bits/atomic.h329
-rw-r--r--libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h2
-rw-r--r--libc/sysdeps/linux/sparc/clone.S99
-rw-r--r--libc/sysdeps/linux/sparc/sigaction.c9
-rw-r--r--libc/sysdeps/linux/sparc/sparcv9/clone.S102
-rw-r--r--libc/sysdeps/linux/sparc/sysdep.h69
-rw-r--r--libc/sysdeps/linux/x86_64/Makefile.arch12
-rw-r--r--libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h2
-rw-r--r--libc/sysdeps/linux/x86_64/clone.S4
-rw-r--r--libc/sysdeps/linux/x86_64/sysdep.h349
-rw-r--r--libc/sysdeps/linux/x86_64/vfork.S12
-rw-r--r--libc/termios/tcdrain.c27
-rw-r--r--libc/unistd/daemon.c51
-rw-r--r--libc/unistd/sysconf.c29
112 files changed, 4950 insertions, 864 deletions
diff --git a/libc/Makefile.in b/libc/Makefile.in
index 323c4e463..ff3e5c31d 100644
--- a/libc/Makefile.in
+++ b/libc/Makefile.in
@@ -16,7 +16,9 @@ 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
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..4a23ab061 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"
@@ -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..504aa254e 100644
--- a/libc/misc/pthread/Makefile.in
+++ b/libc/misc/pthread/Makefile.in
@@ -10,6 +10,7 @@ subdirs += libc/misc/pthread
MISC_PTHREAD_DIR := $(top_srcdir)libc/misc/pthread
MISC_PTHREAD_OUT := $(top_builddir)libc/misc/pthread
+libc-shared-$(UCLIBC_HAS_TLS) += $(MISC_PTHREAD_OUT)/tsd.os
libc-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/unlock.o
libc-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/weaks.o
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/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 336c0239b..a3f01b6e9 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);
@@ -34,16 +35,16 @@ static const char *static_ut_name = default_file_name;
static 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;
}
@@ -70,7 +71,7 @@ static 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)) {
ret = &static_utmp;
}
@@ -81,7 +82,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);
}
@@ -182,7 +183,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/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..554c6b9cb 100644
--- a/libc/sysdeps/linux/common/__rt_sigtimedwait.c
+++ b/libc/sysdeps/linux/common/__rt_sigtimedwait.c
@@ -2,44 +2,97 @@
/*
* __rt_sigtimedwait() for uClibc
*
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
*
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ * GNU Library General Public License (LGPL) version 2 or later.
*/
#include <sys/syscall.h>
#include <signal.h>
-#define __need_NULL
-#include <stddef.h>
+#include <string.h>
+libc_hidden_proto(memcpy)
#ifdef __NR_rt_sigtimedwait
-#define __NR___rt_sigtimedwait __NR_rt_sigtimedwait
-static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set, siginfo_t *, info,
- const struct timespec *, timeout, size_t, setsize)
+#include <string.h>
+libc_hidden_proto(memcpy)
-int sigwaitinfo(const sigset_t * set, siginfo_t * info)
+# ifdef __UCLIBC_HAS_THREADS_NATIVE__
+# include <sysdep-cancel.h>
+
+static int do_sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec *timeout)
{
- return __rt_sigtimedwait(set, info, NULL, _NSIG / 8);
+# ifdef SIGCANCEL
+ sigset_t tmpset;
+
+ if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+ || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+ ))
+ {
+ /* Create a temporary mask without the bit for SIGCANCEL set. */
+ // We are not copying more than we have to.
+ memcpy (&tmpset, set, _NSIG / 8);
+ __sigdelset (&tmpset, SIGCANCEL);
+# ifdef SIGSETXID
+ __sigdelset (&tmpset, SIGSETXID);
+# endif
+ set = &tmpset;
+ }
+# endif
+
+ /* XXX The size argument hopefully will have to be changed to the
+ real size of the user-level sigset_t. */
+ int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info,
+ timeout, _NSIG / 8);
+
+ /* The kernel generates a SI_TKILL code in si_code in case tkill is
+ used. tkill is transparently used in raise(). Since having
+ SI_TKILL as a code is useful in general we fold the results
+ here. */
+ if (result != -1 && info != NULL && info->si_code == SI_TKILL)
+ info->si_code = SI_USER;
+
+ return result;
}
-int sigtimedwait(const sigset_t * set, siginfo_t * info,
- const struct timespec *timeout)
+/* Return any pending signal or wait for one for the given time. */
+int __sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec *timeout)
{
- return __rt_sigtimedwait(set, info, timeout, _NSIG / 8);
+ if(SINGLE_THREAD_P)
+ return do_sigtimedwait(set, info, timeout);
+
+ int oldtype = LIBC_CANCEL_ASYNC();
+
+ /* XXX The size argument hopefully will have to be changed to the
+ real size of the user-level sigset_t. */
+ int result = do_sigtimedwait(set, info, timeout);
+
+ LIBC_CANCEL_RESET(oldtype);
+
+ return result;
}
-#else
-int sigwaitinfo(const sigset_t * set, siginfo_t * info)
+# else
+# define __need_NULL
+# include <stddef.h>
+# define __NR___rt_sigtimedwait __NR_rt_sigtimedwait
+static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set,
+ siginfo_t *, info, const struct timespec *, timeout,
+ size_t, setsize);
+
+int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info,
+ const struct timespec *timeout)
{
- if (set == NULL)
- __set_errno(EINVAL);
- else
- __set_errno(ENOSYS);
- return -1;
+ return __rt_sigtimedwait(set, info, timeout, _NSIG / 8);
}
-
-int sigtimedwait(const sigset_t * set, siginfo_t * info,
- const struct timespec *timeout)
+# endif /* !__UCLIBC_HAS_THREADS_NATIVE__ */
+#else
+int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info,
+ const struct timespec *timeout)
{
if (set == NULL)
__set_errno(EINVAL);
@@ -48,5 +101,4 @@ int sigtimedwait(const sigset_t * set, siginfo_t * info,
return -1;
}
#endif
-libc_hidden_def(sigwaitinfo)
-libc_hidden_def(sigtimedwait)
+weak_alias(__sigtimedwait,sigtimedwait)
diff --git a/libc/sysdeps/linux/common/__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..c6094c3d2 100644
--- a/libc/sysdeps/linux/common/bits/uClibc_mutex.h
+++ b/libc/sysdeps/linux/common/bits/uClibc_mutex.h
@@ -62,7 +62,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 +131,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_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..4211c26cc 100644
--- a/libc/sysdeps/linux/common/poll.c
+++ b/libc/sysdeps/linux/common/poll.c
@@ -21,30 +21,35 @@
#include <sys/poll.h>
#include <bits/kernel-features.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
+
#if defined __ASSUME_POLL_SYSCALL && defined __NR_poll
-_syscall3(int, poll, struct pollfd *, fds,
- unsigned long int, nfds, int, timeout)
+libc_hidden_proto(poll)
-#elif defined(__NR_ppoll) && defined __UCLIBC_LINUX_SPECIFIC__
+#ifdef __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 +59,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 +229,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 23d872a29..f9ea54ac7 100644
--- a/libc/sysdeps/linux/i386/bits/syscalls.h
+++ b/libc/sysdeps/linux/i386/bits/syscalls.h
@@ -102,7 +102,7 @@ __asm__ (".L__X'%ebx = 1\n\t"
"int $0x80\n\t" \
RESTOREARGS_##nr \
: "=a" (resultvar) \
- : "i" (name) ASMFMT_##nr(args) : "memory", "cc"); \
+ : "g" (name) ASMFMT_##nr(args) : "memory", "cc"); \
(int) resultvar; })
#define LOADARGS_0
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/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/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)