diff options
Diffstat (limited to 'libc')
106 files changed, 3646 insertions, 880 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 99346d7f8..c6d6204ae 100644 --- a/libc/inet/hostid.c +++ b/libc/inet/hostid.c @@ -14,6 +14,7 @@ #include <netdb.h> #include <fcntl.h> #include <unistd.h> +#include <not-cancel.h> #define HOSTID "/etc/hostid" @@ -26,11 +27,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,13 +45,13 @@ 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); - if (fd >= 0 && read(fd, &id, sizeof(id))) + fd = open_not_cancel_2(HOSTID, O_RDONLY); + if (fd >= 0 && read_not_cancel(fd, &id, sizeof(id))) { - close (fd); + close_not_cancel_no_status (fd); return id; } - if (fd >= 0) close (fd); + if (fd >= 0) close_not_cancel_no_status (fd); /* Try some methods of returning a unique 32 bit id. Clearly IP * numbers, if on the internet, will have a unique address. If they 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 b166aaaa7..cb2c6ed14 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 @@ -267,6 +281,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 @@ -386,34 +405,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 f768b7019..be9ddac94 100644 --- a/libc/signal/Makefile.in +++ b/libc/signal/Makefile.in @@ -21,6 +21,10 @@ ifeq ($(UCLIBC_SUSV4_LEGACY),y) CSRC += sigintr.c endif +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC:=$(filter-out raise.c sigaction.c,$(CSRC)) +endif + ifneq ($(strip $(ARCH_OBJS)),) CSRC := $(filter-out $(notdir $(ARCH_OBJS:.o=.c)),$(CSRC)) endif diff --git a/libc/signal/sigpause.c b/libc/signal/sigpause.c index e465fac7a..8c4e83e76 100644 --- a/libc/signal/sigpause.c +++ b/libc/signal/sigpause.c @@ -23,7 +23,9 @@ #define __FAVOR_BSD #include <signal.h> #include <stddef.h> /* For NULL. */ -#include <string.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#endif #include "sigset-cvt-mask.h" @@ -45,6 +47,9 @@ int __sigpause (int sig_or_mask, int is_sig) else sigset_set_old_mask (&set, sig_or_mask); + /* Note the sigpause() is a cancellation point. But since we call + sigsuspend() which itself is a cancellation point we do not have + to do anything here. */ return sigsuspend (&set); } libc_hidden_def(__sigpause) @@ -56,5 +61,18 @@ libc_hidden_def(__sigpause) the BSD version. So make this the default. */ int sigpause (int mask) { +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + if (SINGLE_THREAD_P) + return __sigpause (mask, 0); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = __sigpause (mask, 0); + + LIBC_CANCEL_RESET (oldtype); + + return result; +#else return __sigpause (mask, 0); +#endif } diff --git a/libc/signal/sigset-cvt-mask.h b/libc/signal/sigset-cvt-mask.h index 76dd01c7e..d4c2dc7ca 100644 --- a/libc/signal/sigset-cvt-mask.h +++ b/libc/signal/sigset-cvt-mask.h @@ -19,6 +19,8 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <string.h> + static __inline__ void __attribute__ ((unused)) sigset_set_old_mask (sigset_t *set, int mask) { diff --git a/libc/signal/sigwait.c b/libc/signal/sigwait.c index 6bca1b1e5..917e3d7be 100644 --- a/libc/signal/sigwait.c +++ b/libc/signal/sigwait.c @@ -1,7 +1,8 @@ /* vi: set sw=4 ts=4: */ /* sigwait * - * Copyright (C) 2003 by Erik Andersen <andersen@uclibc.org> + * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com> + * Copyright (C) 2003-2005 by Erik Andersen <andersen@uclibc.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,19 +23,86 @@ #include <signal.h> #include <string.h> -#if defined __UCLIBC_HAS_REALTIME__ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# include <sysdep-cancel.h> -int sigwait(const sigset_t *set, int *sig) +# ifdef __NR_rt_sigtimedwait + +/* Return any pending signal or wait for one for the given time. */ +static int do_sigwait(const sigset_t *set, int *sig) +{ + int ret; + +# ifdef SIGCANCEL + sigset_t tmpset; + if (set != NULL + && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + /* Create a temporary mask without the bit for SIGCANCEL set. */ + // We are not copying more than we have to. + memcpy(&tmpset, set, _NSIG / 8); + __sigdelset(&tmpset, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset(&tmpset, SIGSETXID); +# endif + set = &tmpset; + } +# endif + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + INTERNAL_SYSCALL_DECL(err); + do + ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, set, NULL, + NULL, _NSIG / 8); + while (INTERNAL_SYSCALL_ERROR_P (ret, err) + && INTERNAL_SYSCALL_ERRNO (ret, err) == EINTR); + if (! INTERNAL_SYSCALL_ERROR_P (ret, err)) + { + *sig = ret; + ret = 0; + } +else + ret = INTERNAL_SYSCALL_ERRNO (ret, err); + + return ret; +} + +int sigwait (const sigset_t *set, int *sig) +{ + if(SINGLE_THREAD_P) + return do_sigwait(set, sig); + + int oldtype = LIBC_CANCEL_ASYNC(); + + int result = do_sigwait(set, sig); + + LIBC_CANCEL_RESET(oldtype); + + return result; +} +# else /* __NR_rt_sigtimedwait */ +# error We must have rt_sigtimedwait defined!!! +# endif +#else /* __UCLIBC_HAS_THREADS_NATIVE__ */ + +# if defined __UCLIBC_HAS_REALTIME__ + +int sigwait (const sigset_t *set, int *sig) { - int ret = sigwaitinfo(set, NULL); - if (ret != -1) { + int ret = 1; + if ((ret = sigwaitinfo(set, NULL)) != -1) { *sig = ret; return 0; } return 1; } -#else /* __UCLIBC_HAS_REALTIME__ */ +# else /* __UCLIBC_HAS_REALTIME__ */ /* variant without REALTIME extensions */ static smallint was_sig; /* obviously not thread-safe */ @@ -94,4 +162,5 @@ int sigwait (const sigset_t *set, int *sig) *sig = was_sig; return was_sig == -1 ? -1 : 0; } -#endif /* __UCLIBC_HAS_REALTIME__ */ +# endif /* __UCLIBC_HAS_REALTIME__ */ +#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */ diff --git a/libc/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 48ee5f227..af8be6451 100644 --- a/libc/stdlib/Makefile.in +++ b/libc/stdlib/Makefile.in @@ -13,7 +13,7 @@ include $(top_srcdir)libc/stdlib/malloc-standard/Makefile.in CSRC := \ 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 \ @@ -40,7 +40,6 @@ ifeq ($(UCLIBC_SUSV3_LEGACY),y) CSRC += mktemp.c endif - # multi source stdlib.c CSRC += abs.c labs.c atoi.c atol.c strtol.c strtoul.c _stdlib_strto_l.c \ qsort.c bsearch.c \ @@ -92,7 +91,9 @@ STDLIB_SRC := $(patsubst %.c,$(STDLIB_DIR)/%.c,$(CSRC)) STDLIB_OBJ := $(patsubst %.c,$(STDLIB_OUT)/%.o,$(CSRC)) 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..64c2432f5 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -34,6 +34,15 @@ 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)) +ifneq ($(TARGET_ARCH),arm) +CSRC := $(filter-out waitpid.c, $(CSRC)) +else +CSRC := $(filter-out vfork.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 +84,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/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) |