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.in35
-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.c201
-rw-r--r--libc/string/Makefile.in5
-rw-r--r--libc/string/sh/memchr.S30
-rw-r--r--libc/string/sh/sh4/memcpy.S11
-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/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-features.h387
-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/msync.c29
-rw-r--r--libc/sysdeps/linux/common/nanosleep.c33
-rw-r--r--libc/sysdeps/linux/common/not-cancel.h19
-rw-r--r--libc/sysdeps/linux/common/open64.c19
-rw-r--r--libc/sysdeps/linux/common/pause.c30
-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/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/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.h54
-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/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/sparcv9/clone.S102
-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.S1
-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.c26
106 files changed, 3667 insertions, 885 deletions
diff --git a/libc/Makefile.in b/libc/Makefile.in
index 7297e9284..c4cf5d7c7 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 19acbe0d6..c5feedeba 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();
@@ -183,17 +194,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
@@ -268,6 +282,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
@@ -387,34 +406,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 ceea1c21b..48e816236 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_THREADS) += $(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 9e234b4ce..a29f69723 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:=$(filter-out raise.c sigaction.c,$(CSRC))
+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 3d34538fb..4fd095e58 100644
--- a/libc/stdlib/Makefile.in
+++ b/libc/stdlib/Makefile.in
@@ -13,19 +13,32 @@ 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 \
valloc.c a64l.c l64a.c __uc_malloc.c
-CSRC-$(UCLIBC_HAS_ADVANCED_REALTIME) += posix_memalign.c
-CSRC-$(UCLIBC_HAS_PTY) += grantpt.c unlockpt.c ptsname.c
-CSRC-$(UCLIBC_HAS_ARC4RANDOM) += arc4random.c
-CSRC-$(UCLIBC_HAS_LFS) += mkstemp64.c
-CSRC-$(UCLIBC_HAS_FLOATS) += drand48.c drand48_r.c erand48.c erand48_r.c
-CSRC-$(if $(findstring yy,$(UCLIBC_HAS_FLOATS)$(UCLIBC_SUSV3_LEGACY)),y) += \
- gcvt.c
-CSRC-$(UCLIBC_SUSV3_LEGACY) += mktemp.c
+ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y)
+CSRC += posix_memalign.c
+endif
+ifeq ($(UCLIBC_HAS_PTY),y)
+CSRC += grantpt.c unlockpt.c ptsname.c
+endif
+ifeq ($(UCLIBC_HAS_ARC4RANDOM),y)
+CSRC += arc4random.c
+endif
+ifeq ($(UCLIBC_HAS_LFS),y)
+CSRC += mkstemp64.c
+endif
+ifeq ($(UCLIBC_HAS_FLOATS),y)
+CSRC += drand48.c drand48_r.c erand48.c erand48_r.c
+ifeq ($(UCLIBC_SUSV3_LEGACY),y)
+CSRC += gcvt.c
+endif
+endif
+ifeq ($(UCLIBC_SUSV3_LEGACY),y)
+CSRC += mktemp.c
+endif
# multi source stdlib.c
CSRC-y += abs.c labs.c atoi.c atol.c strtol.c strtoul.c _stdlib_strto_l.c \
@@ -65,7 +78,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..7026a8d20 100644
--- a/libc/stdlib/system.c
+++ b/libc/stdlib/system.c
@@ -10,8 +10,15 @@
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sched.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
+#include <sysdep-cancel.h>
+#endif
+#if !defined __UCLIBC_HAS_THREADS_NATIVE__
/* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
#include <sys/syscall.h>
#ifndef __NR_vfork
@@ -61,4 +68,198 @@ int __libc_system(const char *command)
signal(SIGCHLD, save_chld);
return wait_val;
}
+#else
+/* We have to and actually can handle cancelable system(). The big
+ problem: we have to kill the child process if necessary. To do
+ this a cleanup handler has to be registered and is has to be able
+ to find the PID of the child. The main problem is to reliable have
+ the PID when needed. It is not necessary for the parent thread to
+ return. It might still be in the kernel when the cancellation
+ request comes. Therefore we have to use the clone() calls ability
+ to have the kernel write the PID into the user-level variable. */
+
+libc_hidden_proto(sigaction)
+libc_hidden_proto(waitpid)
+
+#if defined __ia64__
+# define FORK() \
+ INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
+ &pid, NULL, NULL)
+#elif defined __sparc__
+# define FORK() \
+ INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
+#elif defined __s390__
+# define FORK() \
+ INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid)
+#else
+# define FORK() \
+ INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
+#endif
+
+static void cancel_handler (void *arg);
+
+# define CLEANUP_HANDLER \
+ __libc_cleanup_region_start (1, cancel_handler, &pid)
+
+# define CLEANUP_RESET \
+ __libc_cleanup_region_end (0)
+
+static struct sigaction intr, quit;
+static int sa_refcntr;
+__libc_lock_define_initialized (static, lock);
+
+# define DO_LOCK() __libc_lock_lock (lock)
+# define DO_UNLOCK() __libc_lock_unlock (lock)
+# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
+# define ADD_REF() sa_refcntr++
+# define SUB_REF() --sa_refcntr
+
+/* Execute LINE as a shell command, returning its status. */
+static int
+do_system (const char *line)
+{
+ int status, save;
+ pid_t pid;
+ struct sigaction sa;
+ sigset_t omask;
+
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ __sigemptyset (&sa.sa_mask);
+
+ DO_LOCK ();
+ if (ADD_REF () == 0)
+ {
+ if (sigaction (SIGINT, &sa, &intr) < 0)
+ {
+ SUB_REF ();
+ goto out;
+ }
+ if (sigaction (SIGQUIT, &sa, &quit) < 0)
+ {
+ save = errno;
+ SUB_REF ();
+ goto out_restore_sigint;
+ }
+ }
+ DO_UNLOCK ();
+
+ /* We reuse the bitmap in the 'sa' structure. */
+ __sigaddset (&sa.sa_mask, SIGCHLD);
+ save = errno;
+ if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
+ {
+ {
+ DO_LOCK ();
+ if (SUB_REF () == 0)
+ {
+ save = errno;
+ (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+ out_restore_sigint:
+ (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+ __set_errno (save);
+ }
+ out:
+ DO_UNLOCK ();
+ return -1;
+ }
+ }
+
+ CLEANUP_HANDLER;
+
+ pid = FORK ();
+ if (pid == (pid_t) 0)
+ {
+ /* Child side. */
+ const char *new_argv[4];
+ new_argv[0] = "/bin/sh";
+ new_argv[1] = "-c";
+ new_argv[2] = line;
+ new_argv[3] = NULL;
+
+ /* Restore the signals. */
+ (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+ (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+ (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
+ INIT_LOCK ();
+
+ /* Exec the shell. */
+ (void) execve ("/bin/sh", (char *const *) new_argv, __environ);
+ _exit (127);
+ }
+ else if (pid < (pid_t) 0)
+ /* The fork failed. */
+ status = -1;
+ else
+ /* Parent side. */
+ {
+ /* Note the system() is a cancellation point. But since we call
+ waitpid() which itself is a cancellation point we do not
+ have to do anything here. */
+ if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+ status = -1;
+ }
+
+ CLEANUP_RESET;
+
+ save = errno;
+ DO_LOCK ();
+ if ((SUB_REF () == 0
+ && (sigaction (SIGINT, &intr, (struct sigaction *) NULL)
+ | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
+ || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
+ {
+ status = -1;
+ }
+ DO_UNLOCK ();
+
+ return status;
+}
+
+
+int
+__libc_system (const char *line)
+{
+ if (line == NULL)
+ /* Check that we have a command processor available. It might
+ not be available after a chroot(), for example. */
+ return do_system ("exit 0") == 0;
+
+ if (SINGLE_THREAD_P)
+ return do_system (line);
+
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+ int result = do_system (line);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+}
+
+
+/* The cancellation handler. */
+static void
+cancel_handler (void *arg)
+{
+ pid_t child = *(pid_t *) arg;
+
+ INTERNAL_SYSCALL_DECL (err);
+ INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
+
+ TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
+
+ DO_LOCK ();
+
+ if (SUB_REF () == 0)
+ {
+ (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+ (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+ }
+
+ DO_UNLOCK ();
+}
+#endif
+#ifdef IS_IN_libc
weak_alias(__libc_system,system)
+#endif
diff --git a/libc/string/Makefile.in b/libc/string/Makefile.in
index 08a1856b7..67679ece7 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/memcpy.S b/libc/string/sh/sh4/memcpy.S
index c03c18c73..efdaf8bba 100644
--- a/libc/string/sh/sh4/memcpy.S
+++ b/libc/string/sh/sh4/memcpy.S
@@ -18,6 +18,7 @@
* If there is an overlap, then the results are undefined.
*/
+#include <sysdep.h>
#include <endian.h>
#ifdef __LITTLE_ENDIAN__
@@ -176,12 +177,7 @@
9: rts
nop
-/* void * memcpy(void *dst, const void *src, size_t len) */
-.text
-.align 4
-.type memcpy,@function
-.globl memcpy;
-memcpy:
+ENTRY(memcpy)
! Calculate the invariants which will be used in the remainder
! of the code:
@@ -908,6 +904,5 @@ memcpy:
rts
mov.b r1,@-r0
-.size memcpy,.-memcpy;
-
+END(memcpy)
libc_hidden_def (memcpy)
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/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 ec889ca0d..45c70baf6 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)
+#do nothing
+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-features.h b/libc/sysdeps/linux/common/bits/kernel-features.h
index 88297349a..923341b35 100644
--- a/libc/sysdeps/linux/common/bits/kernel-features.h
+++ b/libc/sysdeps/linux/common/bits/kernel-features.h
@@ -26,23 +26,126 @@
#endif
#include <linux/version.h>
-#define __LINUX_KERNEL_VERSION LINUX_VERSION_CODE
+#define __LINUX_KERNEL_VERSION LINUX_VERSION_CODE
+
+/* We assume for __LINUX_KERNEL_VERSION the same encoding used in
+ linux/version.h. I.e., the major, minor, and subminor all get a
+ byte with the major number being in the highest byte. This means
+ we can do numeric comparisons.
+
+ In the following we will define certain symbols depending on
+ whether the describes kernel feature is available in the kernel
+ version given by __LINUX_KERNEL_VERSION. We are not always exactly
+ recording the correct versions in which the features were
+ introduced. If somebody cares these values can afterwards be
+ corrected. Most of the numbers here are set corresponding to
+ 2.2.0. */
+
+/* `getcwd' system call. */
+#if __LINUX_KERNEL_VERSION >= 131584
+# define __ASSUME_GETCWD_SYSCALL 1
+#endif
/* Real-time signal became usable in 2.1.70. */
#if __LINUX_KERNEL_VERSION >= 131398
# define __ASSUME_REALTIME_SIGNALS 1
#endif
-/* Beginning with 2.5.63 support for realtime and monotonic clocks and
- timers based on them is available. */
-#if __LINUX_KERNEL_VERSION >= 132415
-# define __ASSUME_POSIX_TIMERS 1
+/* When were the `pread'/`pwrite' syscalls introduced? */
+#if __LINUX_KERNEL_VERSION >= 131584
+# define __ASSUME_PREAD_SYSCALL 1
+# define __ASSUME_PWRITE_SYSCALL 1
#endif
-/* On x86, the set_thread_area syscall was introduced in 2.5.29, but its
- semantics was changed in 2.5.30, and again after 2.5.31. */
-#if __LINUX_KERNEL_VERSION >= 132384 && defined __i386__
-# define __ASSUME_SET_THREAD_AREA_SYSCALL 1
+/* When was `poll' introduced? */
+#if __LINUX_KERNEL_VERSION >= 131584
+# define __ASSUME_POLL_SYSCALL 1
+#endif
+
+/* The `lchown' syscall was introduced in 2.1.80. */
+#if __LINUX_KERNEL_VERSION >= 131408
+# define __ASSUME_LCHOWN_SYSCALL 1
+#endif
+
+/* When did the `setresuid' sysall became available? */
+#if __LINUX_KERNEL_VERSION >= 131584 && !defined __sparc__
+# define __ASSUME_SETRESUID_SYSCALL 1
+#endif
+
+/* The SIOCGIFNAME ioctl is available starting with 2.1.50. */
+#if __LINUX_KERNEL_VERSION >= 131408
+# define __ASSUME_SIOCGIFNAME 1
+#endif
+
+/* MSG_NOSIGNAL was at least available with Linux 2.2.0. */
+#if __LINUX_KERNEL_VERSION >= 131584
+# define __ASSUME_MSG_NOSIGNAL 1
+#endif
+
+/* On x86 another `getrlimit' syscall was added in 2.3.25. */
+#if __LINUX_KERNEL_VERSION >= 131865 && defined __i386__
+# define __ASSUME_NEW_GETRLIMIT_SYSCALL 1
+#endif
+
+/* On x86 the truncate64/ftruncate64 syscalls were introduced in 2.3.31. */
+#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__
+# define __ASSUME_TRUNCATE64_SYSCALL 1
+#endif
+
+/* On x86 the mmap2 syscall was introduced in 2.3.31. */
+#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__
+# define __ASSUME_MMAP2_SYSCALL 1
+#endif
+
+/* On x86 the stat64/lstat64/fstat64 syscalls were introduced in 2.3.34. */
+#if __LINUX_KERNEL_VERSION >= 131874 && defined __i386__
+# define __ASSUME_STAT64_SYSCALL 1
+#endif
+
+/* On sparc and ARM the truncate64/ftruncate64/mmap2/stat64/lstat64/fstat64
+ syscalls were introduced in 2.3.35. */
+#if __LINUX_KERNEL_VERSION >= 131875 && (defined __sparc__ || defined __arm__)
+# define __ASSUME_TRUNCATE64_SYSCALL 1
+# define __ASSUME_MMAP2_SYSCALL 1
+# define __ASSUME_STAT64_SYSCALL 1
+#endif
+
+/* I know for sure that getrlimit are in 2.3.35 on powerpc. */
+#if __LINUX_KERNEL_VERSION >= 131875 && defined __powerpc__
+# define __ASSUME_NEW_GETRLIMIT_SYSCALL 1
+#endif
+
+/* I know for sure that these are in 2.3.35 on powerpc. But PowerPC64 does not
+ support separate 64-bit syscalls, already 64-bit */
+#if __LINUX_KERNEL_VERSION >= 131875 && defined __powerpc__ \
+ && !defined __powerpc64__
+# define __ASSUME_TRUNCATE64_SYSCALL 1
+# define __ASSUME_STAT64_SYSCALL 1
+#endif
+
+/* Linux 2.3.39 introduced 32bit UID/GIDs. Some platforms had 32
+ bit type all along. */
+#if __LINUX_KERNEL_VERSION >= 131879 || defined __powerpc__ || defined __mips__
+# define __ASSUME_32BITUIDS 1
+#endif
+
+/* Linux 2.3.39 sparc added setresuid. */
+#if __LINUX_KERNEL_VERSION >= 131879 && defined __sparc__
+# define __ASSUME_SETRESUID_SYSCALL 1
+#endif
+
+#if __LINUX_KERNEL_VERSION >= 131879
+# define __ASSUME_SETRESGID_SYSCALL 1
+#endif
+
+/* Linux 2.3.39 introduced IPC64. Except for powerpc. */
+#if __LINUX_KERNEL_VERSION >= 131879 && !defined __powerpc__
+# define __ASSUME_IPC64 1
+#endif
+
+/* MIPS platforms had IPC64 all along. */
+#if defined __mips__
+# define __ASSUME_IPC64 1
#endif
/* We can use the LDTs for threading with Linux 2.3.99 and newer. */
@@ -50,6 +153,74 @@
# define __ASSUME_LDT_WORKS 1
#endif
+/* Linux 2.4.0 on PPC introduced a correct IPC64. But PowerPC64 does not
+ support a separate 64-bit sys call, already 64-bit */
+#if __LINUX_KERNEL_VERSION >= 132096 && defined __powerpc__ \
+ && !defined __powerpc64__
+# define __ASSUME_IPC64 1
+#endif
+
+/* SH kernels got stat64, mmap2, and truncate64 during 2.4.0-test. */
+#if __LINUX_KERNEL_VERSION >= 132096 && defined __sh__
+# define __ASSUME_TRUNCATE64_SYSCALL 1
+# define __ASSUME_MMAP2_SYSCALL 1
+# define __ASSUME_STAT64_SYSCALL 1
+#endif
+
+/* The changed st_ino field appeared in 2.4.0-test6. But we cannot
+ distinguish this version from other 2.4.0 releases. Therefore play
+ save and assume it available is for 2.4.1 and up. However, SH is lame,
+ and still does not have a 64-bit inode field. */
+#if __LINUX_KERNEL_VERSION >= 132097 && !defined __alpha__ && !defined __sh__
+# define __ASSUME_ST_INO_64_BIT 1
+#endif
+
+/* To support locking of large files a new fcntl() syscall was introduced
+ in 2.4.0-test7. We test for 2.4.1 for the earliest version we know
+ the syscall is available. */
+#if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __sparc__)
+# define __ASSUME_FCNTL64 1
+#endif
+
+/* The AT_CLKTCK auxiliary vector entry was introduction in the 2.4.0
+ series. */
+#if __LINUX_KERNEL_VERSION >= 132097
+# define __ASSUME_AT_CLKTCK 1
+#endif
+
+/* Arm got fcntl64 in 2.4.4, PowerPC and SH have it also in 2.4.4 (I
+ don't know when it got introduced). But PowerPC64 does not support
+ separate FCNTL64 call, FCNTL is already 64-bit */
+#if __LINUX_KERNEL_VERSION >= 132100 \
+ && (defined __arm__ || defined __powerpc__ || defined __sh__) \
+ && !defined __powerpc64__
+# define __ASSUME_FCNTL64 1
+#endif
+
+/* The getdents64 syscall was introduced in 2.4.0-test7. We test for
+ 2.4.1 for the earliest version we know the syscall is available. */
+#if __LINUX_KERNEL_VERSION >= 132097
+# define __ASSUME_GETDENTS64_SYSCALL 1
+#endif
+
+/* When did O_DIRECTORY became available? Early in 2.3 but when?
+ Be safe, use 2.3.99. */
+#if __LINUX_KERNEL_VERSION >= 131939
+# define __ASSUME_O_DIRECTORY 1
+#endif
+
+/* Starting with one of the 2.4.0 pre-releases the Linux kernel passes
+ up the page size information. */
+#if __LINUX_KERNEL_VERSION >= 132097
+# define __ASSUME_AT_PAGESIZE 1
+#endif
+
+/* Starting with at least 2.4.0 the kernel passes the uid/gid unconditionally
+ up to the child. */
+#if __LINUX_KERNEL_VERSION >= 132097
+# define __ASSUME_AT_XID 1
+#endif
+
/* Starting with 2.4.5 kernels PPC passes the AUXV in the standard way
and the vfork syscall made it into the official kernel. */
#if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__
@@ -57,17 +228,72 @@
# define __ASSUME_VFORK_SYSCALL 1
#endif
+/* Starting with 2.4.5 kernels the mmap2 syscall made it into the official
+ kernel. But PowerPC64 does not support a separate MMAP2 call. */
+#if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__ \
+ && !defined __powerpc64__
+# define __ASSUME_MMAP2_SYSCALL 1
+#endif
+
+/* Starting with 2.4.21 PowerPC implements the new prctl syscall.
+ This allows applications to get/set the Floating Point Exception Mode. */
+#if __LINUX_KERNEL_VERSION >= (132096+21) && defined __powerpc__
+# define __ASSUME_NEW_PRCTL_SYSCALL 1
+#endif
+
+/* Starting with 2.4.21 the PowerPC32 clone syscall works as expected. */
+#if __LINUX_KERNEL_VERSION >= (132096+21) && defined __powerpc__ \
+ && !defined __powerpc64__
+# define __ASSUME_FIXED_CLONE_SYSCALL 1
+#endif
+
+/* Starting with 2.4.21 PowerPC64 implements the new rt_sigreturn syscall.
+ The new rt_sigreturn takes an ucontext pointer allowing rt_sigreturn
+ to be used in the set/swapcontext implementation. */
+#if __LINUX_KERNEL_VERSION >= (132096+21) && defined __powerpc64__
+# define __ASSUME_NEW_RT_SIGRETURN_SYSCALL 1
+#endif
+
+/* On x86, the set_thread_area syscall was introduced in 2.5.29, but its
+ semantics was changed in 2.5.30, and again after 2.5.31. */
+#if __LINUX_KERNEL_VERSION >= 132384 && defined __i386__
+# define __ASSUME_SET_THREAD_AREA_SYSCALL 1
+#endif
+
/* The vfork syscall on x86 and arm was definitely available in 2.4. */
#if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __arm__)
# define __ASSUME_VFORK_SYSCALL 1
#endif
-/* Starting with version 2.6.4-rc1 the getdents syscall returns d_type
- * information as well and in between 2.6.5 and 2.6.8 most compat wrappers
- * were fixed too. Except s390{,x} which was fixed in 2.6.11. */
-#if (__LINUX_KERNEL_VERSION >= 0x020608 && !defined __s390__) \
- || (__LINUX_KERNEL_VERSION >= 0x02060b && defined __s390__)
-# define __ASSUME_GETDENTS32_D_TYPE 1
+/* There are an infinite number of PA-RISC kernel versions numbered
+ 2.4.0. But they've not really been released as such. We require
+ and expect the final version here. */
+#ifdef __hppa__
+# define __ASSUME_32BITUIDS 1
+# define __ASSUME_TRUNCATE64_SYSCALL 1
+# define __ASSUME_MMAP2_SYSCALL 1
+# define __ASSUME_STAT64_SYSCALL 1
+# define __ASSUME_IPC64 1
+# define __ASSUME_ST_INO_64_BIT 1
+# define __ASSUME_FCNTL64 1
+# define __ASSUME_GETDENTS64_SYSCALL 1
+#endif
+
+/* Alpha switched to a 64-bit timeval sometime before 2.2.0. */
+#if __LINUX_KERNEL_VERSION >= 131584 && defined __alpha__
+# define __ASSUME_TIMEVAL64 1
+#endif
+
+#if defined __mips__ && _MIPS_SIM == _ABIN32
+# define __ASSUME_FCNTL64 1
+#endif
+
+/* The late 2.5 kernels saw a lot of new CLONE_* flags. Summarize
+ their availability with one define. The changes were made first
+ for i386 and the have to be done separately for the other archs.
+ For i386 we pick 2.5.50 as the first version with support. */
+#if __LINUX_KERNEL_VERSION >= 132402 && defined __i386__
+# define __ASSUME_CLONE_THREAD_FLAGS 1
#endif
/* Support for various CLOEXEC and NONBLOCK flags was added for x86,
@@ -87,6 +313,137 @@
# define __ASSUME_VFORK_SYSCALL 1
#endif
+/* Beginning with 2.5.63 support for realtime and monotonic clocks and
+ timers based on them is available. */
+#if __LINUX_KERNEL_VERSION >= 132415
+# define __ASSUME_POSIX_TIMERS 1
+#endif
+
+/* The late 2.5 kernels saw a lot of new CLONE_* flags. Summarize
+ their availability with one define. The changes were made first
+ for i386 and the have to be done separately for the other archs.
+ For ia64, s390*, PPC, x86-64 we pick 2.5.64 as the first version
+ with support. */
+#if __LINUX_KERNEL_VERSION >= 132416 \
+ && (defined __ia64__ || defined __s390__ || defined __powerpc__ \
+ || defined __x86_64__ || defined __sh__)
+# define __ASSUME_CLONE_THREAD_FLAGS 1
+#endif
+
+/* With kernel 2.4.17 we always have netlink support. */
+#if __LINUX_KERNEL_VERSION >= (132096+17)
+# define __ASSUME_NETLINK_SUPPORT 1
+#endif
+
+/* The requeue futex functionality was introduced in 2.5.70. */
+#if __LINUX_KERNEL_VERSION >= 132422
+# define __ASSUME_FUTEX_REQUEUE 1
+#endif
+
+/* The statfs64 syscalls are available in 2.5.74. */
+#if __LINUX_KERNEL_VERSION >= 132426
+# define __ASSUME_STATFS64 1
+#endif
+
+/* Starting with at least 2.5.74 the kernel passes the setuid-like exec
+ flag unconditionally up to the child. */
+#if __LINUX_KERNEL_VERSION >= 132426
+# define __ASSUME_AT_SECURE 1
+#endif
+
+/* Starting with the 2.5.75 kernel the kernel fills in the correct value
+ in the si_pid field passed as part of the siginfo_t struct to signal
+ handlers. */
+#if __LINUX_KERNEL_VERSION >= 132427
+# define __ASSUME_CORRECT_SI_PID 1
+#endif
+
+/* The tgkill syscall was instroduced for i386 in 2.5.75. For Alpha
+ it was introduced in 2.6.0-test1 which unfortunately cannot be
+ distinguished from 2.6.0. On x86-64, ppc, and ppc64 it was
+ introduced in 2.6.0-test3. */
+#if (__LINUX_KERNEL_VERSION >= 132427 && defined __i386__) \
+ || (__LINUX_KERNEL_VERSION >= 132609 && defined __alpha__) \
+ || (__LINUX_KERNEL_VERSION >= 132609 && defined __x86_64__) \
+ || (__LINUX_KERNEL_VERSION >= 132609 && defined __powerpc__) \
+ || (__LINUX_KERNEL_VERSION >= 132609 && defined __sh__)
+# define __ASSUME_TGKILL 1
+#endif
+
+/* The utimes syscall has been available for some architectures
+ forever. For x86 it was introduced after 2.5.75, for x86-64,
+ ppc, and ppc64 it was introduced in 2.6.0-test3. */
+#if defined __alpha__ || defined __ia64__ || defined __hppa__ \
+ || defined __sparc__ \
+ || (__LINUX_KERNEL_VERSION > 132427 && defined __i386__) \
+ || (__LINUX_KERNEL_VERSION > 132609 && defined __x86_64__) \
+ || (__LINUX_KERNEL_VERSION >= 132609 && defined __powerpc__) \
+ || (__LINUX_KERNEL_VERSION >= 132609 && defined __sh__)
+# define __ASSUME_UTIMES 1
+#endif
+
+// XXX Disabled for now since the semantics we want is not achieved.
+#if 0
+/* The CLONE_STOPPED flag was introduced in the 2.6.0-test1 series. */
+#if __LINUX_KERNEL_VERSION >= 132609
+# define __ASSUME_CLONE_STOPPED 1
+#endif
+#endif
+
+/* The fixed version of the posix_fadvise64 syscall appeared in
+ 2.6.0-test3. At least for x86. Powerpc support appeared in
+ 2.6.2, but for 32-bit userspace only. */
+#if (__LINUX_KERNEL_VERSION >= 132609 && defined __i386__) \
+ || (__LINUX_KERNEL_VERSION >= 132610 && defined __powerpc__ \
+ && !defined __powerpc64__)
+# define __ASSUME_FADVISE64_64_SYSCALL 1
+#endif
+
+/* The PROT_GROWSDOWN/PROT_GROWSUP flags were introduced in the 2.6.0-test
+ series. */
+#if __LINUX_KERNEL_VERSION >= 132609
+# define __ASSUME_PROT_GROWSUPDOWN 1
+#endif
+
+/* Starting with 2.6.0 PowerPC adds signal/swapcontext support for Vector
+ SIMD (AKA Altivec, VMX) instructions and register state. This changes
+ the overall size of the sigcontext and adds the swapcontext syscall. */
+#if __LINUX_KERNEL_VERSION >= 132608 && defined __powerpc__
+# define __ASSUME_SWAPCONTEXT_SYSCALL 1
+#endif
+
+/* The CLONE_DETACHED flag is not necessary in 2.6.2 kernels, it is
+ implied. */
+#if __LINUX_KERNEL_VERSION >= 132610
+# define __ASSUME_NO_CLONE_DETACHED 1
+#endif
+
+/* Starting with version 2.6.4-rc1 the getdents syscall returns d_type
+ information as well and in between 2.6.5 and 2.6.8 most compat wrappers
+ were fixed too. Except s390{,x} which was fixed in 2.6.11. */
+#if (__LINUX_KERNEL_VERSION >= 0x020608 && !defined __s390__) \
+ || (__LINUX_KERNEL_VERSION >= 0x02060b && defined __s390__)
+# define __ASSUME_GETDENTS32_D_TYPE 1
+#endif
+
+/* Starting with version 2.5.3, the initial location returned by `brk'
+ after exec is always rounded up to the next page. */
+#if __LINUX_KERNEL_VERSION >= 132355
+# define __ASSUME_BRK_PAGE_ROUNDED 1
+#endif
+
+/* Starting with version 2.6.9, the waitid system call is available.
+ Except for powerpc and powerpc64, where it is available in 2.6.12. */
+#if (__LINUX_KERNEL_VERSION >= 0x020609 && !defined __powerpc__) \
+ || (__LINUX_KERNEL_VERSION >= 0x02060c && defined __powerpc__)
+# define __ASSUME_WAITID_SYSCALL 1
+#endif
+
+/* Starting with version 2.6.9, SSI_IEEE_RAISE_EXCEPTION exists. */
+#if __LINUX_KERNEL_VERSION >= 0x020609 && defined __alpha__
+#define __ASSUME_IEEE_RAISE_EXCEPTION 1
+#endif
+
/* This header was added somewhere around 2.6.13 */
#if __LINUX_KERNEL_VERSION >= 132621
# define HAVE_LINUX_CPUMASK_H 1
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/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..ebdc6078d
--- /dev/null
+++ b/libc/sysdeps/linux/common/not-cancel.h
@@ -0,0 +1,19 @@
+/* By default we have none. Map the name to the normal functions. */
+#define open_not_cancel(name, flags, mode) \
+ open (name, flags, mode)
+#define open_not_cancel_2(name, flags) \
+ open (name, flags)
+#define close_not_cancel(fd) \
+ close (fd)
+#define close_not_cancel_no_status(fd) \
+ (void) close (fd)
+#define read_not_cancel(fd, buf, n) \
+ read (fd, buf, n)
+#define write_not_cancel(fd, buf, n) \
+ write (fd, buf, n)
+#define writev_not_cancel_no_status(fd, iov, n) \
+ (void) writev (fd, iov, n)
+#define fcntl_not_cancel(fd, cmd, val) \
+ fcntl (fd, cmd, val)
+# define waitpid_not_cancel(pid, stat_loc, options) \
+ waitpid (pid, stat_loc, options)
diff --git a/libc/sysdeps/linux/common/open64.c b/libc/sysdeps/linux/common/open64.c
index cfe471c64..c1f5400b8 100644
--- a/libc/sysdeps/linux/common/open64.c
+++ b/libc/sysdeps/linux/common/open64.c
@@ -7,6 +7,10 @@
#include <features.h>
#include <fcntl.h>
#include <stdarg.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+#endif
#ifdef __UCLIBC_HAS_LFS__
@@ -28,7 +32,20 @@ int open64 (const char *file, int oflag, ...)
va_end (arg);
}
- return open(file, oflag | O_LARGEFILE, mode);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+ if (SINGLE_THREAD_P)
+ return INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode);
+
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+ int result = INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+#else
+ return open(file, oflag | O_LARGEFILE, mode);
+#endif
}
#ifndef __LINUXTHREADS_OLD__
libc_hidden_def(open64)
diff --git a/libc/sysdeps/linux/common/pause.c b/libc/sysdeps/linux/common/pause.c
index 19ba30706..cd0ea4a77 100644
--- a/libc/sysdeps/linux/common/pause.c
+++ b/libc/sysdeps/linux/common/pause.c
@@ -10,18 +10,30 @@
#define __UCLIBC_HIDE_DEPRECATED__
#include <sys/syscall.h>
#include <unistd.h>
-#include <signal.h>
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(pause) weak_function pause;
-strong_alias(pause, __libc_pause)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
#endif
-#ifdef __NR_pause
-_syscall0(int, pause)
-#else
-int pause(void)
+#include <signal.h>
+
+/* Suspend the process until a signal arrives.
+ This always returns -1 and sets errno to EINTR. */
+int
+__libc_pause (void)
{
- return __sigpause(sigblock(0), 0);
+ sigset_t set;
+
+ __sigemptyset (&set);
+ sigprocmask (SIG_BLOCK, NULL, &set);
+
+ /* pause is a cancellation point, but so is sigsuspend.
+ So no need for anything special here. */
+
+ return sigsuspend (&set);
}
+weak_alias (__libc_pause, pause)
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+LIBC_CANCEL_HANDLED (); /* sigsuspend handles our cancellation. */
#endif
diff --git a/libc/sysdeps/linux/common/poll.c b/libc/sysdeps/linux/common/poll.c
index 4a6f06e19..f50e92c8e 100644
--- a/libc/sysdeps/linux/common/poll.c
+++ b/libc/sysdeps/linux/common/poll.c
@@ -20,30 +20,33 @@
#include <sys/syscall.h>
#include <sys/poll.h>
-#ifdef __NR_poll
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
-_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>
@@ -53,6 +56,9 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout)
#include <sys/param.h>
#include <unistd.h>
+libc_hidden_proto(getdtablesize)
+libc_hidden_proto(select)
+
/* uClinux 2.0 doesn't have poll, emulate it using select */
/* Poll the file descriptors described by the NFDS structures starting at
@@ -220,10 +226,4 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout)
}
#endif
-
-#ifndef __LINUXTHREADS_OLD__
libc_hidden_def(poll)
-#else
-libc_hidden_weak(poll)
-strong_alias(poll,__libc_poll)
-#endif
diff --git a/libc/sysdeps/linux/common/pselect.c b/libc/sysdeps/linux/common/pselect.c
index 63ab0dbb1..7e93537dd 100644
--- a/libc/sysdeps/linux/common/pselect.c
+++ b/libc/sysdeps/linux/common/pselect.c
@@ -22,9 +22,12 @@
#include <stddef.h> /* For NULL. */
#include <sys/time.h>
#include <sys/select.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#endif
-extern __typeof(pselect) __libc_pselect;
-
+libc_hidden_proto(sigprocmask)
+libc_hidden_proto(select)
/* Check the first NFDS descriptors each in READFDS (if not NULL) for read
@@ -33,8 +36,13 @@ extern __typeof(pselect) __libc_pselect;
after waiting the interval specified therein. Additionally set the sigmask
SIGMASK for this call. Returns the number of ready descriptors, or -1 for
errors. */
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+static int
+__pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+#else
int
-__libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+#endif
const struct timespec *timeout, const sigset_t *sigmask)
{
struct timeval tval;
@@ -64,4 +72,23 @@ __libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
return retval;
}
-weak_alias(__libc_pselect,pselect)
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+int
+pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ const struct timespec *timeout, const sigset_t *sigmask)
+{
+ if (SINGLE_THREAD_P)
+ return __pselect (nfds, readfds, writefds, exceptfds,
+ timeout, sigmask);
+
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+ int result = __pselect (nfds, readfds, writefds, exceptfds,
+ timeout, sigmask);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+}
+#endif
diff --git a/libc/sysdeps/linux/common/readv.c b/libc/sysdeps/linux/common/readv.c
index 3c40a0d8d..fce396d5f 100644
--- a/libc/sysdeps/linux/common/readv.c
+++ b/libc/sysdeps/linux/common/readv.c
@@ -2,7 +2,8 @@
/*
* readv() for uClibc
*
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
*
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
@@ -10,5 +11,40 @@
#include <sys/syscall.h>
#include <sys/uio.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+
+/* We should deal with kernel which have a smaller UIO_FASTIOV as well
+ as a very big count. */
+static ssize_t __readv (int fd, const struct iovec *vector, int count)
+{
+ ssize_t bytes_read;
+
+ bytes_read = INLINE_SYSCALL (readv, 3, fd, vector, count);
+
+ if (bytes_read >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
+ return bytes_read;
+
+ /* glibc tries again, but we do not. */
+ //return __atomic_readv_replacement (fd, vector, count);
+
+ return -1;
+}
+
+ssize_t readv (int fd, const struct iovec *vector, int count)
+{
+ if (SINGLE_THREAD_P)
+ return __readv (fd, vector, count);
+
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+ int result = __readv (fd, vector, count);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+}
+#else
_syscall3(ssize_t, readv, int, filedes, const struct iovec *, vector,
int, count)
+#endif
diff --git a/libc/sysdeps/linux/common/select.c b/libc/sysdeps/linux/common/select.c
index caff28d7c..0c2d91984 100644
--- a/libc/sysdeps/linux/common/select.c
+++ b/libc/sysdeps/linux/common/select.c
@@ -11,15 +11,21 @@
#include <sys/select.h>
#include <stdint.h>
-extern __typeof(select) __libc_select;
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep-cancel.h>
+#else
+#define SINGLE_THREAD_P 1
+#endif
#define USEC_PER_SEC 1000000L
+extern __typeof(select) __libc_select;
+
#if !defined(__NR__newselect) && !defined(__NR_select) && defined __USE_XOPEN2K
# define __NR___libc_pselect6 __NR_pselect6
_syscall6(int, __libc_pselect6, int, n, fd_set *, readfds, fd_set *, writefds,
- fd_set *, exceptfds, const struct timespec *, timeout,
- const sigset_t *, sigmask)
+ fd_set *, exceptfds, const struct timespec *, timeout,
+ const sigset_t *, sigmask)
int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
@@ -30,12 +36,12 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
_ts.tv_sec = timeout->tv_sec;
/* GNU extension: allow for timespec values where the sub-sec
- * field is equal to or more than 1 second. The kernel will
- * reject this on us, so take care of the time shift ourself.
- * Some applications (like readline and linphone) do this.
- * See 'clarification on select() type calls and invalid timeouts'
- * on the POSIX general list for more information.
- */
+ * field is equal to or more than 1 second. The kernel will
+ * reject this on us, so take care of the time shift ourself.
+ * Some applications (like readline and linphone) do this.
+ * See 'clarification on select() type calls and invalid timeouts'
+ * on the POSIX general list for more information.
+ */
usec = timeout->tv_usec;
if (usec >= USEC_PER_SEC) {
_ts.tv_sec += usec / USEC_PER_SEC;
@@ -46,18 +52,41 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
ts = &_ts;
}
- return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0);
+ if (SINGLE_THREAD_P)
+ return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+ int oldtype = LIBC_CANCEL_ASYNC ();
+ int result = __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0);
+ LIBC_CANCEL_RESET (oldtype);
+ return result;
+#endif
+
}
#else
#ifdef __NR__newselect
-# define __NR___libc_select __NR__newselect
+# define __NR___syscall_select __NR__newselect
#else
-# define __NR___libc_select __NR_select
+# define __NR___syscall_select __NR_select
#endif
-_syscall5(int, __libc_select, int, n, fd_set *, readfds, fd_set *, writefds,
- fd_set *, exceptfds, struct timeval *, timeout)
+
+_syscall5(int, __syscall_select, int, n, fd_set *, readfds,
+ fd_set *, writefds, fd_set *, exceptfds, struct timeval *, timeout);
+
+int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+ if (SINGLE_THREAD_P)
+ return __syscall_select(n, readfds, writefds, exceptfds, timeout);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+ int oldtype = LIBC_CANCEL_ASYNC ();
+ int result = __syscall_select(n, readfds, writefds, exceptfds, timeout);
+ LIBC_CANCEL_RESET (oldtype);
+ return result;
+#endif
+}
#endif
diff --git a/libc/sysdeps/linux/common/sigprocmask.c b/libc/sysdeps/linux/common/sigprocmask.c
index 13bb2beb7..011d7b367 100644
--- a/libc/sysdeps/linux/common/sigprocmask.c
+++ b/libc/sysdeps/linux/common/sigprocmask.c
@@ -14,6 +14,7 @@
#undef sigprocmask
+libc_hidden_proto(sigprocmask)
#ifdef __NR_rt_sigprocmask
@@ -24,20 +25,28 @@ _syscall4(int, __rt_sigprocmask, int, how, const sigset_t *, set,
int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)
{
- if (set &&
-# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2)
- (((unsigned int) how) > 2)
-# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3)
- (((unsigned int)(how-1)) > 2)
-# else
-# warning "compile time assumption violated.. slow path..."
- ((how != SIG_BLOCK) && (how != SIG_UNBLOCK)
- && (how != SIG_SETMASK))
+#ifdef SIGCANCEL
+ sigset_t local_newmask;
+
+ /*
+ * The only thing we have to make sure here is that SIGCANCEL and
+ * SIGSETXID are not blocked.
+ */
+ if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+ || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+ ))
+ {
+ local_newmask = *set;
+ __sigdelset (&local_newmask, SIGCANCEL);
+# ifdef SIGSETXID
+ __sigdelset (&local_newmask, SIGSETXID);
# endif
- ) {
- __set_errno(EINVAL);
- return -1;
+ set = &local_newmask;
}
+#endif
+
return __rt_sigprocmask(how, set, oldset, _NSIG / 8);
}
@@ -51,20 +60,28 @@ _syscall3(int, __syscall_sigprocmask, int, how, const sigset_t *, set,
int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)
{
- if (set &&
-# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2)
- (((unsigned int) how) > 2)
-# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3)
- (((unsigned int)(how-1)) > 2)
-# else
-# warning "compile time assumption violated.. slow path..."
- ((how != SIG_BLOCK) && (how != SIG_UNBLOCK)
- && (how != SIG_SETMASK))
+#ifdef SIGCANCEL
+ sigset_t local_newmask;
+
+ /*
+ * The only thing we have to make sure here is that SIGCANCEL and
+ * SIGSETXID are not blocked.
+ */
+ if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+ || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+ ))
+ {
+ local_newmask = *set;
+ __sigdelset (&local_newmask, SIGCANCEL);
+# ifdef SIGSETXID
+ __sigdelset (&local_newmask, SIGSETXID);
# endif
- ) {
- __set_errno(EINVAL);
- return -1;
+ set = &local_newmask;
}
+#endif
+
return (__syscall_sigprocmask(how, set, oldset));
}
#endif
diff --git a/libc/sysdeps/linux/common/sigsuspend.c b/libc/sysdeps/linux/common/sigsuspend.c
index 3648e76b5..789eeda89 100644
--- a/libc/sysdeps/linux/common/sigsuspend.c
+++ b/libc/sysdeps/linux/common/sigsuspend.c
@@ -11,27 +11,49 @@
#if defined __USE_POSIX
#include <signal.h>
+#undef sigsuspend
-extern __typeof(sigsuspend) __libc_sigsuspend;
+libc_hidden_proto(sigsuspend)
#ifdef __NR_rt_sigsuspend
# define __NR___rt_sigsuspend __NR_rt_sigsuspend
-static __inline__ _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size)
-int __libc_sigsuspend(const sigset_t * mask)
+# ifdef __UCLIBC_HAS_THREADS_NATIVE__
+# include <errno.h>
+# include <sysdep-cancel.h>
+
+/* Change the set of blocked signals to SET,
+ wait until a signal arrives, and restore the set of blocked signals. */
+int sigsuspend (const sigset_t *set)
+{
+ if (SINGLE_THREAD_P)
+ return INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
+
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+ int result = INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+}
+# else
+static inline _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size);
+
+int sigsuspend(const sigset_t * mask)
{
return __rt_sigsuspend(mask, _NSIG / 8);
}
+# endif
#else
# define __NR___syscall_sigsuspend __NR_sigsuspend
static __inline__ _syscall3(int, __syscall_sigsuspend, int, a, unsigned long int, b,
unsigned long int, c)
-int __libc_sigsuspend(const sigset_t * set)
+int sigsuspend(const sigset_t * set)
{
return __syscall_sigsuspend(0, 0, set->__val[0]);
}
#endif
-weak_alias(__libc_sigsuspend,sigsuspend)
-libc_hidden_weak(sigsuspend)
+libc_hidden_def(sigsuspend)
#endif
diff --git a/libc/sysdeps/linux/common/wait.c b/libc/sysdeps/linux/common/wait.c
index b16495314..d4b79bd37 100644
--- a/libc/sysdeps/linux/common/wait.c
+++ b/libc/sysdeps/linux/common/wait.c
@@ -1,23 +1,43 @@
/*
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
* Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
*
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
-
#include <stdlib.h>
#include <syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
-#ifdef __LINUXTHREADS_OLD__
-extern __typeof(wait) weak_function wait;
-strong_alias(wait,__libc_wait)
-#endif
+/* Wait for a child to die. When one does, put its status in *STAT_LOC
+ * and return its process ID. For errors, return (pid_t) -1. */
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+
+pid_t attribute_hidden
+__libc_wait (__WAIT_STATUS_DEFN stat_loc)
+{
+ if (SINGLE_THREAD_P)
+ return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
+ (struct rusage *) NULL);
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+ pid_t result = INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
+ (struct rusage *) NULL);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+}
+#else
/* Wait for a child to die. When one does, put its status in *STAT_LOC
* and return its process ID. For errors, return (pid_t) -1. */
-__pid_t wait(__WAIT_STATUS_DEFN stat_loc)
+__pid_t __libc_wait (__WAIT_STATUS_DEFN stat_loc)
{
- return wait4(WAIT_ANY, stat_loc, 0, NULL);
+ return wait4 (WAIT_ANY, stat_loc, 0, (struct rusage *) NULL);
}
+#endif
+weak_alias(__libc_wait,wait)
diff --git a/libc/sysdeps/linux/common/waitpid.c b/libc/sysdeps/linux/common/waitpid.c
index e46499377..d0437194d 100644
--- a/libc/sysdeps/linux/common/waitpid.c
+++ b/libc/sysdeps/linux/common/waitpid.c
@@ -1,5 +1,6 @@
/* vi: set sw=4 ts=4: */
/*
+ * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>
* Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
*
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
@@ -10,13 +11,27 @@
#include <sys/wait.h>
#include <sys/resource.h>
-__pid_t waitpid(__pid_t pid, int *wait_stat, int options)
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include "sysdep-cancel.h"
+#else
+#define SINGLE_THREAD_P 1
+#endif
+
+libc_hidden_proto(wait4)
+
+extern __typeof(waitpid) __libc_waitpid;
+__pid_t __libc_waitpid(__pid_t pid, int *wait_stat, int options)
{
- return wait4(pid, wait_stat, options, NULL);
+ if (SINGLE_THREAD_P)
+ return wait4(pid, wait_stat, options, NULL);
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+ int oldtype = LIBC_CANCEL_ASYNC ();
+ int result = wait4(pid, wait_stat, options, NULL);
+ LIBC_CANCEL_RESET (oldtype);
+ return result;
+#endif
}
-#ifndef __LINUXTHREADS_OLD__
-libc_hidden_def(waitpid)
-#else
+libc_hidden_proto(waitpid)
+weak_alias(__libc_waitpid,waitpid)
libc_hidden_weak(waitpid)
-strong_alias(waitpid,__libc_waitpid)
-#endif
diff --git a/libc/sysdeps/linux/common/writev.c b/libc/sysdeps/linux/common/writev.c
index 99de7e43d..bd0e4077d 100644
--- a/libc/sysdeps/linux/common/writev.c
+++ b/libc/sysdeps/linux/common/writev.c
@@ -10,5 +10,41 @@
#include <sys/syscall.h>
#include <sys/uio.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <sysdep-cancel.h>
+
+/* We should deal with kernel which have a smaller UIO_FASTIOV as well
+ as a very big count. */
+static ssize_t __writev (int fd, const struct iovec *vector, int count)
+{
+ ssize_t bytes_written;
+
+ bytes_written = INLINE_SYSCALL (writev, 3, fd, vector, count);
+
+ if (bytes_written >= 0 || errno != EINVAL || count <= UIO_FASTIOV)
+ return bytes_written;
+
+ /* glibc tries again, but we do not. */
+ /* return __atomic_writev_replacement (fd, vector, count); */
+
+ return -1;
+}
+
+ssize_t writev (int fd, const struct iovec *vector, int count)
+{
+ if (SINGLE_THREAD_P)
+ return __writev (fd, vector, count);
+
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+ ssize_t result = __writev (fd, vector, count);
+
+ LIBC_CANCEL_RESET (oldtype);
+
+ return result;
+}
+#else
_syscall3(ssize_t, writev, int, filedes, const struct iovec *, vector,
int, count)
+#endif
diff --git a/libc/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/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..38d4ce903
--- /dev/null
+++ b/libc/sysdeps/linux/mips/sysdep.h
@@ -0,0 +1,54 @@
+/* Adapted from glibc's sysdeps/unix/mips/sysdep.h */
+
+/* Copyright (C) 1992, 1995, 1997, 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 <features.h>
+
+#if __UCLIBC_HAS_THREADS_NATIVE__
+#include_next <sysdep.h>
+
+#else
+
+#ifdef __ASSEMBLER__
+
+#include <sgidefs.h>
+#include <sys/regdef.h>
+
+#define ENTRY(name) \
+ .globl name; \
+ .align 2; \
+ .ent name,0; \
+ name##:
+
+#undef END
+#define END(function) \
+ .end function; \
+ .size function,.-function
+
+#if _MIPS_SIM == _ABIO32
+# define L(label) $L ## label
+#else
+# define L(label) .L ## label
+#endif
+
+#endif
+
+#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */
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/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/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/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..8f53a8412 100644
--- a/libc/sysdeps/linux/x86_64/clone.S
+++ b/libc/sysdeps/linux/x86_64/clone.S
@@ -112,3 +112,4 @@ clone:
call HIDDEN_JUMPTARGET(_exit)
.size clone,.-clone
+weak_alias(clone, __clone)
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..b92498b23 100644
--- a/libc/unistd/sysconf.c
+++ b/libc/unistd/sysconf.c
@@ -34,6 +34,9 @@
#ifdef __UCLIBC_HAS_REGEX__
#include <regex.h>
#endif
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sysdep.h>
+#endif
#ifdef HAVE_LINUX_CPUMASK_H
# include <linux/cpumask.h>
@@ -906,13 +909,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)