diff options
Diffstat (limited to 'libc/sysdeps')
59 files changed, 2421 insertions, 642 deletions
| diff --git a/libc/sysdeps/linux/arm/Makefile.arch b/libc/sysdeps/linux/arm/Makefile.arch index c3c55258a..bec06ff44 100644 --- a/libc/sysdeps/linux/arm/Makefile.arch +++ b/libc/sysdeps/linux/arm/Makefile.arch @@ -5,14 +5,24 @@  # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.  # -CSRC := brk.c ioperm.c iopl.c mmap.c sigaction.c __syscall_error.c +CSRC := brk.c ioperm.c iopl.c mmap.c __syscall_error.c + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +endif  SSRC := \ -	__longjmp.S vfork.S clone.S setjmp.S bsd-setjmp.S \ +	__longjmp.S setjmp.S bsd-setjmp.S \  	bsd-_setjmp.S sigrestorer.S mmap64.S +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +SSRC += libc-aeabi_read_tp.S libc-thumb_atomics.S +else +SSRC += vfork.S clone.S +endif +  ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y) -        CSRC += posix_fadvise.c posix_fadvise64.c +CSRC += posix_fadvise.c posix_fadvise64.c  endif  ifeq ($(CONFIG_ARM_EABI),y) diff --git a/libc/sysdeps/linux/arm/clone.S b/libc/sysdeps/linux/arm/clone.S index d9483735d..fdc05b88b 100644 --- a/libc/sysdeps/linux/arm/clone.S +++ b/libc/sysdeps/linux/arm/clone.S @@ -30,12 +30,12 @@  /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */  .text -.global clone -.type clone,%function +.global __clone +.type __clone,%function  .align 2  #if defined(THUMB1_ONLY)  .thumb_func -clone: +__clone:  	@ sanity check args  	cmp	r0, #0  	beq	__einval @@ -52,9 +52,15 @@ clone:  	@ get flags  	mov	r0, r2  	@ new sp is already in r1 +	@ load remaining arguments off the stack +	stmfd	sp!, {r4} +	ldr	r2, [sp, #4] +	ldr	r3, [sp, #8] +	ldr	r4, [sp, #12]  	DO_CALL (clone)  	movs	a1, a1  	blt	__error +	ldmnefd sp!, {r4}  	beq	1f  	bx	lr  1: @@ -80,7 +86,7 @@ __error:  	POP_RET  .pool  #else -clone: +__clone:  	@ sanity check args  	cmp	r0, #0  	IT(te, ne) @@ -98,9 +104,15 @@ clone:  	@ get flags  	mov	r0, r2  	@ new sp is already in r1 +	@ load remaining arguments off the stack +	stmfd	sp!, {r4} +	ldr	r2, [sp, #4] +	ldr	r3, [sp, #8] +	ldr	r4, [sp, #12]  	DO_CALL (clone)  	movs	a1, a1  	blt	__error +	ldmnefd	sp!, {r4}  	IT(t, ne)  #if defined(__USE_BX__)  	bxne	lr @@ -120,6 +132,7 @@ __error:  	b	__syscall_error  #endif -.size clone,.-clone +.size __clone,.-__clone +weak_alias(__clone, clone)  #endif diff --git a/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S b/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S new file mode 100644 index 000000000..3aa135bf2 --- /dev/null +++ b/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S @@ -0,0 +1 @@ +#include <ldso/ldso/arm/aeabi_read_tp.S> diff --git a/libc/sysdeps/linux/arm/libc-thumb_atomics.S b/libc/sysdeps/linux/arm/libc-thumb_atomics.S new file mode 100644 index 000000000..e7bc8950d --- /dev/null +++ b/libc/sysdeps/linux/arm/libc-thumb_atomics.S @@ -0,0 +1 @@ +#include <ldso/ldso/arm/thumb_atomics.S> diff --git a/libc/sysdeps/linux/arm/vfork.S b/libc/sysdeps/linux/arm/vfork.S index 42595b026..17d6a4db0 100644 --- a/libc/sysdeps/linux/arm/vfork.S +++ b/libc/sysdeps/linux/arm/vfork.S @@ -12,6 +12,15 @@  #include <bits/errno.h>  #include <sys/syscall.h> +#ifndef SAVE_PID +#define SAVE_PID +#endif + +#ifndef RESTORE_PID +#define RESTORE_PID +#endif + +  #ifdef __NR_fork  .text  .global	__vfork @@ -23,7 +32,9 @@  .thumb_func  __vfork:  #ifdef __NR_vfork +	SAVE_PID  	DO_CALL (vfork) +	RESTORE_PID  	ldr		r1, =0xfffff000  	cmp		r0, r1  	bcs		1f @@ -57,7 +68,9 @@ __error:  __vfork:  #ifdef __NR_vfork +	SAVE_PID  	DO_CALL (vfork) +	RESTORE_PID  	cmn	r0, #4096  	IT(t, cc)  #if defined(__USE_BX__) diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in index ec889ca0d..45c70baf6 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -34,6 +34,17 @@ CSRC := $(filter-out capget.c capset.c inotify.c ioperm.c iopl.c madvise.c \  	sync_file_range.c sysctl.c sysinfo.c timerfd.c uselib.c vhangup.c,$(CSRC))  endif +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC := $(filter-out fork.c getpid.c raise.c open.c close.c read.c write.c, $(CSRC)) +ifeq ($(TARGET_ARCH),arm) +CSRC := $(filter-out vfork.c, $(CSRC)) +else ifeq ($(TARGET_ARCH),x86_64) +#do nothing +else +CSRC := $(filter-out waitpid.c, $(CSRC)) +endif +endif +  ifneq ($(UCLIBC_BSD_SPECIFIC),y)  # we need these internally: getdomainname.c  CSRC := $(filter-out mincore.c setdomainname.c,$(CSRC)) @@ -75,6 +86,18 @@ ifneq ($(UCLIBC_SV4_DEPRECATED),y)  CSRC := $(filter-out ustat.c,$(CSRC))  endif +ifeq ($(TARGET_ARCH),sh) +CSRC := $(filter-out longjmp.c vfork.c,$(CSRC)) +endif + +ifeq ($(TARGET_ARCH),sparc) +CSRC := $(filter-out vfork.c,$(CSRC)) +endif + +ifeq ($(TARGET_ARCH),i386) +CSRC := $(filter-out vfork.c,$(CSRC)) +endif +  # fails for some reason  ifneq ($(strip $(ARCH_OBJS)),)  CSRC := $(filter-out $(notdir $(ARCH_OBJS:.o=.c)) $(ARCH_OBJ_FILTEROUT),$(CSRC)) diff --git a/libc/sysdeps/linux/common/__rt_sigtimedwait.c b/libc/sysdeps/linux/common/__rt_sigtimedwait.c index f9ec0eabf..554c6b9cb 100644 --- a/libc/sysdeps/linux/common/__rt_sigtimedwait.c +++ b/libc/sysdeps/linux/common/__rt_sigtimedwait.c @@ -2,44 +2,97 @@  /*   * __rt_sigtimedwait() for uClibc   * - * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com> + * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>   * - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + * GNU Library General Public License (LGPL) version 2 or later.   */  #include <sys/syscall.h>  #include <signal.h> -#define __need_NULL -#include <stddef.h> +#include <string.h> +libc_hidden_proto(memcpy)  #ifdef __NR_rt_sigtimedwait -#define __NR___rt_sigtimedwait __NR_rt_sigtimedwait -static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set, siginfo_t *, info, -		  const struct timespec *, timeout, size_t, setsize) +#include <string.h> +libc_hidden_proto(memcpy) -int sigwaitinfo(const sigset_t * set, siginfo_t * info) +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#  include <sysdep-cancel.h> + +static int do_sigtimedwait(const sigset_t *set, siginfo_t *info, +						   const struct timespec *timeout)  { -	return __rt_sigtimedwait(set, info, NULL, _NSIG / 8); +#  ifdef SIGCANCEL +	sigset_t tmpset; + +	if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +#   ifdef SIGSETXID +		|| __builtin_expect (__sigismember (set, SIGSETXID), 0) +#   endif +		)) +	{ +		/* Create a temporary mask without the bit for SIGCANCEL set.  */ +		// We are not copying more than we have to. +		memcpy (&tmpset, set, _NSIG / 8); +		__sigdelset (&tmpset, SIGCANCEL); +#   ifdef SIGSETXID +		__sigdelset (&tmpset, SIGSETXID); +#   endif +		set = &tmpset; +	} +#  endif + +	/* XXX The size argument hopefully will have to be changed to the +	   real size of the user-level sigset_t.  */ +	int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info, +								 timeout, _NSIG / 8); + +	/* The kernel generates a SI_TKILL code in si_code in case tkill is +	   used.  tkill is transparently used in raise().  Since having +	   SI_TKILL as a code is useful in general we fold the results +	   here.  */ +	if (result != -1 && info != NULL && info->si_code == SI_TKILL) +		info->si_code = SI_USER; + +	return result;  } -int sigtimedwait(const sigset_t * set, siginfo_t * info, -				 const struct timespec *timeout) +/* Return any pending signal or wait for one for the given time.  */ +int __sigtimedwait(const sigset_t *set, siginfo_t *info, +				   const struct timespec *timeout)  { -	return __rt_sigtimedwait(set, info, timeout, _NSIG / 8); +	if(SINGLE_THREAD_P) +		return do_sigtimedwait(set, info, timeout); + +	int oldtype = LIBC_CANCEL_ASYNC(); + +	/* XXX The size argument hopefully will have to be changed to the +	   real size of the user-level sigset_t.  */ +	int result = do_sigtimedwait(set, info, timeout); + +	LIBC_CANCEL_RESET(oldtype); + +	return result;  } -#else -int sigwaitinfo(const sigset_t * set, siginfo_t * info) +# else +#  define __need_NULL +#  include <stddef.h> +#  define __NR___rt_sigtimedwait __NR_rt_sigtimedwait +static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set, +				 siginfo_t *, info, const struct timespec *, timeout, +				 size_t, setsize); + +int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info, +									const struct timespec *timeout)  { -	if (set == NULL) -		__set_errno(EINVAL); -	else -		__set_errno(ENOSYS); -	return -1; +	return __rt_sigtimedwait(set, info, timeout, _NSIG / 8);  } - -int sigtimedwait(const sigset_t * set, siginfo_t * info, -				 const struct timespec *timeout) +# endif /* !__UCLIBC_HAS_THREADS_NATIVE__ */ +#else +int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info, +									const struct timespec *timeout)  {  	if (set == NULL)  		__set_errno(EINVAL); @@ -48,5 +101,4 @@ int sigtimedwait(const sigset_t * set, siginfo_t * info,  	return -1;  }  #endif -libc_hidden_def(sigwaitinfo) -libc_hidden_def(sigtimedwait) +weak_alias(__sigtimedwait,sigtimedwait) diff --git a/libc/sysdeps/linux/common/__rt_sigwaitinfo.c b/libc/sysdeps/linux/common/__rt_sigwaitinfo.c new file mode 100644 index 000000000..c8953bfbc --- /dev/null +++ b/libc/sysdeps/linux/common/__rt_sigwaitinfo.c @@ -0,0 +1,102 @@ +/* vi: set sw=4 ts=4: */ +/* + * __rt_sigwaitinfo() for uClibc + * + * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com> + * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org> + * + * GNU Library General Public License (LGPL) version 2 or later. + */ + +#include <sys/syscall.h> +#include <signal.h> +#include <string.h> + +libc_hidden_proto(memcpy) + +#ifdef __NR_rt_sigtimedwait + +#include <string.h> + +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#  include <sysdep-cancel.h> + +static int do_sigwaitinfo(const sigset_t *set, siginfo_t *info) +{ +#  ifdef SIGCANCEL +	sigset_t tmpset; + +	if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +#   ifdef SIGSETXID +		|| __builtin_expect (__sigismember (set, SIGSETXID), 0) +#   endif +		)) +	{ +		/* Create a temporary mask without the bit for SIGCANCEL set.  */ +		// We are not copying more than we have to. +		memcpy (&tmpset, set, _NSIG / 8); +		__sigdelset (&tmpset, SIGCANCEL); +#   ifdef SIGSETXID +		__sigdelset (&tmpset, SIGSETXID); +#   endif +		set = &tmpset; +	} +#  endif + +	/* XXX The size argument hopefully will have to be changed to the +	   real size of the user-level sigset_t.  */ +	int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info, +								 NULL, _NSIG / 8); + +	/* The kernel generates a SI_TKILL code in si_code in case tkill is +	   used.  tkill is transparently used in raise().  Since having +	   SI_TKILL as a code is useful in general we fold the results +	   here.  */ +	if (result != -1 && info != NULL && info->si_code == SI_TKILL) +		info->si_code = SI_USER; + +	return result; +} + +/* Return any pending signal or wait for one for the given time.  */ +int __sigwaitinfo(const sigset_t *set, siginfo_t *info) +{ +	if(SINGLE_THREAD_P) +		return do_sigwaitinfo(set, info); + +	int oldtype = LIBC_CANCEL_ASYNC(); + +	/* XXX The size argument hopefully will have to be changed to the +	   real size of the user-level sigset_t.  */ +	int result = do_sigwaitinfo(set, info); + +	LIBC_CANCEL_RESET(oldtype); + +	return result; +} +# else +#  define __need_NULL +#  include <stddef.h> +#  define __NR___rt_sigwaitinfo __NR_rt_sigtimedwait +static _syscall4(int, __rt_sigwaitinfo, const sigset_t *, set, +				 siginfo_t *, info, const struct timespec *, timeout, +				 size_t, setsize); + +int attribute_hidden __sigwaitinfo(const sigset_t * set, siginfo_t * info) +{ +	return __rt_sigwaitinfo(set, info, NULL, _NSIG / 8); +} +# endif +#else +int attribute_hidden __sigwaitinfo(const sigset_t * set, siginfo_t * info) +{ +	if (set == NULL) +		__set_errno(EINVAL); +	else +		__set_errno(ENOSYS); +	return -1; +} +#endif +libc_hidden_proto(sigwaitinfo) +weak_alias (__sigwaitinfo, sigwaitinfo) +libc_hidden_weak(sigwaitinfo) diff --git a/libc/sysdeps/linux/common/__syscall_fcntl.c b/libc/sysdeps/linux/common/__syscall_fcntl.c index 355b22b00..4e3bc23df 100644 --- a/libc/sysdeps/linux/common/__syscall_fcntl.c +++ b/libc/sysdeps/linux/common/__syscall_fcntl.c @@ -2,6 +2,7 @@  /*   * __syscall_fcntl() for uClibc   * + * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>   * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>   *   * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. @@ -9,42 +10,83 @@  #include <sys/syscall.h>  #include <stdarg.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h>	/* Must come before <fcntl.h>.  */ +#endif  #include <fcntl.h>  #include <bits/wordsize.h> -#define __NR___syscall_fcntl __NR_fcntl -static __always_inline -_syscall3(int, __syscall_fcntl, int, fd, int, cmd, long, arg) +extern __typeof(fcntl) __libc_fcntl; +libc_hidden_proto(__libc_fcntl) -int fcntl(int fd, int cmd, ...) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +int __fcntl_nocancel (int fd, int cmd, ...)  { -	long arg; -	va_list list; +	va_list ap; +	void *arg; -	va_start(list, cmd); -	arg = va_arg(list, long); -	va_end(list); +	va_start (ap, cmd); +	arg = va_arg (ap, void *); +	va_end (ap); -#if __WORDSIZE == 32 +# if __WORDSIZE == 32  	if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) { -#if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 -		return fcntl64(fd, cmd, arg); -#else +#  if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 +		return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); +#  else  		__set_errno(ENOSYS);  		return -1; -#endif +#  endif  	} +# endif +	return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg); +}  #endif -	return (__syscall_fcntl(fd, cmd, arg)); -} -#ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(fcntl) +int __libc_fcntl (int fd, int cmd, ...) +{ +	va_list ap; +	void *arg; + +	va_start (ap, cmd); +	arg = va_arg (ap, void *); +	va_end (ap); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	if (SINGLE_THREAD_P || (cmd != F_SETLKW && cmd != F_SETLKW64)) +# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 +		return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); +# else +		return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg); +# endif + +	int oldtype = LIBC_CANCEL_ASYNC (); + +# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 +	int result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); +# else +	int result = INLINE_SYSCALL (fcntl, 3, fd, cmd, arg); +# endif + +	LIBC_CANCEL_RESET (oldtype); + +	return result;  #else -libc_hidden_weak(fcntl) -strong_alias(fcntl,__libc_fcntl) +# if __WORDSIZE == 32 +	if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) { +#  if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 +		return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); +#  else +		__set_errno(ENOSYS); +		return -1; +#  endif +	} +# endif +	return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);  #endif +} +libc_hidden_def(__libc_fcntl) -#if ! defined __NR_fcntl64 && defined __UCLIBC_HAS_LFS__ -strong_alias(fcntl,fcntl64) -#endif +libc_hidden_proto(fcntl) +weak_alias(__libc_fcntl,fcntl) +libc_hidden_weak(fcntl) diff --git a/libc/sysdeps/linux/common/__syscall_rt_sigaction.c b/libc/sysdeps/linux/common/__syscall_rt_sigaction.c index b4b007d02..006b38a2a 100644 --- a/libc/sysdeps/linux/common/__syscall_rt_sigaction.c +++ b/libc/sysdeps/linux/common/__syscall_rt_sigaction.c @@ -12,7 +12,9 @@  #ifdef __NR_rt_sigaction  #include <signal.h> -int __syscall_rt_sigaction (int __signum, const struct sigaction *__act, struct sigaction *__oldact, size_t __size) attribute_hidden; +int __syscall_rt_sigaction (int __signum, const struct sigaction *__act, +							struct sigaction *__oldact, size_t __size); +  #define __NR___syscall_rt_sigaction __NR_rt_sigaction  _syscall4(int, __syscall_rt_sigaction, int, signum,  		  const struct sigaction *, act, struct sigaction *, oldact, diff --git a/libc/sysdeps/linux/common/_exit.c b/libc/sysdeps/linux/common/_exit.c index 6cece0878..51117d109 100644 --- a/libc/sysdeps/linux/common/_exit.c +++ b/libc/sysdeps/linux/common/_exit.c @@ -12,13 +12,23 @@  #include <unistd.h>  #include <sys/types.h>  #include <sys/syscall.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep.h> +#endif  void attribute_noreturn _exit(int status)  {  	/* The loop is added only to keep gcc happy. */  	while(1) +	{ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# ifdef __NR_exit_group +		INLINE_SYSCALL(exit_group, 1, status); +# endif +#endif  		INLINE_SYSCALL(exit, 1, status); +	}  }  libc_hidden_def(_exit)  weak_alias(_exit,_Exit) diff --git a/libc/sysdeps/linux/common/bits/kernel-features.h b/libc/sysdeps/linux/common/bits/kernel-features.h index 88297349a..923341b35 100644 --- a/libc/sysdeps/linux/common/bits/kernel-features.h +++ b/libc/sysdeps/linux/common/bits/kernel-features.h @@ -26,23 +26,126 @@  #endif  #include <linux/version.h> -#define __LINUX_KERNEL_VERSION	LINUX_VERSION_CODE +#define __LINUX_KERNEL_VERSION		LINUX_VERSION_CODE + +/* We assume for __LINUX_KERNEL_VERSION the same encoding used in +   linux/version.h.  I.e., the major, minor, and subminor all get a +   byte with the major number being in the highest byte.  This means +   we can do numeric comparisons. + +   In the following we will define certain symbols depending on +   whether the describes kernel feature is available in the kernel +   version given by __LINUX_KERNEL_VERSION.  We are not always exactly +   recording the correct versions in which the features were +   introduced.  If somebody cares these values can afterwards be +   corrected.  Most of the numbers here are set corresponding to +   2.2.0.  */ + +/* `getcwd' system call.  */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_GETCWD_SYSCALL	1 +#endif  /* Real-time signal became usable in 2.1.70.  */  #if __LINUX_KERNEL_VERSION >= 131398  # define __ASSUME_REALTIME_SIGNALS	1  #endif -/* Beginning with 2.5.63 support for realtime and monotonic clocks and -   timers based on them is available.  */ -#if __LINUX_KERNEL_VERSION >= 132415 -# define __ASSUME_POSIX_TIMERS		1 +/* When were the `pread'/`pwrite' syscalls introduced?  */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_PREAD_SYSCALL		1 +# define __ASSUME_PWRITE_SYSCALL	1  #endif -/* On x86, the set_thread_area syscall was introduced in 2.5.29, but its -   semantics was changed in 2.5.30, and again after 2.5.31.  */ -#if __LINUX_KERNEL_VERSION >= 132384 && defined __i386__ -# define __ASSUME_SET_THREAD_AREA_SYSCALL	1 +/* When was `poll' introduced?  */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_POLL_SYSCALL		1 +#endif + +/* The `lchown' syscall was introduced in 2.1.80.  */ +#if __LINUX_KERNEL_VERSION >= 131408 +# define __ASSUME_LCHOWN_SYSCALL	1 +#endif + +/* When did the `setresuid' sysall became available?  */ +#if __LINUX_KERNEL_VERSION >= 131584 && !defined __sparc__ +# define __ASSUME_SETRESUID_SYSCALL	1 +#endif + +/* The SIOCGIFNAME ioctl is available starting with 2.1.50.  */ +#if __LINUX_KERNEL_VERSION >= 131408 +# define __ASSUME_SIOCGIFNAME		1 +#endif + +/* MSG_NOSIGNAL was at least available with Linux 2.2.0.  */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_MSG_NOSIGNAL		1 +#endif + +/* On x86 another `getrlimit' syscall was added in 2.3.25.  */ +#if __LINUX_KERNEL_VERSION >= 131865 && defined __i386__ +# define __ASSUME_NEW_GETRLIMIT_SYSCALL	1 +#endif + +/* On x86 the truncate64/ftruncate64 syscalls were introduced in 2.3.31.  */ +#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__ +# define __ASSUME_TRUNCATE64_SYSCALL	1 +#endif + +/* On x86 the mmap2 syscall was introduced in 2.3.31.  */ +#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__ +# define __ASSUME_MMAP2_SYSCALL	1 +#endif + +/* On x86 the stat64/lstat64/fstat64 syscalls were introduced in 2.3.34.  */ +#if __LINUX_KERNEL_VERSION >= 131874 && defined __i386__ +# define __ASSUME_STAT64_SYSCALL	1 +#endif + +/* On sparc and ARM the truncate64/ftruncate64/mmap2/stat64/lstat64/fstat64 +   syscalls were introduced in 2.3.35.  */ +#if __LINUX_KERNEL_VERSION >= 131875 && (defined __sparc__ || defined __arm__) +# define __ASSUME_TRUNCATE64_SYSCALL	1 +# define __ASSUME_MMAP2_SYSCALL		1 +# define __ASSUME_STAT64_SYSCALL	1 +#endif + +/* I know for sure that getrlimit are in 2.3.35 on powerpc.  */ +#if __LINUX_KERNEL_VERSION >= 131875 && defined __powerpc__ +# define __ASSUME_NEW_GETRLIMIT_SYSCALL	1 +#endif + +/* I know for sure that these are in 2.3.35 on powerpc. But PowerPC64 does not +   support separate 64-bit syscalls, already 64-bit */ +#if __LINUX_KERNEL_VERSION >= 131875 && defined __powerpc__ \ +    && !defined __powerpc64__ +# define __ASSUME_TRUNCATE64_SYSCALL	1 +# define __ASSUME_STAT64_SYSCALL	1 +#endif + +/* Linux 2.3.39 introduced 32bit UID/GIDs.  Some platforms had 32 +   bit type all along.  */ +#if __LINUX_KERNEL_VERSION >= 131879 || defined __powerpc__ || defined __mips__ +# define __ASSUME_32BITUIDS		1 +#endif + +/* Linux 2.3.39 sparc added setresuid.  */ +#if __LINUX_KERNEL_VERSION >= 131879 && defined __sparc__ +# define __ASSUME_SETRESUID_SYSCALL	1 +#endif + +#if __LINUX_KERNEL_VERSION >= 131879 +# define __ASSUME_SETRESGID_SYSCALL	1 +#endif + +/* Linux 2.3.39 introduced IPC64.  Except for powerpc.  */ +#if __LINUX_KERNEL_VERSION >= 131879 && !defined __powerpc__ +# define __ASSUME_IPC64		1 +#endif + +/* MIPS platforms had IPC64 all along.  */ +#if defined __mips__ +# define __ASSUME_IPC64		1  #endif  /* We can use the LDTs for threading with Linux 2.3.99 and newer.  */ @@ -50,6 +153,74 @@  # define __ASSUME_LDT_WORKS		1  #endif +/* Linux 2.4.0 on PPC introduced a correct IPC64. But PowerPC64 does not +   support a separate 64-bit sys call, already 64-bit */ +#if __LINUX_KERNEL_VERSION >= 132096 && defined __powerpc__ \ +    && !defined __powerpc64__ +# define __ASSUME_IPC64			1 +#endif + +/* SH kernels got stat64, mmap2, and truncate64 during 2.4.0-test.  */ +#if __LINUX_KERNEL_VERSION >= 132096 && defined __sh__ +# define __ASSUME_TRUNCATE64_SYSCALL	1 +# define __ASSUME_MMAP2_SYSCALL		1 +# define __ASSUME_STAT64_SYSCALL	1 +#endif + +/* The changed st_ino field appeared in 2.4.0-test6.  But we cannot +   distinguish this version from other 2.4.0 releases.  Therefore play +   save and assume it available is for 2.4.1 and up.  However, SH is lame, +   and still does not have a 64-bit inode field.  */ +#if __LINUX_KERNEL_VERSION >= 132097 && !defined __alpha__ && !defined __sh__ +# define __ASSUME_ST_INO_64_BIT		1 +#endif + +/* To support locking of large files a new fcntl() syscall was introduced +   in 2.4.0-test7.  We test for 2.4.1 for the earliest version we know +   the syscall is available.  */ +#if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __sparc__) +# define __ASSUME_FCNTL64		1 +#endif + +/* The AT_CLKTCK auxiliary vector entry was introduction in the 2.4.0 +   series.  */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_AT_CLKTCK		1 +#endif + +/* Arm got fcntl64 in 2.4.4, PowerPC and SH have it also in 2.4.4 (I +   don't know when it got introduced).  But PowerPC64 does not support +   separate FCNTL64 call, FCNTL is already 64-bit */ +#if __LINUX_KERNEL_VERSION >= 132100 \ +    && (defined __arm__ || defined __powerpc__ || defined __sh__) \ +    && !defined __powerpc64__ +# define __ASSUME_FCNTL64		1 +#endif + +/* The getdents64 syscall was introduced in 2.4.0-test7.  We test for +   2.4.1 for the earliest version we know the syscall is available.  */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_GETDENTS64_SYSCALL	1 +#endif + +/* When did O_DIRECTORY became available?  Early in 2.3 but when? +   Be safe, use 2.3.99.  */ +#if __LINUX_KERNEL_VERSION >= 131939 +# define __ASSUME_O_DIRECTORY		1 +#endif + +/* Starting with one of the 2.4.0 pre-releases the Linux kernel passes +   up the page size information.  */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_AT_PAGESIZE		1 +#endif + +/* Starting with at least 2.4.0 the kernel passes the uid/gid unconditionally +   up to the child.  */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_AT_XID		1 +#endif +  /* Starting with 2.4.5 kernels PPC passes the AUXV in the standard way     and the vfork syscall made it into the official kernel.  */  #if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__ @@ -57,17 +228,72 @@  # define __ASSUME_VFORK_SYSCALL		1  #endif +/* Starting with 2.4.5 kernels the mmap2 syscall made it into the official +   kernel.  But PowerPC64 does not support a separate MMAP2 call.  */ +#if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__ \ +    && !defined __powerpc64__ +# define __ASSUME_MMAP2_SYSCALL		1 +#endif + +/* Starting with 2.4.21 PowerPC implements the new prctl syscall. +   This allows applications to get/set the Floating Point Exception Mode.  */ +#if __LINUX_KERNEL_VERSION >= (132096+21) && defined __powerpc__ +# define __ASSUME_NEW_PRCTL_SYSCALL		1 +#endif + +/* Starting with 2.4.21 the PowerPC32 clone syscall works as expected.  */ +#if __LINUX_KERNEL_VERSION >= (132096+21) && defined __powerpc__ \ +    && !defined __powerpc64__ +# define __ASSUME_FIXED_CLONE_SYSCALL		1 +#endif + +/* Starting with 2.4.21 PowerPC64 implements the new rt_sigreturn syscall. +   The new rt_sigreturn takes an ucontext pointer allowing rt_sigreturn +   to be used in the set/swapcontext implementation.  */ +#if __LINUX_KERNEL_VERSION >= (132096+21) && defined __powerpc64__ +# define __ASSUME_NEW_RT_SIGRETURN_SYSCALL		1 +#endif + +/* On x86, the set_thread_area syscall was introduced in 2.5.29, but its +   semantics was changed in 2.5.30, and again after 2.5.31.  */ +#if __LINUX_KERNEL_VERSION >= 132384 && defined __i386__ +# define __ASSUME_SET_THREAD_AREA_SYSCALL	1 +#endif +  /* The vfork syscall on x86 and arm was definitely available in 2.4.  */  #if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __arm__)  # define __ASSUME_VFORK_SYSCALL		1  #endif -/* Starting with version 2.6.4-rc1 the getdents syscall returns d_type - *    information as well and in between 2.6.5 and 2.6.8 most compat wrappers - *       were fixed too.  Except s390{,x} which was fixed in 2.6.11.  */ -#if (__LINUX_KERNEL_VERSION >= 0x020608 && !defined __s390__) \ -    || (__LINUX_KERNEL_VERSION >= 0x02060b && defined __s390__) -# define __ASSUME_GETDENTS32_D_TYPE 1 +/* There are an infinite number of PA-RISC kernel versions numbered +   2.4.0.  But they've not really been released as such.  We require +   and expect the final version here.  */ +#ifdef __hppa__ +# define __ASSUME_32BITUIDS		1 +# define __ASSUME_TRUNCATE64_SYSCALL	1 +# define __ASSUME_MMAP2_SYSCALL		1 +# define __ASSUME_STAT64_SYSCALL	1 +# define __ASSUME_IPC64			1 +# define __ASSUME_ST_INO_64_BIT		1 +# define __ASSUME_FCNTL64		1 +# define __ASSUME_GETDENTS64_SYSCALL	1 +#endif + +/* Alpha switched to a 64-bit timeval sometime before 2.2.0.  */ +#if __LINUX_KERNEL_VERSION >= 131584 && defined __alpha__ +# define __ASSUME_TIMEVAL64		1 +#endif + +#if defined __mips__ && _MIPS_SIM == _ABIN32 +# define __ASSUME_FCNTL64		1 +#endif + +/* The late 2.5 kernels saw a lot of new CLONE_* flags.  Summarize +   their availability with one define.  The changes were made first +   for i386 and the have to be done separately for the other archs. +   For i386 we pick 2.5.50 as the first version with support.  */ +#if __LINUX_KERNEL_VERSION >= 132402 && defined __i386__ +# define __ASSUME_CLONE_THREAD_FLAGS	1  #endif  /* Support for various CLOEXEC and NONBLOCK flags was added for x86, @@ -87,6 +313,137 @@  # define __ASSUME_VFORK_SYSCALL		1  #endif +/* Beginning with 2.5.63 support for realtime and monotonic clocks and +   timers based on them is available.  */ +#if __LINUX_KERNEL_VERSION >= 132415 +# define __ASSUME_POSIX_TIMERS		1 +#endif + +/* The late 2.5 kernels saw a lot of new CLONE_* flags.  Summarize +   their availability with one define.  The changes were made first +   for i386 and the have to be done separately for the other archs. +   For ia64, s390*, PPC, x86-64 we pick 2.5.64 as the first version +   with support.  */ +#if __LINUX_KERNEL_VERSION >= 132416 \ +    && (defined __ia64__ || defined __s390__ || defined __powerpc__ \ +	|| defined __x86_64__ || defined __sh__) +# define __ASSUME_CLONE_THREAD_FLAGS	1 +#endif + +/* With kernel 2.4.17 we always have netlink support.  */ +#if __LINUX_KERNEL_VERSION >= (132096+17) +# define __ASSUME_NETLINK_SUPPORT	1 +#endif + +/* The requeue futex functionality was introduced in 2.5.70.  */ +#if __LINUX_KERNEL_VERSION >= 132422 +# define __ASSUME_FUTEX_REQUEUE	1 +#endif + +/* The statfs64 syscalls are available in 2.5.74.  */ +#if __LINUX_KERNEL_VERSION >= 132426 +# define __ASSUME_STATFS64	1 +#endif + +/* Starting with at least 2.5.74 the kernel passes the setuid-like exec +   flag unconditionally up to the child.  */ +#if __LINUX_KERNEL_VERSION >= 132426 +# define __ASSUME_AT_SECURE	1 +#endif + +/* Starting with the 2.5.75 kernel the kernel fills in the correct value +   in the si_pid field passed as part of the siginfo_t struct to signal +   handlers.  */ +#if __LINUX_KERNEL_VERSION >= 132427 +# define __ASSUME_CORRECT_SI_PID	1 +#endif + +/* The tgkill syscall was instroduced for i386 in 2.5.75.  For Alpha +   it was introduced in 2.6.0-test1 which unfortunately cannot be +   distinguished from 2.6.0.  On x86-64, ppc, and ppc64 it was +   introduced in 2.6.0-test3. */ +#if (__LINUX_KERNEL_VERSION >= 132427 && defined __i386__) \ +    || (__LINUX_KERNEL_VERSION >= 132609 && defined __alpha__) \ +    || (__LINUX_KERNEL_VERSION >= 132609 && defined __x86_64__) \ +    || (__LINUX_KERNEL_VERSION >= 132609 && defined __powerpc__) \ +    || (__LINUX_KERNEL_VERSION >= 132609 && defined __sh__) +# define __ASSUME_TGKILL	1 +#endif + +/* The utimes syscall has been available for some architectures +   forever.  For x86 it was introduced after 2.5.75, for x86-64, +   ppc, and ppc64 it was introduced in 2.6.0-test3.  */ +#if defined __alpha__ || defined __ia64__ || defined __hppa__ \ +    || defined __sparc__ \ +    || (__LINUX_KERNEL_VERSION > 132427 && defined __i386__) \ +    || (__LINUX_KERNEL_VERSION > 132609 && defined __x86_64__) \ +    || (__LINUX_KERNEL_VERSION >= 132609 && defined __powerpc__) \ +    || (__LINUX_KERNEL_VERSION >= 132609 && defined __sh__) +# define __ASSUME_UTIMES	1 +#endif + +// XXX Disabled for now since the semantics we want is not achieved. +#if 0 +/* The CLONE_STOPPED flag was introduced in the 2.6.0-test1 series.  */ +#if __LINUX_KERNEL_VERSION >= 132609 +# define __ASSUME_CLONE_STOPPED	1 +#endif +#endif + +/* The fixed version of the posix_fadvise64 syscall appeared in +   2.6.0-test3.  At least for x86.  Powerpc support appeared in +   2.6.2, but for 32-bit userspace only.  */ +#if (__LINUX_KERNEL_VERSION >= 132609 && defined __i386__) \ +    || (__LINUX_KERNEL_VERSION >= 132610 && defined __powerpc__ \ +       && !defined __powerpc64__) +# define __ASSUME_FADVISE64_64_SYSCALL	1 +#endif + +/* The PROT_GROWSDOWN/PROT_GROWSUP flags were introduced in the 2.6.0-test +   series.  */ +#if __LINUX_KERNEL_VERSION >= 132609 +# define __ASSUME_PROT_GROWSUPDOWN	1 +#endif + +/* Starting with 2.6.0 PowerPC adds signal/swapcontext support for Vector +   SIMD (AKA Altivec, VMX) instructions and register state.  This changes +   the overall size of the sigcontext and adds the swapcontext syscall.  */ +#if __LINUX_KERNEL_VERSION >= 132608 && defined __powerpc__ +# define __ASSUME_SWAPCONTEXT_SYSCALL	1 +#endif + +/* The CLONE_DETACHED flag is not necessary in 2.6.2 kernels, it is +   implied.  */ +#if __LINUX_KERNEL_VERSION >= 132610 +# define __ASSUME_NO_CLONE_DETACHED	1 +#endif + +/* Starting with version 2.6.4-rc1 the getdents syscall returns d_type +   information as well and in between 2.6.5 and 2.6.8 most compat wrappers +   were fixed too.  Except s390{,x} which was fixed in 2.6.11.  */ +#if (__LINUX_KERNEL_VERSION >= 0x020608 && !defined __s390__) \ +    || (__LINUX_KERNEL_VERSION >= 0x02060b && defined __s390__) +# define __ASSUME_GETDENTS32_D_TYPE	1 +#endif + +/* Starting with version 2.5.3, the initial location returned by `brk' +   after exec is always rounded up to the next page.  */ +#if __LINUX_KERNEL_VERSION >= 132355 +# define __ASSUME_BRK_PAGE_ROUNDED	1 +#endif + +/* Starting with version 2.6.9, the waitid system call is available. +   Except for powerpc and powerpc64, where it is available in 2.6.12.  */ +#if (__LINUX_KERNEL_VERSION >= 0x020609 && !defined __powerpc__) \ +    || (__LINUX_KERNEL_VERSION >= 0x02060c && defined __powerpc__) +# define __ASSUME_WAITID_SYSCALL	1 +#endif + +/* Starting with version 2.6.9, SSI_IEEE_RAISE_EXCEPTION exists.  */ +#if __LINUX_KERNEL_VERSION >= 0x020609 && defined __alpha__ +#define __ASSUME_IEEE_RAISE_EXCEPTION	1 +#endif +  /* This header was added somewhere around 2.6.13  */  #if __LINUX_KERNEL_VERSION >= 132621  # define HAVE_LINUX_CPUMASK_H	1 diff --git a/libc/sysdeps/linux/common/bits/kernel_sigaction.h b/libc/sysdeps/linux/common/bits/kernel_sigaction.h index f74e0a28a..0a35ac8cb 100644 --- a/libc/sysdeps/linux/common/bits/kernel_sigaction.h +++ b/libc/sysdeps/linux/common/bits/kernel_sigaction.h @@ -25,12 +25,12 @@ struct old_kernel_sigaction {   */  extern int __syscall_sigaction(int, const struct old_kernel_sigaction *, -	struct old_kernel_sigaction *) attribute_hidden; +	struct old_kernel_sigaction *);  #endif  extern int __syscall_rt_sigaction(int, const struct sigaction *, -	struct sigaction *, size_t) attribute_hidden; +	struct sigaction *, size_t);  #endif /* _BITS_SIGACTION_STRUCT_H */ diff --git a/libc/sysdeps/linux/common/bits/uClibc_mutex.h b/libc/sysdeps/linux/common/bits/uClibc_mutex.h index 14aeb9c80..c6094c3d2 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_mutex.h +++ b/libc/sysdeps/linux/common/bits/uClibc_mutex.h @@ -62,7 +62,55 @@  #define __UCLIBC_MUTEX_UNLOCK(M)									\          __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) -#else +#ifdef __USE_STDIO_FUTEXES__ + +#include <bits/stdio-lock.h> + +#define __UCLIBC_IO_MUTEX(M)			_IO_lock_t M +#define __UCLIBC_IO_MUTEX_LOCK(M) 		_IO_lock_lock(M) +#define __UCLIBC_IO_MUTEX_UNLOCK(M) 	_IO_lock_unlock(M) +#define __UCLIBC_IO_MUTEX_TRYLOCK(M) 	_IO_lock_trylock(M) +#define __UCLIBC_IO_MUTEX_INIT(M) 	_IO_lock_t M = _IO_lock_initializer +#define __UCLIBC_IO_MUTEX_EXTERN(M)		extern _IO_lock_t M + +#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C)		\ +	if (C) {										\ +		_IO_lock_lock(M);							\ +	} + +#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C)	\ +	if (C) {										\ +		_IO_lock_unlock(M);							\ +	} + +#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V)			\ +		__UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,((A=(V))) == 0) + +#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A)			\ +		__UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,((A) == 0)) + +#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M)		_IO_lock_lock(M) +#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M) 	_IO_lock_unlock(M) + +#else /* of __USE_STDIO_FUTEXES__ */ + +#define __UCLIBC_IO_MUTEX(M)                        __UCLIBC_MUTEX(M) +#define __UCLIBC_IO_MUTEX_LOCK(M)                   __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_UNLOCK(M)                 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) +#define __UCLIBC_IO_MUTEX_TRYLOCK(M)                __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_INIT(M)                   __UCLIBC_MUTEX_INIT(M, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +#define __UCLIBC_IO_MUTEX_EXTERN(M)                 __UCLIBC_MUTEX_EXTERN(M) +#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V)          __UCLIBC_MUTEX_AUTO_LOCK(M,A,V) +#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A)          __UCLIBC_MUTEX_AUTO_UNLOCK(M,A) +#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M)     __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M)   __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C)     __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C)   __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) + +#endif /* of __USE_STDIO_FUTEXES__ */ + + +#else /* of __UCLIBC_HAS_THREADS__ */  #define __UCLIBC_MUTEX(M)				void *__UCLIBC_MUTEX_DUMMY_ ## M  #define __UCLIBC_MUTEX_INIT(M,I)			extern void *__UCLIBC_MUTEX_DUMMY_ ## M @@ -83,6 +131,22 @@  #define __UCLIBC_MUTEX_LOCK(M)				((void)0)  #define __UCLIBC_MUTEX_UNLOCK(M)			((void)0) -#endif +#define __UCLIBC_IO_MUTEX(M)                        __UCLIBC_MUTEX(M) +#define __UCLIBC_IO_MUTEX_LOCK(M)                   __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_UNLOCK(M)                 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) +#define __UCLIBC_IO_MUTEX_TRYLOCK(M)                __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_INIT(M)                   __UCLIBC_MUTEX_INIT(M, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +#define __UCLIBC_IO_MUTEX_EXTERN(M)                 __UCLIBC_MUTEX_EXTERN(M) +#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V)          __UCLIBC_MUTEX_AUTO_LOCK(M,A,V) +#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A)          __UCLIBC_MUTEX_AUTO_UNLOCK(M,A) +#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M)     __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M)   __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C)     __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C)   __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) + +#endif /* of __UCLIBC_HAS_THREADS__ */ + +#define __UCLIBC_IO_MUTEX_TRYLOCK_CANCEL_UNSAFE(M)	\ +		__UCLIBC_IO_MUTEX_TRYLOCK(M)  #endif /* _UCLIBC_MUTEX_H */ diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h index 3631ef79f..a8cf4eb56 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h +++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h @@ -134,26 +134,26 @@          __UCLIBC_MUTEX_AUTO_LOCK_VAR(__infunc_user_locking)  #define __STDIO_AUTO_THREADLOCK(__stream)					\ -        __UCLIBC_MUTEX_AUTO_LOCK((__stream)->__lock, __infunc_user_locking,	\ +        __UCLIBC_IO_MUTEX_AUTO_LOCK((__stream)->__lock, __infunc_user_locking,	\  	(__stream)->__user_locking)  #define __STDIO_AUTO_THREADUNLOCK(__stream)					\ -        __UCLIBC_MUTEX_AUTO_UNLOCK((__stream)->__lock, __infunc_user_locking) +        __UCLIBC_IO_MUTEX_AUTO_UNLOCK((__stream)->__lock, __infunc_user_locking)  #define __STDIO_ALWAYS_THREADLOCK(__stream)					\ -        __UCLIBC_MUTEX_LOCK((__stream)->__lock) +        __UCLIBC_IO_MUTEX_LOCK((__stream)->__lock)  #define __STDIO_ALWAYS_THREADUNLOCK(__stream)					\ -        __UCLIBC_MUTEX_UNLOCK((__stream)->__lock) +        __UCLIBC_IO_MUTEX_UNLOCK((__stream)->__lock)  #define __STDIO_ALWAYS_THREADLOCK_CANCEL_UNSAFE(__stream)			\ -        __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE((__stream)->__lock) +        __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE((__stream)->__lock)  #define __STDIO_ALWAYS_THREADTRYLOCK_CANCEL_UNSAFE(__stream)			\ -        __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE((__stream)->__lock) +        __UCLIBC_IO_MUTEX_TRYLOCK_CANCEL_UNSAFE((__stream)->__lock)  #define __STDIO_ALWAYS_THREADUNLOCK_CANCEL_UNSAFE(__stream)			\ -        __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE((__stream)->__lock) +        __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE((__stream)->__lock)  #ifdef __UCLIBC_HAS_THREADS__  #define __STDIO_SET_USER_LOCKING(__stream)	((__stream)->__user_locking = 1) @@ -161,6 +161,14 @@  #define __STDIO_SET_USER_LOCKING(__stream)		((void)0)  #endif +#ifdef __UCLIBC_HAS_THREADS__ +#ifdef __USE_STDIO_FUTEXES__ +#define STDIO_INIT_MUTEX(M) _IO_lock_init(M) +#else +#define STDIO_INIT_MUTEX(M) __stdio_init_mutex(& M) +#endif +#endif +  /**********************************************************************/  #define __STDIO_IOFBF 0		/* Fully buffered.  */ @@ -275,7 +283,7 @@ struct __STDIO_FILE_STRUCT {  #endif  #ifdef __UCLIBC_HAS_THREADS__  	int __user_locking; -	__UCLIBC_MUTEX(__lock); +	__UCLIBC_IO_MUTEX(__lock);  #endif  /* Everything after this is unimplemented... and may be trashed. */  #if __STDIO_BUILTIN_BUF_SIZE > 0 @@ -351,9 +359,9 @@ extern void _stdio_term(void) attribute_hidden;  extern struct __STDIO_FILE_STRUCT *_stdio_openlist;  #ifdef __UCLIBC_HAS_THREADS__ -__UCLIBC_MUTEX_EXTERN(_stdio_openlist_add_lock); +__UCLIBC_IO_MUTEX_EXTERN(_stdio_openlist_add_lock);  #ifdef __STDIO_BUFFERS -__UCLIBC_MUTEX_EXTERN(_stdio_openlist_del_lock); +__UCLIBC_IO_MUTEX_EXTERN(_stdio_openlist_del_lock);  extern volatile int _stdio_openlist_use_count; /* _stdio_openlist_del_lock */  extern int _stdio_openlist_del_count; /* _stdio_openlist_del_lock */  #endif diff --git a/libc/sysdeps/linux/common/fsync.c b/libc/sysdeps/linux/common/fsync.c index 774efc9ce..711811f23 100644 --- a/libc/sysdeps/linux/common/fsync.c +++ b/libc/sysdeps/linux/common/fsync.c @@ -10,9 +10,28 @@  #include <sys/syscall.h>  #include <unistd.h> -#ifdef __LINUXTHREADS_OLD__ -extern __typeof(fsync) weak_function fsync; -strong_alias(fsync,__libc_fsync) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include "sysdep-cancel.h" +#else +#define SINGLE_THREAD_P 1  #endif -_syscall1(int, fsync, int, fd) +#define __NR___syscall_fsync __NR_fsync +static inline _syscall1(int, __syscall_fsync, int, fd) + +extern __typeof(fsync) __libc_fsync; + +int __libc_fsync(int fd) +{ +	if (SINGLE_THREAD_P) +		return __syscall_fsync(fd); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	int result = __syscall_fsync(fd); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif +} + +weak_alias(__libc_fsync, fsync) diff --git a/libc/sysdeps/linux/common/ioctl.c b/libc/sysdeps/linux/common/ioctl.c index 7ac8f16c2..f2f0f539a 100644 --- a/libc/sysdeps/linux/common/ioctl.c +++ b/libc/sysdeps/linux/common/ioctl.c @@ -11,20 +11,36 @@  #include <stdarg.h>  #include <sys/ioctl.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif + +libc_hidden_proto(ioctl)  #define __NR___syscall_ioctl __NR_ioctl  static __always_inline -_syscall3(int, __syscall_ioctl, int, fd, int, request, void *, arg) +_syscall3(int, __syscall_ioctl, int, fd, unsigned long int, request, void *, arg)  int ioctl(int fd, unsigned long int request, ...)  { -    void *arg; -    va_list list; +	void *arg; +	va_list list; + +	va_start(list, request); +	arg = va_arg(list, void *); + +	va_end(list); -    va_start(list, request); -    arg = va_arg(list, void *); -    va_end(list); +	if (SINGLE_THREAD_P) +		return __syscall_ioctl(fd, request, arg); -    return __syscall_ioctl(fd, request, arg); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	int result = __syscall_ioctl(fd, request, arg); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif  }  libc_hidden_def(ioctl) diff --git a/libc/sysdeps/linux/common/msync.c b/libc/sysdeps/linux/common/msync.c index 7a46f0c32..2629bd4aa 100644 --- a/libc/sysdeps/linux/common/msync.c +++ b/libc/sysdeps/linux/common/msync.c @@ -9,16 +9,33 @@  #include <sys/syscall.h>  #include <unistd.h> +#include <sys/mman.h> -#if defined __NR_msync && defined __ARCH_USE_MMU__ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif -#include <sys/mman.h> +#define __NR___syscall_msync __NR_msync +static __always_inline _syscall3(int, __syscall_msync, void *, addr, size_t, length, +						int, flags) -#ifdef __LINUXTHREADS_OLD__ -extern __typeof(msync) weak_function msync; -strong_alias(msync,__libc_msync) +extern __typeof(msync) __libc_msync; +int __libc_msync(void * addr, size_t length, int flags) +{ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype, result;  #endif -_syscall3(int, msync, void *, addr, size_t, length, int, flags) +	if (SINGLE_THREAD_P) +		return __syscall_msync(addr, length, flags); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	oldtype = LIBC_CANCEL_ASYNC (); +	result = __syscall_msync(addr, length, flags); +	LIBC_CANCEL_RESET (oldtype); +	return result;  #endif +} +weak_alias(__libc_msync,msync) diff --git a/libc/sysdeps/linux/common/nanosleep.c b/libc/sysdeps/linux/common/nanosleep.c index 0849127db..0be59c511 100644 --- a/libc/sysdeps/linux/common/nanosleep.c +++ b/libc/sysdeps/linux/common/nanosleep.c @@ -10,13 +10,32 @@  #include <sys/syscall.h>  #include <time.h> -#if defined __USE_POSIX199309 && defined __NR_nanosleep -_syscall2(int, nanosleep, const struct timespec *, req, -		  struct timespec *, rem) -#ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(nanosleep) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#include <pthreadP.h>  #else -libc_hidden_weak(nanosleep) -strong_alias(nanosleep,__libc_nanosleep) +#define SINGLE_THREAD_P 1  #endif + +#define __NR___syscall_nanosleep __NR_nanosleep +static inline _syscall2(int, __syscall_nanosleep, const struct timespec *, req, +						struct timespec *, rem); + +extern __typeof(nanosleep) __libc_nanosleep; + +int __libc_nanosleep(const struct timespec *req, struct timespec *rem) +{ +	if (SINGLE_THREAD_P) +		return __syscall_nanosleep(req, rem); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	int result = __syscall_nanosleep(req, rem); +	LIBC_CANCEL_RESET (oldtype); +	return result;  #endif +} + +libc_hidden_proto(nanosleep) +weak_alias(__libc_nanosleep,nanosleep) +libc_hidden_weak(nanosleep) diff --git a/libc/sysdeps/linux/common/not-cancel.h b/libc/sysdeps/linux/common/not-cancel.h new file mode 100644 index 000000000..ebdc6078d --- /dev/null +++ b/libc/sysdeps/linux/common/not-cancel.h @@ -0,0 +1,19 @@ +/* By default we have none.  Map the name to the normal functions.  */ +#define open_not_cancel(name, flags, mode) \ +  open (name, flags, mode) +#define open_not_cancel_2(name, flags) \ +  open (name, flags) +#define close_not_cancel(fd) \ +  close (fd) +#define close_not_cancel_no_status(fd) \ +  (void) close (fd) +#define read_not_cancel(fd, buf, n) \ +  read (fd, buf, n) +#define write_not_cancel(fd, buf, n) \ +  write (fd, buf, n) +#define writev_not_cancel_no_status(fd, iov, n) \ +  (void) writev (fd, iov, n) +#define fcntl_not_cancel(fd, cmd, val) \ +  fcntl (fd, cmd, val) +# define waitpid_not_cancel(pid, stat_loc, options) \ +  waitpid (pid, stat_loc, options) diff --git a/libc/sysdeps/linux/common/open64.c b/libc/sysdeps/linux/common/open64.c index cfe471c64..c1f5400b8 100644 --- a/libc/sysdeps/linux/common/open64.c +++ b/libc/sysdeps/linux/common/open64.c @@ -7,6 +7,10 @@  #include <features.h>  #include <fcntl.h>  #include <stdarg.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <errno.h> +#include <sysdep-cancel.h> +#endif  #ifdef __UCLIBC_HAS_LFS__ @@ -28,7 +32,20 @@ int open64 (const char *file, int oflag, ...)  	va_end (arg);      } -    return open(file, oflag | O_LARGEFILE, mode); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +  if (SINGLE_THREAD_P) +    return INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode); + +  int oldtype = LIBC_CANCEL_ASYNC (); + +  int result = INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode); + +  LIBC_CANCEL_RESET (oldtype); + +  return result; +#else +  return open(file, oflag | O_LARGEFILE, mode); +#endif  }  #ifndef __LINUXTHREADS_OLD__  libc_hidden_def(open64) diff --git a/libc/sysdeps/linux/common/pause.c b/libc/sysdeps/linux/common/pause.c index 19ba30706..cd0ea4a77 100644 --- a/libc/sysdeps/linux/common/pause.c +++ b/libc/sysdeps/linux/common/pause.c @@ -10,18 +10,30 @@  #define __UCLIBC_HIDE_DEPRECATED__  #include <sys/syscall.h>  #include <unistd.h> -#include <signal.h> -#ifdef __LINUXTHREADS_OLD__ -extern __typeof(pause) weak_function pause; -strong_alias(pause, __libc_pause) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h>  #endif -#ifdef __NR_pause -_syscall0(int, pause) -#else -int pause(void) +#include <signal.h> + +/* Suspend the process until a signal arrives. +   This always returns -1 and sets errno to EINTR.  */ +int +__libc_pause (void)  { -	return __sigpause(sigblock(0), 0); +  sigset_t set; + +  __sigemptyset (&set); +  sigprocmask (SIG_BLOCK, NULL, &set); + +  /* pause is a cancellation point, but so is sigsuspend. +     So no need for anything special here.  */ + +  return sigsuspend (&set);  } +weak_alias (__libc_pause, pause) + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +LIBC_CANCEL_HANDLED ();		/* sigsuspend handles our cancellation.  */  #endif diff --git a/libc/sysdeps/linux/common/poll.c b/libc/sysdeps/linux/common/poll.c index 4a6f06e19..f50e92c8e 100644 --- a/libc/sysdeps/linux/common/poll.c +++ b/libc/sysdeps/linux/common/poll.c @@ -20,30 +20,33 @@  #include <sys/syscall.h>  #include <sys/poll.h> -#ifdef __NR_poll +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif -_syscall3(int, poll, struct pollfd *, fds, -	unsigned long int, nfds, int, timeout) +libc_hidden_proto(poll) -#elif defined(__NR_ppoll) && defined __UCLIBC_LINUX_SPECIFIC__ +#ifdef __NR_poll + +#define __NR___syscall_poll __NR_poll +static inline _syscall3(int, __syscall_poll, struct pollfd *, fds, +			unsigned long int, nfds, int, timeout);  int poll(struct pollfd *fds, nfds_t nfds, int timeout)  { -	struct timespec *ts = NULL, tval; -	if (timeout > 0) { -		tval.tv_sec = timeout / 1000; -		tval.tv_nsec = (timeout % 1000) * 1000000; -		ts = &tval; -	} else if (timeout == 0) { -		tval.tv_sec = 0; -		tval.tv_nsec = 0; -		ts = &tval; -	} -	return ppoll(fds, nfds, ts, NULL); +    if (SINGLE_THREAD_P) +	return __syscall_poll(fds, nfds, timeout); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +    int oldtype = LIBC_CANCEL_ASYNC (); +    int result = __syscall_poll(fds, nfds, timeout); +    LIBC_CANCEL_RESET (oldtype); +    return result; +#endif  } - -#else -/* ugh, this arch lacks poll, so we need to emulate this crap ... */ +#else /* !__NR_poll */  #include <alloca.h>  #include <sys/types.h> @@ -53,6 +56,9 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout)  #include <sys/param.h>  #include <unistd.h> +libc_hidden_proto(getdtablesize) +libc_hidden_proto(select) +  /* uClinux 2.0 doesn't have poll, emulate it using select */  /* Poll the file descriptors described by the NFDS structures starting at @@ -220,10 +226,4 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout)  }  #endif - -#ifndef __LINUXTHREADS_OLD__  libc_hidden_def(poll) -#else -libc_hidden_weak(poll) -strong_alias(poll,__libc_poll) -#endif diff --git a/libc/sysdeps/linux/common/pselect.c b/libc/sysdeps/linux/common/pselect.c index 63ab0dbb1..7e93537dd 100644 --- a/libc/sysdeps/linux/common/pselect.c +++ b/libc/sysdeps/linux/common/pselect.c @@ -22,9 +22,12 @@  #include <stddef.h>	/* For NULL.  */  #include <sys/time.h>  #include <sys/select.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#endif -extern __typeof(pselect) __libc_pselect; - +libc_hidden_proto(sigprocmask) +libc_hidden_proto(select)  /* Check the first NFDS descriptors each in READFDS (if not NULL) for read @@ -33,8 +36,13 @@ extern __typeof(pselect) __libc_pselect;     after waiting the interval specified therein.  Additionally set the sigmask     SIGMASK for this call.  Returns the number of ready descriptors, or -1 for     errors.  */ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +static int +__pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, +#else  int -__libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, +pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, +#endif  	   const struct timespec *timeout, const sigset_t *sigmask)  {    struct timeval tval; @@ -64,4 +72,23 @@ __libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,    return retval;  } -weak_alias(__libc_pselect,pselect) + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +int +pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, +	   const struct timespec *timeout, const sigset_t *sigmask) +{ +	if (SINGLE_THREAD_P) +		return __pselect (nfds, readfds, writefds, exceptfds, +				  timeout, sigmask); + +	int oldtype = LIBC_CANCEL_ASYNC (); + +	int result = __pselect (nfds, readfds, writefds, exceptfds, +				 timeout, sigmask); + +	LIBC_CANCEL_RESET (oldtype); + +	return result; +} +#endif diff --git a/libc/sysdeps/linux/common/readv.c b/libc/sysdeps/linux/common/readv.c index 3c40a0d8d..fce396d5f 100644 --- a/libc/sysdeps/linux/common/readv.c +++ b/libc/sysdeps/linux/common/readv.c @@ -2,7 +2,8 @@  /*   * readv() for uClibc   * - * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com> + * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>   *   * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.   */ @@ -10,5 +11,40 @@  #include <sys/syscall.h>  #include <sys/uio.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> + +/* We should deal with kernel which have a smaller UIO_FASTIOV as well +   as a very big count.  */ +static ssize_t __readv (int fd, const struct iovec *vector, int count) +{ +  ssize_t bytes_read; + +  bytes_read = INLINE_SYSCALL (readv, 3, fd, vector, count); + +  if (bytes_read >= 0 || errno != EINVAL || count <= UIO_FASTIOV) +    return bytes_read; + +  /* glibc tries again, but we do not. */ +  //return __atomic_readv_replacement (fd, vector, count); + +  return -1; +} + +ssize_t readv (int fd, const struct iovec *vector, int count) +{ +  if (SINGLE_THREAD_P) +    return __readv (fd, vector, count); + +  int oldtype = LIBC_CANCEL_ASYNC (); + +  int result = __readv (fd, vector, count); + +  LIBC_CANCEL_RESET (oldtype); + +  return result; +} +#else  _syscall3(ssize_t, readv, int, filedes, const struct iovec *, vector,  		  int, count) +#endif diff --git a/libc/sysdeps/linux/common/select.c b/libc/sysdeps/linux/common/select.c index caff28d7c..0c2d91984 100644 --- a/libc/sysdeps/linux/common/select.c +++ b/libc/sysdeps/linux/common/select.c @@ -11,15 +11,21 @@  #include <sys/select.h>  #include <stdint.h> -extern __typeof(select) __libc_select; +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif  #define USEC_PER_SEC 1000000L +extern __typeof(select) __libc_select; +  #if !defined(__NR__newselect) && !defined(__NR_select) && defined __USE_XOPEN2K  # define __NR___libc_pselect6 __NR_pselect6  _syscall6(int, __libc_pselect6, int, n, fd_set *, readfds, fd_set *, writefds, -	fd_set *, exceptfds, const struct timespec *, timeout, -	const sigset_t *, sigmask) +        fd_set *, exceptfds, const struct timespec *, timeout, +        const sigset_t *, sigmask)  int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,                    struct timeval *timeout) @@ -30,12 +36,12 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,  		_ts.tv_sec = timeout->tv_sec;  		/* GNU extension: allow for timespec values where the sub-sec -		 * field is equal to or more than 1 second.  The kernel will -		 * reject this on us, so take care of the time shift ourself. -		 * Some applications (like readline and linphone) do this. -		 * See 'clarification on select() type calls and invalid timeouts' -		 * on the POSIX general list for more information. -		 */ +		* field is equal to or more than 1 second.  The kernel will +		* reject this on us, so take care of the time shift ourself. +		* Some applications (like readline and linphone) do this. +		* See 'clarification on select() type calls and invalid timeouts' +		* on the POSIX general list for more information. +		*/  		usec = timeout->tv_usec;  		if (usec >= USEC_PER_SEC) {  			_ts.tv_sec += usec / USEC_PER_SEC; @@ -46,18 +52,41 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,  		ts = &_ts;  	} -	return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0); +	if (SINGLE_THREAD_P) +		return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	int result = __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif +  }  #else  #ifdef __NR__newselect -# define __NR___libc_select __NR__newselect +# define __NR___syscall_select __NR__newselect  #else -# define __NR___libc_select __NR_select +# define __NR___syscall_select __NR_select  #endif -_syscall5(int, __libc_select, int, n, fd_set *, readfds, fd_set *, writefds, -		  fd_set *, exceptfds, struct timeval *, timeout) + +_syscall5(int, __syscall_select, int, n, fd_set *, readfds, +		fd_set *, writefds, fd_set *, exceptfds, struct timeval *, timeout); + +int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, +                  struct timeval *timeout) +{ +	if (SINGLE_THREAD_P) +		return __syscall_select(n, readfds, writefds, exceptfds, timeout); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	int result = __syscall_select(n, readfds, writefds, exceptfds, timeout); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif +}  #endif diff --git a/libc/sysdeps/linux/common/sigprocmask.c b/libc/sysdeps/linux/common/sigprocmask.c index 13bb2beb7..011d7b367 100644 --- a/libc/sysdeps/linux/common/sigprocmask.c +++ b/libc/sysdeps/linux/common/sigprocmask.c @@ -14,6 +14,7 @@  #undef sigprocmask +libc_hidden_proto(sigprocmask)  #ifdef __NR_rt_sigprocmask @@ -24,20 +25,28 @@ _syscall4(int, __rt_sigprocmask, int, how, const sigset_t *, set,  int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)  { -	if (set && -# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2) -		(((unsigned int) how) > 2) -# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3) -		(((unsigned int)(how-1)) > 2) -# else -#  warning "compile time assumption violated.. slow path..." -		((how != SIG_BLOCK) && (how != SIG_UNBLOCK) -		 && (how != SIG_SETMASK)) +#ifdef SIGCANCEL +	sigset_t local_newmask; + +	/* +	 * The only thing we have to make sure here is that SIGCANCEL and +	 * SIGSETXID are not blocked. +	 */ +	if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID +		|| __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif +		)) +	{ +		local_newmask = *set; +		__sigdelset (&local_newmask, SIGCANCEL); +# ifdef SIGSETXID +		__sigdelset (&local_newmask, SIGSETXID);  # endif -		) { -		__set_errno(EINVAL); -		return -1; +		set = &local_newmask;  	} +#endif +  	return __rt_sigprocmask(how, set, oldset, _NSIG / 8);  } @@ -51,20 +60,28 @@ _syscall3(int, __syscall_sigprocmask, int, how, const sigset_t *, set,  int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)  { -	if (set && -# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2) -		(((unsigned int) how) > 2) -# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3) -		(((unsigned int)(how-1)) > 2) -# else -#  warning "compile time assumption violated.. slow path..." -		((how != SIG_BLOCK) && (how != SIG_UNBLOCK) -		 && (how != SIG_SETMASK)) +#ifdef SIGCANCEL +	sigset_t local_newmask; + +	/* +	 * The only thing we have to make sure here is that SIGCANCEL and +	 * SIGSETXID are not blocked. +	 */ +	if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID +		|| __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif +		)) +	{ +		local_newmask = *set; +		__sigdelset (&local_newmask, SIGCANCEL); +# ifdef SIGSETXID +		__sigdelset (&local_newmask, SIGSETXID);  # endif -		) { -		__set_errno(EINVAL); -		return -1; +		set = &local_newmask;  	} +#endif +  	return (__syscall_sigprocmask(how, set, oldset));  }  #endif diff --git a/libc/sysdeps/linux/common/sigsuspend.c b/libc/sysdeps/linux/common/sigsuspend.c index 3648e76b5..789eeda89 100644 --- a/libc/sysdeps/linux/common/sigsuspend.c +++ b/libc/sysdeps/linux/common/sigsuspend.c @@ -11,27 +11,49 @@  #if defined __USE_POSIX  #include <signal.h> +#undef sigsuspend -extern __typeof(sigsuspend) __libc_sigsuspend; +libc_hidden_proto(sigsuspend)  #ifdef __NR_rt_sigsuspend  # define __NR___rt_sigsuspend __NR_rt_sigsuspend -static __inline__ _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size) -int __libc_sigsuspend(const sigset_t * mask) +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#  include <errno.h> +#  include <sysdep-cancel.h> + +/* Change the set of blocked signals to SET, +   wait until a signal arrives, and restore the set of blocked signals.  */ +int sigsuspend (const sigset_t *set) +{ +	if (SINGLE_THREAD_P) +		return INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8); + +	int oldtype = LIBC_CANCEL_ASYNC (); + +	int result = INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8); + +	LIBC_CANCEL_RESET (oldtype); + +	return result; +} +# else +static inline _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size); + +int sigsuspend(const sigset_t * mask)  {  	return __rt_sigsuspend(mask, _NSIG / 8);  } +# endif  #else  # define __NR___syscall_sigsuspend __NR_sigsuspend  static __inline__ _syscall3(int, __syscall_sigsuspend, int, a, unsigned long int, b,  		  unsigned long int, c) -int __libc_sigsuspend(const sigset_t * set) +int sigsuspend(const sigset_t * set)  {  	return __syscall_sigsuspend(0, 0, set->__val[0]);  }  #endif -weak_alias(__libc_sigsuspend,sigsuspend) -libc_hidden_weak(sigsuspend) +libc_hidden_def(sigsuspend)  #endif diff --git a/libc/sysdeps/linux/common/wait.c b/libc/sysdeps/linux/common/wait.c index b16495314..d4b79bd37 100644 --- a/libc/sysdeps/linux/common/wait.c +++ b/libc/sysdeps/linux/common/wait.c @@ -1,23 +1,43 @@  /* + * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>   * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>   *   * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.   */ -  #include <stdlib.h>  #include <syscall.h>  #include <sys/types.h>  #include <sys/wait.h>  #include <sys/resource.h> -#ifdef __LINUXTHREADS_OLD__ -extern __typeof(wait) weak_function wait; -strong_alias(wait,__libc_wait) -#endif +/* Wait for a child to die.  When one does, put its status in *STAT_LOC + * and return its process ID.  For errors, return (pid_t) -1.  */ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <errno.h> +#include <sysdep-cancel.h> + +pid_t attribute_hidden +__libc_wait (__WAIT_STATUS_DEFN stat_loc) +{ +  if (SINGLE_THREAD_P) +    return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0, +			   (struct rusage *) NULL); +  int oldtype = LIBC_CANCEL_ASYNC (); + +  pid_t result = INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0, +				 (struct rusage *) NULL); + +  LIBC_CANCEL_RESET (oldtype); + +  return result; +} +#else  /* Wait for a child to die.  When one does, put its status in *STAT_LOC   * and return its process ID.  For errors, return (pid_t) -1.  */ -__pid_t wait(__WAIT_STATUS_DEFN stat_loc) +__pid_t __libc_wait (__WAIT_STATUS_DEFN stat_loc)  { -	return wait4(WAIT_ANY, stat_loc, 0, NULL); +      return wait4 (WAIT_ANY, stat_loc, 0, (struct rusage *) NULL);  } +#endif +weak_alias(__libc_wait,wait) diff --git a/libc/sysdeps/linux/common/waitpid.c b/libc/sysdeps/linux/common/waitpid.c index e46499377..d0437194d 100644 --- a/libc/sysdeps/linux/common/waitpid.c +++ b/libc/sysdeps/linux/common/waitpid.c @@ -1,5 +1,6 @@  /* vi: set sw=4 ts=4: */  /* + * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com>   * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>   *   * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. @@ -10,13 +11,27 @@  #include <sys/wait.h>  #include <sys/resource.h> -__pid_t waitpid(__pid_t pid, int *wait_stat, int options) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include "sysdep-cancel.h" +#else +#define SINGLE_THREAD_P 1 +#endif + +libc_hidden_proto(wait4) + +extern __typeof(waitpid) __libc_waitpid; +__pid_t __libc_waitpid(__pid_t pid, int *wait_stat, int options)  { -	return wait4(pid, wait_stat, options, NULL); +	if (SINGLE_THREAD_P) +		return wait4(pid, wait_stat, options, NULL); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	int result = wait4(pid, wait_stat, options, NULL); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif  } -#ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(waitpid) -#else +libc_hidden_proto(waitpid) +weak_alias(__libc_waitpid,waitpid)  libc_hidden_weak(waitpid) -strong_alias(waitpid,__libc_waitpid) -#endif diff --git a/libc/sysdeps/linux/common/writev.c b/libc/sysdeps/linux/common/writev.c index 99de7e43d..bd0e4077d 100644 --- a/libc/sysdeps/linux/common/writev.c +++ b/libc/sysdeps/linux/common/writev.c @@ -10,5 +10,41 @@  #include <sys/syscall.h>  #include <sys/uio.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <errno.h> +#include <sysdep-cancel.h> + +/* We should deal with kernel which have a smaller UIO_FASTIOV as well +   as a very big count.  */ +static ssize_t __writev (int fd, const struct iovec *vector, int count) +{ +  ssize_t bytes_written; + +  bytes_written = INLINE_SYSCALL (writev, 3, fd, vector, count); + +  if (bytes_written >= 0 || errno != EINVAL || count <= UIO_FASTIOV) +    return bytes_written; + +  /* glibc tries again, but we do not. */ +  /* return __atomic_writev_replacement (fd, vector, count); */ + +  return -1; +} + +ssize_t writev (int fd, const struct iovec *vector, int count) +{ +  if (SINGLE_THREAD_P) +    return __writev (fd, vector, count); + +  int oldtype = LIBC_CANCEL_ASYNC (); + +  ssize_t result = __writev (fd, vector, count); + +  LIBC_CANCEL_RESET (oldtype); + +  return result; +} +#else  _syscall3(ssize_t, writev, int, filedes, const struct iovec *, vector,  		  int, count) +#endif diff --git a/libc/sysdeps/linux/i386/Makefile.arch b/libc/sysdeps/linux/i386/Makefile.arch index 2bf2b7607..668cca742 100644 --- a/libc/sysdeps/linux/i386/Makefile.arch +++ b/libc/sysdeps/linux/i386/Makefile.arch @@ -5,8 +5,17 @@  # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.  # -CSRC := brk.c sigaction.c __syscall_error.c +CSRC := brk.c __syscall_error.c + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +endif  SSRC := \ -	__longjmp.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ +	__longjmp.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \  	sync_file_range.S syscall.S mmap.S mmap64.S posix_fadvise64.S + + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +SSRC += vfork.S clone.S +endif diff --git a/libc/sysdeps/linux/i386/bits/syscalls.h b/libc/sysdeps/linux/i386/bits/syscalls.h index 23d872a29..f9ea54ac7 100644 --- a/libc/sysdeps/linux/i386/bits/syscalls.h +++ b/libc/sysdeps/linux/i386/bits/syscalls.h @@ -102,7 +102,7 @@ __asm__ (".L__X'%ebx = 1\n\t"      "int $0x80\n\t"                                                           \      RESTOREARGS_##nr                                                          \      : "=a" (resultvar)                                                        \ -    : "i" (name) ASMFMT_##nr(args) : "memory", "cc");                         \ +    : "g" (name) ASMFMT_##nr(args) : "memory", "cc");                         \       (int) resultvar; })  #define LOADARGS_0 diff --git a/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h b/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h index deeec03d5..536e9c155 100644 --- a/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h @@ -37,7 +37,7 @@  #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__  /* define if target supports CFI pseudo ops */ -#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ +#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__  /* define if target supports IEEE signed zero floats */  #define __UCLIBC_HAVE_SIGNED_ZERO__ diff --git a/libc/sysdeps/linux/i386/clone.S b/libc/sysdeps/linux/i386/clone.S index 14fc25ca1..a7de3fe27 100644 --- a/libc/sysdeps/linux/i386/clone.S +++ b/libc/sysdeps/linux/i386/clone.S @@ -79,7 +79,10 @@ clone:  	movl	%eax,8(%ecx)  	/* Don't leak any information.  */  	movl	$0,4(%ecx) +#ifndef RESET_PID  	movl	$0,(%ecx) +#endif +  	/* Do the system call */  	pushl	%ebx @@ -90,6 +93,10 @@ clone:  	movl	FLAGS+12(%esp),%ebx  	movl	CTID+12(%esp),%edi  	movl	$__NR_clone,%eax +#ifdef RESET_PID +	/* Remember the flag value.  */ +	movl	%ebx, (%ecx) +#endif  	int	$0x80  	popl	%edi  	popl	%esi @@ -121,3 +128,4 @@ __error:  	jmp __syscall_error  .size clone,.-clone +weak_alias(clone, __clone) diff --git a/libc/sysdeps/linux/i386/vfork.S b/libc/sysdeps/linux/i386/vfork.S index 8005ff1d2..c9db2f48c 100644 --- a/libc/sysdeps/linux/i386/vfork.S +++ b/libc/sysdeps/linux/i386/vfork.S @@ -18,9 +18,19 @@  __vfork:  	popl %ecx + +#ifdef SAVE_PID +	SAVE_PID +#endif +  	movl $__NR_vfork,%eax  	int $0x80  	pushl %ecx + +#ifdef RESTORE_PID +	RESTORE_PID +#endif +  	cmpl $-4095,%eax  	jae __syscall_error  	ret diff --git a/libc/sysdeps/linux/mips/Makefile.arch b/libc/sysdeps/linux/mips/Makefile.arch index 2570a6988..73e64991c 100644 --- a/libc/sysdeps/linux/mips/Makefile.arch +++ b/libc/sysdeps/linux/mips/Makefile.arch @@ -7,11 +7,15 @@  CSRC := \  	__longjmp.c  brk.c setjmp_aux.c mmap.c __syscall_error.c \ -	cacheflush.c pread_write.c sysmips.c _test_and_set.c sigaction.c \ +	cacheflush.c pread_write.c sysmips.c _test_and_set.c \  	readahead.c  ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y) -        CSRC += posix_fadvise.c posix_fadvise64.c +CSRC += posix_fadvise.c posix_fadvise64.c +endif + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c  endif  SSRC := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S syscall.S pipe.S diff --git a/libc/sysdeps/linux/mips/clone.S b/libc/sysdeps/linux/mips/clone.S index 15fa29558..a53d5c492 100644 --- a/libc/sysdeps/linux/mips/clone.S +++ b/libc/sysdeps/linux/mips/clone.S @@ -132,3 +132,4 @@ L(__thread_start):          jal             _exit  #endif  	.end  __thread_start +weak_alias(clone, __clone) diff --git a/libc/sysdeps/linux/mips/sys/asm.h b/libc/sysdeps/linux/mips/sys/asm.h index 79d143975..d424ed3b1 100644 --- a/libc/sysdeps/linux/mips/sys/asm.h +++ b/libc/sysdeps/linux/mips/sys/asm.h @@ -472,4 +472,20 @@ symbol		=	value  # define MTC0	dmtc0  #endif +/* The MIPS archtectures do not have a uniform memory model.  Particular +   platforms may provide additional guarantees - for instance, the R4000 +   LL and SC instructions implicitly perform a SYNC, and the 4K promises +   strong ordering. + +   However, in the absence of those guarantees, we must assume weak ordering +   and SYNC explicitly where necessary. + +   Some obsolete MIPS processors may not support the SYNC instruction.  This +   applies to "true" MIPS I processors; most of the processors which compile +   using MIPS I implement parts of MIPS II.  */ + +#ifndef MIPS_SYNC +# define MIPS_SYNC      sync +#endif +  #endif /* sys/asm.h */ diff --git a/libc/sysdeps/linux/mips/sys/regdef.h b/libc/sysdeps/linux/mips/sys/regdef.h index 9d2c4c1c4..2d94130af 100644 --- a/libc/sysdeps/linux/mips/sys/regdef.h +++ b/libc/sysdeps/linux/mips/sys/regdef.h @@ -20,6 +20,8 @@  #ifndef _SYS_REGDEF_H  #define _SYS_REGDEF_H +#include <sgidefs.h> +  /*   * Symbolic register names for 32 bit ABI   */ diff --git a/libc/sysdeps/linux/mips/syscall_error.S b/libc/sysdeps/linux/mips/syscall_error.S new file mode 100644 index 000000000..1e348ad4a --- /dev/null +++ b/libc/sysdeps/linux/mips/syscall_error.S @@ -0,0 +1,82 @@ +/* Copyright (C) 1992, 1993, 1994, 1997, 1998, 1999, 2000, 2002, 2003 +   Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Brendan Kehoe (brendan@zen.org). + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sys/asm.h> +#include <sysdep.h> +#include <bits/errno.h> + +#ifdef __UCLIBC_HAS_THREADS__ + +LOCALSZ= 3 +FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK +RAOFF= FRAMESZ-(1*SZREG) +GPOFF= FRAMESZ-(2*SZREG) +V0OFF= FRAMESZ-(3*SZREG) + +ENTRY(__syscall_error) +#ifdef __PIC__ +	.set noat +	SETUP_GPX (AT) +	.set at +#endif +	PTR_SUBU sp, FRAMESZ +	.set noat +	SETUP_GPX64(GPOFF,AT) +	.set at +#ifdef __PIC__ +	SAVE_GP(GPOFF) +#endif +	REG_S	v0, V0OFF(sp) +	REG_S	ra, RAOFF(sp) + +	/* Find our per-thread errno address  */ +	jal	__errno_location + +	/* Store the error value.  */ +	REG_L	t0, V0OFF(sp) +	sw	t0, 0(v0) + +	/* And just kick back a -1.  */ +	REG_L	ra, RAOFF(sp) +	RESTORE_GP64 +	PTR_ADDU sp, FRAMESZ +	li	v0, -1 +	j	ra +	END(__syscall_error) + +#else /* __UCLIBC_HAS_THREADS__ */ + + +ENTRY(__syscall_error) +#ifdef __PIC__ +	SETUP_GPX (AT) +#endif +	SETUP_GPX64 (t9, AT) + +	/* Store it in errno... */ +	sw v0, errno + +	/* And just kick back a -1.  */ +	li v0, -1 + +	RESTORE_GP64 +	j ra +	END(__syscall_error) +#endif  /* __UCLIBC_HAS_THREADS__ */ diff --git a/libc/sysdeps/linux/mips/sysdep.h b/libc/sysdeps/linux/mips/sysdep.h new file mode 100644 index 000000000..38d4ce903 --- /dev/null +++ b/libc/sysdeps/linux/mips/sysdep.h @@ -0,0 +1,54 @@ +/* Adapted from glibc's sysdeps/unix/mips/sysdep.h */ + +/* Copyright (C) 1992, 1995, 1997, 1999, 2000, 2002, 2003 +   Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Brendan Kehoe (brendan@zen.org). + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <features.h> + +#if __UCLIBC_HAS_THREADS_NATIVE__ +#include_next <sysdep.h> + +#else + +#ifdef __ASSEMBLER__ + +#include <sgidefs.h> +#include <sys/regdef.h> + +#define ENTRY(name) \ +  .globl name;                                                                \ +  .align 2;                                                                   \ +  .ent name,0;                                                                \ +  name##: + +#undef END +#define END(function)                                   \ +                .end    function;                       \ +                .size   function,.-function + +#if _MIPS_SIM == _ABIO32 +# define L(label) $L ## label +#else +# define L(label) .L ## label +#endif + +#endif + +#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */ diff --git a/libc/sysdeps/linux/mips/vfork.S b/libc/sysdeps/linux/mips/vfork.S new file mode 100644 index 000000000..8400df052 --- /dev/null +++ b/libc/sysdeps/linux/mips/vfork.S @@ -0,0 +1,97 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* vfork() is just a special case of clone().  */ + +#include <sys/asm.h> +#include <sysdep.h> + +#ifndef SAVE_PID +#define SAVE_PID +#endif + +#ifndef RESTORE_PID +#define RESTORE_PID +#endif + + +/* int vfork() */ + +	.text +LOCALSZ= 1 +FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK +GPOFF= FRAMESZ-(1*SZREG) +NESTED(__vfork,FRAMESZ,sp) +#ifdef __PIC__ +	SETUP_GP +#endif +	PTR_SUBU sp, FRAMESZ +	SETUP_GP64 (a5, __vfork) +#ifdef __PIC__ +	SAVE_GP (GPOFF) +#endif +#ifdef PROF +# if (_MIPS_SIM != _ABIO32) +	PTR_S		a5, GPOFF(sp) +# endif +	.set		noat +	move		$1, ra +# if (_MIPS_SIM == _ABIO32) +	subu		sp,sp,8 +# endif +	jal		_mcount +	.set		at +# if (_MIPS_SIM != _ABIO32) +	PTR_L		a5, GPOFF(sp) +# endif +#endif + +	PTR_ADDU	sp, FRAMESZ + +	SAVE_PID + +	li		a0, 0x4112	/* CLONE_VM | CLONE_VFORK | SIGCHLD */ +	move		a1, sp + +	/* Do the system call */ +	li		v0,__NR_clone +	syscall + +	RESTORE_PID + +	bnez		a3,L(error) + +	/* Successful return from the parent or child.  */ +	RESTORE_GP64 +	j		ra +	nop + +	/* Something bad happened -- no child created.  */ +L(error): +#ifdef __PIC__ +	PTR_LA		t9, __syscall_error +	RESTORE_GP64 +	jr		t9 +#else +	RESTORE_GP64 +	j		__syscall_error +#endif +	END(__vfork) + +.weak vfork; +	vfork = __vfork diff --git a/libc/sysdeps/linux/sh/Makefile.arch b/libc/sysdeps/linux/sh/Makefile.arch index 31beda111..3e32e1095 100644 --- a/libc/sysdeps/linux/sh/Makefile.arch +++ b/libc/sysdeps/linux/sh/Makefile.arch @@ -7,6 +7,6 @@  #  CSRC := \ -	mmap.c pipe.c __init_brk.c brk.c sbrk.c pread_write.c cacheflush.c +	mmap.c pipe.c __init_brk.c brk.c sbrk.c pread_write.c longjmp.c cacheflush.c -SSRC := setjmp.S __longjmp.S vfork.S clone.S ___fpscr_values.S +SSRC := setjmp.S __longjmp.S ___fpscr_values.S diff --git a/libc/sysdeps/linux/sh/bits/atomic.h b/libc/sysdeps/linux/sh/bits/atomic.h index 6bb7255c5..a099b43a8 100644 --- a/libc/sysdeps/linux/sh/bits/atomic.h +++ b/libc/sysdeps/linux/sh/bits/atomic.h @@ -54,6 +54,10 @@ typedef uintmax_t uatomic_max_t;      Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in      Japanese). +    Niibe Yutaka, "gUSA: User Space Atomicity with Little Kernel +    Modification", LinuxTag 2003, Rome. +    http://www.semmel.ch/Linuxtag-DVD/talks/170/paper.html (in English). +      B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for      Uniprocessors",  Proceedings of the Fifth Architectural Support for      Programming Languages and Operating Systems (ASPLOS), pp. 223-233, @@ -65,56 +69,44 @@ typedef uintmax_t uatomic_max_t;        r1:     saved stack pointer  */ -#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ -  ({ __typeof (*(mem)) __result; \ -     __asm__ __volatile__ ("\ +/* Avoid having lots of different versions of compare and exchange, +   by having this one complicated version. Parameters: +      bwl:     b, w or l for 8, 16 and 32 bit versions. +      version: val or bool, depending on whether the result is the +               previous value or a bool indicating whether the transfer +               did happen (note this needs inverting before being +               returned in atomic_compare_and_exchange_bool). +*/ + +#define __arch_compare_and_exchange_n(mem, newval, oldval, bwl, version) \ +  ({ signed long __result; \ +     __asm __volatile ("\  	.align 2\n\  	mova 1f,r0\n\  	nop\n\  	mov r15,r1\n\  	mov #-8,r15\n\ -     0: mov.b @%1,%0\n\ +     0: mov." #bwl " @%1,%0\n\  	cmp/eq %0,%3\n\  	bf 1f\n\ -	mov.b %2,@%1\n\ -     1: mov r1,r15"\ -	: "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \ -	: "r0", "r1", "t", "memory"); \ +	mov." #bwl " %2,@%1\n\ +     1: mov r1,r15\n\ +     .ifeqs \"bool\",\"" #version "\"\n\ +        movt %0\n\ +     .endif\n"					\ +	: "=&r" (__result)			\ +	: "r" (mem), "r" (newval), "r" (oldval)	\ +	: "r0", "r1", "t", "memory");		\       __result; }) +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ +  __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, val) +  #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ -  ({ __typeof (*(mem)) __result; \ -     __asm__ __volatile__ ("\ -	.align 2\n\ -	mova 1f,r0\n\ -	nop\n\ -	mov r15,r1\n\ -	mov #-8,r15\n\ -     0: mov.w @%1,%0\n\ -	cmp/eq %0,%3\n\ -	bf 1f\n\ -	mov.w %2,@%1\n\ -     1: mov r1,r15"\ -	: "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \ -	: "r0", "r1", "t", "memory"); \ -     __result; }) +  __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, val)  #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ -  ({ __typeof (*(mem)) __result; \ -     __asm__ __volatile__ ("\ -	.align 2\n\ -	mova 1f,r0\n\ -	nop\n\ -	mov r15,r1\n\ -	mov #-8,r15\n\ -     0: mov.l @%1,%0\n\ -	cmp/eq %0,%3\n\ -	bf 1f\n\ -	mov.l %2,@%1\n\ -     1: mov r1,r15"\ -	: "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \ -	: "r0", "r1", "t", "memory"); \ -     __result; }) +  __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, val)  /* XXX We do not really need 64-bit compare-and-exchange.  At least     not in the moment.  Using it would mean causing portability @@ -122,298 +114,180 @@ typedef uintmax_t uatomic_max_t;     such an operation.  So don't define any code for now.  */  # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ -  (abort (), (__typeof (*mem)) 0) +  (abort (), 0) + +/* For "bool" routines, return if the exchange did NOT occur */ + +#define __arch_compare_and_exchange_bool_8_acq(mem, newval, oldval) \ +  (! __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, bool)) + +#define __arch_compare_and_exchange_bool_16_acq(mem, newval, oldval) \ +  (! __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, bool)) + +#define __arch_compare_and_exchange_bool_32_acq(mem, newval, oldval) \ +  (! __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, bool)) + +# define __arch_compare_and_exchange_bool_64_acq(mem, newval, oldval) \ +  (abort (), 0) + +/* Similar to the above, have one template which can be used in a +   number of places. This version returns both the old and the new +   values of the location. Parameters: +      bwl:     b, w or l for 8, 16 and 32 bit versions. +      oper:    The instruction to perform on the old value. +   Note old is not sign extended, so should be an unsigned long. +*/ + +#define __arch_operate_old_new_n(mem, value, old, new, bwl, oper)	\ +  (void) ({ __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	mov r15,r1\n\ +	nop\n\ +	mov #-8,r15\n\ +     0: mov." #bwl " @%2,%0\n\ +	mov %0,%1\n\ +	" #oper " %3,%1\n\ +	mov." #bwl " %1,@%2\n\ +     1: mov r1,r15"			\ +	: "=&r" (old), "=&r"(new)	\ +	: "r" (mem), "r" (value)	\ +	: "r0", "r1", "memory");	\ +    }) + +#define __arch_exchange_and_add_8_int(mem, value)			\ +  ({ int32_t __value = (value), __new, __old;				\ +    __arch_operate_old_new_n((mem), __value, __old, __new, b, add);	\ +    __old; }) + +#define __arch_exchange_and_add_16_int(mem, value)			\ +  ({ int32_t __value = (value), __new, __old;				\ +    __arch_operate_old_new_n((mem), __value, __old, __new, w, add);	\ +    __old; }) + +#define __arch_exchange_and_add_32_int(mem, value)			\ +  ({ int32_t __value = (value), __new, __old;				\ +    __arch_operate_old_new_n((mem), __value, __old, __new, l, add);	\ +    __old; }) + +#define __arch_exchange_and_add_64_int(mem, value)			\ +  (abort (), 0)  #define atomic_exchange_and_add(mem, value) \ -  ({ __typeof (*(mem)) __result, __tmp, __value = (value); \ -     if (sizeof (*(mem)) == 1) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.b @%2,%0\n\ -	  add %0,%1\n\ -	  mov.b %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "memory"); \ -     else if (sizeof (*(mem)) == 2) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.w @%2,%0\n\ -	  add %0,%1\n\ -	  mov.w %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "memory"); \ -     else if (sizeof (*(mem)) == 4) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.l @%2,%0\n\ -	  add %0,%1\n\ -	  mov.l %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "memory"); \ -     else \ -       { \ -	 __typeof (mem) memp = (mem); \ -	 do \ -	   __result = *memp; \ -	 while (__arch_compare_and_exchange_val_64_acq \ -		 (memp,	__result + __value, __result) == __result); \ -	 (void) __value; \ -       } \ -     __result; }) +  __atomic_val_bysize (__arch_exchange_and_add, int, mem, value) + + +/* Again, another template. We get a slight optimisation when the old value +   does not need to be returned. Parameters: +      bwl:     b, w or l for 8, 16 and 32 bit versions. +      oper:    The instruction to perform on the old value. +*/ + +#define __arch_operate_new_n(mem, value, bwl, oper)	 \ +  ({ int32_t __value = (value), __new; \ +     __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	mov r15,r1\n\ +	mov #-6,r15\n\ +     0: mov." #bwl " @%1,%0\n\ +	" #oper " %2,%0\n\ +	mov." #bwl " %0,@%1\n\ +     1: mov r1,r15"			\ +	: "=&r" (__new)			\ +	: "r" (mem), "r" (__value)	\ +	: "r0", "r1", "memory");	\ +     __new;				\ +  }) + +#define __arch_add_8_int(mem, value)		\ +  __arch_operate_new_n(mem, value, b, add) + +#define __arch_add_16_int(mem, value)		\ +  __arch_operate_new_n(mem, value, w, add) + +#define __arch_add_32_int(mem, value)		\ +  __arch_operate_new_n(mem, value, l, add) + +#define __arch_add_64_int(mem, value)		\ +  (abort (), 0)  #define atomic_add(mem, value) \ -  (void) ({ __typeof (*(mem)) __tmp, __value = (value); \ -	    if (sizeof (*(mem)) == 1) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.b @%1,r2\n\ -		add r2,%0\n\ -		mov.b %0,@%1\n\ -	     1: mov r1,r15"\ -		: "=&r" (__tmp) : "r" (mem), "0" (__value) \ -		: "r0", "r1", "r2", "memory"); \ -	    else if (sizeof (*(mem)) == 2) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.w @%1,r2\n\ -		add r2,%0\n\ -		mov.w %0,@%1\n\ -	     1: mov r1,r15"\ -		: "=&r" (__tmp) : "r" (mem), "0" (__value) \ -		: "r0", "r1", "r2", "memory"); \ -	    else if (sizeof (*(mem)) == 4) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.l @%1,r2\n\ -		add r2,%0\n\ -		mov.l %0,@%1\n\ -	     1: mov r1,r15"\ -		: "=&r" (__tmp) : "r" (mem), "0" (__value) \ -		: "r0", "r1", "r2", "memory"); \ -	    else \ -	      { \ -		__typeof (*(mem)) oldval; \ -		__typeof (mem) memp = (mem); \ -		do \ -		  oldval = *memp; \ -		while (__arch_compare_and_exchange_val_64_acq \ -			(memp, oldval + __value, oldval) == oldval); \ -		(void) __value; \ -	      } \ -	    }) +  ((void) __atomic_val_bysize (__arch_add, int, mem, value)) + + +#define __arch_add_negative_8_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, b, add) < 0) + +#define __arch_add_negative_16_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, w, add) < 0) + +#define __arch_add_negative_32_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, l, add) < 0) + +#define __arch_add_negative_64_int(mem, value)		\ +  (abort (), 0)  #define atomic_add_negative(mem, value) \ -  ({ unsigned char __result; \ -     __typeof (*(mem)) __tmp, __value = (value); \ -     if (sizeof (*(mem)) == 1) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.b @%2,r2\n\ -	  add r2,%1\n\ -	  mov.b %1,@%2\n\ -       1: mov r1,r15\n\ -	  shal %1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else if (sizeof (*(mem)) == 2) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.w @%2,r2\n\ -	  add r2,%1\n\ -	  mov.w %1,@%2\n\ -       1: mov r1,r15\n\ -	  shal %1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else if (sizeof (*(mem)) == 4) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.l @%2,r2\n\ -	  add r2,%1\n\ -	  mov.l %1,@%2\n\ -       1: mov r1,r15\n\ -	  shal %1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else \ -       abort (); \ -     __result; }) +  __atomic_bool_bysize (__arch_add_negative, int, mem, value) + + +#define __arch_add_zero_8_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, b, add) == 0) + +#define __arch_add_zero_16_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, w, add) == 0) + +#define __arch_add_zero_32_int(mem, value)		\ +  (__arch_operate_new_n(mem, value, l, add) == 0) + +#define __arch_add_zero_64_int(mem, value)		\ +  (abort (), 0)  #define atomic_add_zero(mem, value) \ -  ({ unsigned char __result; \ -     __typeof (*(mem)) __tmp, __value = (value); \ -     if (sizeof (*(mem)) == 1) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.b @%2,r2\n\ -	  add r2,%1\n\ -	  mov.b %1,@%2\n\ -       1: mov r1,r15\n\ -	  tst %1,%1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else if (sizeof (*(mem)) == 2) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.w @%2,r2\n\ -	  add r2,%1\n\ -	  mov.w %1,@%2\n\ -       1: mov r1,r15\n\ -	  tst %1,%1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else if (sizeof (*(mem)) == 4) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  mov r15,r1\n\ -	  mov #-6,r15\n\ -       0: mov.l @%2,r2\n\ -	  add r2,%1\n\ -	  mov.l %1,@%2\n\ -       1: mov r1,r15\n\ -	  tst %1,%1\n\ -	  movt %0"\ -	: "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ -	: "r0", "r1", "r2", "t", "memory"); \ -     else \ -       abort (); \ -     __result; }) +  __atomic_bool_bysize (__arch_add_zero, int, mem, value) +  #define atomic_increment_and_test(mem) atomic_add_zero((mem), 1)  #define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1) -#define atomic_bit_set(mem, bit) \ -  (void) ({ unsigned int __mask = 1 << (bit); \ -	    if (sizeof (*(mem)) == 1) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.b @%0,r2\n\ -		or %1,r2\n\ -		mov.b r2,@%0\n\ -	     1: mov r1,r15"\ -		: : "r" (mem), "r" (__mask) \ -		: "r0", "r1", "r2", "memory"); \ -	    else if (sizeof (*(mem)) == 2) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.w @%0,r2\n\ -		or %1,r2\n\ -		mov.w r2,@%0\n\ -	     1: mov r1,r15"\ -		: : "r" (mem), "r" (__mask) \ -		: "r0", "r1", "r2", "memory"); \ -	    else if (sizeof (*(mem)) == 4) \ -	      __asm__ __volatile__ ("\ -		.align 2\n\ -		mova 1f,r0\n\ -		mov r15,r1\n\ -		mov #-6,r15\n\ -	     0: mov.l @%0,r2\n\ -		or %1,r2\n\ -		mov.l r2,@%0\n\ -	     1: mov r1,r15"\ -		: : "r" (mem), "r" (__mask) \ -		: "r0", "r1", "r2", "memory"); \ -	    else \ -	      abort (); \ -	    }) - -#define atomic_bit_test_set(mem, bit) \ -  ({ unsigned int __mask = 1 << (bit); \ -     unsigned int __result = __mask; \ -     if (sizeof (*(mem)) == 1) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  nop\n\ -	  mov r15,r1\n\ -	  mov #-8,r15\n\ -       0: mov.b @%2,r2\n\ -	  or r2,%1\n\ -	  and r2,%0\n\ -	  mov.b %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__mask) \ -	: "r" (mem), "0" (__result), "1" (__mask) \ -	: "r0", "r1", "r2", "memory"); \ -     else if (sizeof (*(mem)) == 2) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  nop\n\ -	  mov r15,r1\n\ -	  mov #-8,r15\n\ -       0: mov.w @%2,r2\n\ -	  or r2,%1\n\ -	  and r2,%0\n\ -	  mov.w %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__mask) \ -	: "r" (mem), "0" (__result), "1" (__mask) \ -	: "r0", "r1", "r2", "memory"); \ -     else if (sizeof (*(mem)) == 4) \ -       __asm__ __volatile__ ("\ -	  .align 2\n\ -	  mova 1f,r0\n\ -	  nop\n\ -	  mov r15,r1\n\ -	  mov #-8,r15\n\ -       0: mov.l @%2,r2\n\ -	  or r2,%1\n\ -	  and r2,%0\n\ -	  mov.l %1,@%2\n\ -       1: mov r1,r15"\ -	: "=&r" (__result), "=&r" (__mask) \ -	: "r" (mem), "0" (__result), "1" (__mask) \ -	: "r0", "r1", "r2", "memory"); \ -     else \ -       abort (); \ -     __result; }) + +#define __arch_bit_set_8_int(mem, value)		\ +  __arch_operate_new_n(mem, 1<<(value), b, or) + +#define __arch_bit_set_16_int(mem, value)		\ +  __arch_operate_new_n(mem, 1<<(value), w, or) + +#define __arch_bit_set_32_int(mem, value)		\ +  __arch_operate_new_n(mem, 1<<(value), l, or) + +#define __arch_bit_set_64_int(mem, value)		\ +  (abort (), 0) + +#define __arch_add_64_int(mem, value)			\ +  (abort (), 0) + +#define atomic_bit_set(mem, value) \ +  ((void) __atomic_val_bysize (__arch_bit_set, int, mem, value)) + + +#define __arch_bit_test_set_8_int(mem, value)				\ +  ({ int32_t __value = 1<<(value), __new, __old;			\ +    __arch_operate_old_new_n((mem), __value, __old, __new, b, or);	\ +    __old & __value; }) + +#define __arch_bit_test_set_16_int(mem, value)				\ +  ({ int32_t __value = 1<<(value), __new, __old;			\ +    __arch_operate_old_new_n((mem), __value, __old, __new, w, or);	\ +    __old & __value; }) + +#define __arch_bit_test_set_32_int(mem, value)				\ +  ({ int32_t __value = 1<<(value), __new, __old;			\ +    __arch_operate_old_new_n((mem), __value, __old, __new, l, or);	\ +    __old & __value; }) + +#define __arch_bit_test_set_64_int(mem, value)	\ +  (abort (), 0) + +#define atomic_bit_test_set(mem, value) \ +  __atomic_val_bysize (__arch_bit_test_set, int, mem, value) diff --git a/libc/sysdeps/linux/sh/clone.S b/libc/sysdeps/linux/sh/clone.S index 3d18b6dd0..423a6c2f1 100644 --- a/libc/sysdeps/linux/sh/clone.S +++ b/libc/sysdeps/linux/sh/clone.S @@ -1,4 +1,4 @@ -/* Copyright (C) 1999, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1999, 2000, 2003, 2004, 2007 Free Software Foundation, Inc.     This file is part of the GNU C Library.     The GNU C Library is free software; you can redistribute it and/or @@ -20,93 +20,94 @@     and invokes a function in the right context after its all over.  */  #include <features.h> -#include <sys/syscall.h> -#define _ERRNO_H +#include <asm/unistd.h> +#include <sysdep.h> +#define _ERRNO_H	1  #include <bits/errno.h> -#include <bits/sysnum.h> - - -#ifdef __PIC__ -#define PLTJMP(_x)	_x@PLT -#else -#define PLTJMP(_x)	_x +#ifdef RESET_PID +#include <tcb-offsets.h>  #endif +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, +	     pid_t *ptid, void *tls, pid_t *ctid); */ - -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ - -        .text - -.text -.align 4 -.type	clone,@function -.globl	clone; -clone: +	.text +ENTRY(__clone)  	/* sanity check arguments.  */  	tst	r4, r4 -	bt	0f -	tst	r5, r5 -	bf/s	1f -	 mov	#+__NR_clone, r3 -0:		 -	bra __syscall_error -	 mov	#-EINVAL, r4 - +	bt/s	0f +	 tst	r5, r5 +	bf	1f +0: +	bra	.Lsyscall_error +	 mov	#-EINVAL,r0  1:  	/* insert the args onto the new stack */  	mov.l	r7, @-r5  	/* save the function pointer as the 0th element */  	mov.l	r4, @-r5 -	 +  	/* do the system call */  	mov	r6, r4 -	trapa	#(__SH_SYSCALL_TRAP_BASE + 2) +	mov.l	@r15, r6 +	mov.l	@(8,r15), r7 +	mov.l	@(4,r15), r0 +	mov	#+SYS_ify(clone), r3 +	trapa	#0x15  	mov     r0, r1 -#ifdef __sh2__ -/* 12 arithmetic shifts for the crappy sh2, because shad doesn't exist!	 */ -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -	shar	r1 -#else		  	mov	#-12, r2  	shad	r2, r1 -#endif -	not	r1, r1			/* r1=0 means r0 = -1 to -4095 */ -	tst	r1, r1			/* i.e. error in linux */ -	bf/s	2f -	 tst	r0, r0 -        bra __syscall_error -	 mov	r0, r4 - -2: -	bt	3f +	not	r1, r1			// r1=0 means r0 = -1 to -4095 +	tst	r1, r1			// i.e. error in linux +	bf	.Lclone_end +.Lsyscall_error: +	SYSCALL_ERROR_HANDLER +.Lclone_end: +	tst	r0, r0 +	bt	2f +.Lpseudo_end:  	rts  	 nop +2: +	/* terminate the stack frame */ +	mov	#0, r14 +#ifdef RESET_PID +	mov	r4, r0 +	shlr16	r0 +	tst	#1, r0			// CLONE_THREAD = (1 << 16) +	bf/s	4f +	 mov	r4, r0 +	/* new pid */ +	shlr8	r0 +	tst	#1, r0			// CLONE_VM = (1 << 8) +	bf/s	3f +	 mov	#-1, r0 +	mov	#+SYS_ify(getpid), r3 +	trapa	#0x15  3: +	stc	gbr, r1 +	mov.w	.Lpidoff, r2 +	add	r1, r2 +	mov.l	r0, @r2 +	mov.w	.Ltidoff, r2 +	add	r1, r2 +	mov.l	r0, @r2 +4: +#endif  	/* thread starts */  	mov.l	@r15, r1  	jsr	@r1  	 mov.l	@(4,r15), r4  	/* we are done, passing the return value through r0  */ -	mov.l	.L1, r1 -#ifdef __PIC__ +	mov.l	.L3, r1 +#ifdef SHARED  	mov.l	r12, @-r15  	sts.l	pr, @-r15  	mov	r0, r4 -	mova	.LG, r0  /* .LG from syscall_error.S */ +	mova	.LG, r0  	mov.l	.LG, r12  	add	r0, r12 -	mova	.L1, r0 +	mova	.L3, r0  	add	r0, r1  	jsr	@r1  	 nop @@ -118,8 +119,16 @@ clone:  	 mov	r0, r4  #endif  	.align	2 -.L1: -	.long	PLTJMP( HIDDEN_JUMPTARGET(_exit)) -.size clone,.-clone; +.LG: +	.long	_GLOBAL_OFFSET_TABLE_ +.L3: +	.long	PLTJMP(C_SYMBOL_NAME(_exit)) +#ifdef RESET_PID +.Lpidoff: +	.word	PID - TLS_PRE_TCB_SIZE +.Ltidoff: +	.word	TID - TLS_PRE_TCB_SIZE +#endif +PSEUDO_END (__clone) -#include "syscall_error.S" +weak_alias (__clone, clone) diff --git a/libc/sysdeps/linux/sh/longjmp.c b/libc/sysdeps/linux/sh/longjmp.c new file mode 100644 index 000000000..dd0616d8a --- /dev/null +++ b/libc/sysdeps/linux/sh/longjmp.c @@ -0,0 +1,56 @@ +/* Copyright (C) 1991, 92, 94, 95, 97, 98, 2000 Free Software Foundation, Inc. +   Copyright (C) 2001 Hewlett-Packard Australia + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU Library General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more + details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Derived in part from the Linux-8086 C library, the GNU C Library, and several + other sundry sources.  Files within this library are copyright by their + respective copyright holders. +*/ + +#include <stddef.h> +#include <setjmp.h> +#include <signal.h> + +libc_hidden_proto(sigprocmask) + +extern int __longjmp(char *env, int val); +libc_hidden_proto(__longjmp) + +extern void _longjmp_unwind (jmp_buf env, int val); + + +/* Set the signal mask to the one specified in ENV, and jump +   to the position specified in ENV, causing the setjmp +   call there to return VAL, or 1 if VAL is 0.  */ +void __libc_siglongjmp (sigjmp_buf env, int val) +{ +  /* Perform any cleanups needed by the frames being unwound.  */ + +  _longjmp_unwind (env, val); + +  if (env[0].__mask_was_saved) +    /* Restore the saved signal mask.  */ +    (void) sigprocmask (SIG_SETMASK, &env[0].__saved_mask, +			  (sigset_t *) NULL); + +  /* Call the machine-dependent function to restore machine state.  */ +  __longjmp ((char *) env[0].__jmpbuf, val ?: 1); +} + +__asm__(".weak longjmp; longjmp = __libc_siglongjmp"); +__asm__(".weak _longjmp; _longjmp = __libc_siglongjmp"); +__asm__(".weak siglongjmp; siglongjmp = __libc_siglongjmp"); +strong_alias(__libc_siglongjmp, __libc_longjmp) diff --git a/libc/sysdeps/linux/sh/pread_write.c b/libc/sysdeps/linux/sh/pread_write.c index 84a28e766..86feb9cce 100644 --- a/libc/sysdeps/linux/sh/pread_write.c +++ b/libc/sysdeps/linux/sh/pread_write.c @@ -18,6 +18,13 @@  #include <stdint.h>  #include <endian.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif + +  #ifdef __NR_pread64             /* Newer kernels renamed but it's the same.  */  # ifdef __NR_pread  #  error "__NR_pread and __NR_pread64 both defined???" @@ -33,7 +40,15 @@ static __inline__ _syscall6(ssize_t, __syscall_pread, int, fd, void *, buf,  ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset)  { -	return(__syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset))); +	if (SINGLE_THREAD_P) +		return(__syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset))); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	ssize_t result = __syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif  }  weak_alias(__libc_pread,pread) @@ -43,7 +58,16 @@ ssize_t __libc_pread64(int fd, void *buf, size_t count, off64_t offset)  {  	uint32_t low = offset & 0xffffffff;  	uint32_t high = offset >> 32; -	return(__syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low))); + +	if (SINGLE_THREAD_P) +		return __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	ssize_t result = __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif  }  weak_alias(__libc_pread64,pread64)  # endif /* __UCLIBC_HAS_LFS__  */ @@ -66,7 +90,16 @@ static __inline__ _syscall6(ssize_t, __syscall_pwrite, int, fd, const void *, bu  ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset)  { -	return(__syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset))); +	if (SINGLE_THREAD_P) +		return __syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	ssize_t result = __syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif +  }  weak_alias(__libc_pwrite,pwrite) @@ -76,7 +109,16 @@ ssize_t __libc_pwrite64(int fd, const void *buf, size_t count, off64_t offset)  {  	uint32_t low = offset & 0xffffffff;  	uint32_t high = offset >> 32; -	return(__syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low))); + +	if (SINGLE_THREAD_P) +		return __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +	int oldtype = LIBC_CANCEL_ASYNC (); +	ssize_t result = __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); +	LIBC_CANCEL_RESET (oldtype); +	return result; +#endif  }  weak_alias(__libc_pwrite64,pwrite64)  # endif /* __UCLIBC_HAS_LFS__  */ diff --git a/libc/sysdeps/linux/sh/setjmp.S b/libc/sysdeps/linux/sh/setjmp.S index 00475a008..0a81424e1 100644 --- a/libc/sysdeps/linux/sh/setjmp.S +++ b/libc/sysdeps/linux/sh/setjmp.S @@ -77,7 +77,7 @@ __sigsetjmp_intern:  	mov.l	r9, @-r4  	mov.l	r8, @-r4 -#ifdef __PIC__ +#ifdef __HAVE_SHARED__  	mov.l	.LG, r2  	mova	.LG, r0  	add	r0, r2 diff --git a/libc/sysdeps/linux/sh/syscall_error.S b/libc/sysdeps/linux/sh/syscall_error.S index f55dd535a..737950308 100644 --- a/libc/sysdeps/linux/sh/syscall_error.S +++ b/libc/sysdeps/linux/sh/syscall_error.S @@ -3,7 +3,7 @@ __syscall_error:  	/* Call errno_location, store '-r4' in errno and return -1 */  	mov.l	r12, @-r15  	sts.l	pr, @-r15 -#ifdef __PIC__ +#ifdef SHARED  	mova	.LG, r0  	mov.l	.LG, r12  	add	r0, r12 @@ -27,7 +27,7 @@ __syscall_error:  	.align	4 -#ifdef __PIC__ +#ifdef SHARED  1:	.long   __errno_location@GOT  .LG:	.long	_GLOBAL_OFFSET_TABLE_  #else diff --git a/libc/sysdeps/linux/sparc/Makefile.arch b/libc/sysdeps/linux/sparc/Makefile.arch index ffae27bc7..8a624205a 100644 --- a/libc/sysdeps/linux/sparc/Makefile.arch +++ b/libc/sysdeps/linux/sparc/Makefile.arch @@ -5,8 +5,15 @@  # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.  # -CSRC := brk.c __syscall_error.c qp_ops.c sigaction.c +CSRC := brk.c __syscall_error.c qp_ops.c  SSRC := \ -	__longjmp.S fork.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ +	__longjmp.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \  	syscall.S urem.S udiv.S umul.S sdiv.S rem.S pipe.S + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +SSRC += fork.S vfork.S +endif + + diff --git a/libc/sysdeps/linux/sparc/bits/atomic.h b/libc/sysdeps/linux/sparc/bits/atomic.h new file mode 100644 index 000000000..f625eb92a --- /dev/null +++ b/libc/sysdeps/linux/sparc/bits/atomic.h @@ -0,0 +1,329 @@ +/* Atomic operations.  sparc32 version. +   Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_ATOMIC_H +#define _BITS_ATOMIC_H	1 + +#include <stdint.h> + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +typedef int16_t atomic16_t; +typedef uint16_t uatomic16_t; +typedef int_fast16_t atomic_fast16_t; +typedef uint_fast16_t uatomic_fast16_t; + +typedef int32_t atomic32_t; +typedef uint32_t uatomic32_t; +typedef int_fast32_t atomic_fast32_t; +typedef uint_fast32_t uatomic_fast32_t; + +typedef int64_t atomic64_t; +typedef uint64_t uatomic64_t; +typedef int_fast64_t atomic_fast64_t; +typedef uint_fast64_t uatomic_fast64_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + + +/* We have no compare and swap, just test and set. +   The following implementation contends on 64 global locks +   per library and assumes no variable will be accessed using atomic.h +   macros from two different libraries.  */ + +__make_section_unallocated +  (".gnu.linkonce.b.__sparc32_atomic_locks, \"aw\", %nobits"); + +volatile unsigned char __sparc32_atomic_locks[64] +  __attribute__ ((nocommon, section (".gnu.linkonce.b.__sparc32_atomic_locks" +				     __sec_comment), +		  visibility ("hidden"))); + +#define __sparc32_atomic_do_lock(addr) \ +  do								      \ +    {								      \ +      unsigned int __old_lock;					      \ +      unsigned int __idx = (((long) addr >> 2) ^ ((long) addr >> 12)) \ +			   & 63;				      \ +      do							      \ +	__asm __volatile ("ldstub %1, %0"			      \ +			  : "=r" (__old_lock),			      \ +			    "=m" (__sparc32_atomic_locks[__idx])      \ +			  : "m" (__sparc32_atomic_locks[__idx])	      \ +			  : "memory");				      \ +      while (__old_lock);					      \ +    }								      \ +  while (0) + +#define __sparc32_atomic_do_unlock(addr) \ +  do								      \ +    {								      \ +      __sparc32_atomic_locks[(((long) addr >> 2)		      \ +			      ^ ((long) addr >> 12)) & 63] = 0;	      \ +      __asm __volatile ("" ::: "memory");			      \ +    }								      \ +  while (0) + +#define __sparc32_atomic_do_lock24(addr) \ +  do								      \ +    {								      \ +      unsigned int __old_lock;					      \ +      do							      \ +	__asm __volatile ("ldstub %1, %0"			      \ +			  : "=r" (__old_lock), "=m" (*(addr))	      \ +			  : "m" (*(addr))			      \ +			  : "memory");				      \ +      while (__old_lock);					      \ +    }								      \ +  while (0) + +#define __sparc32_atomic_do_unlock24(addr) \ +  do								      \ +    {								      \ +      *(char *) (addr) = 0;					      \ +      __asm __volatile ("" ::: "memory");			      \ +    }								      \ +  while (0) + + +#ifndef SHARED +# define __v9_compare_and_exchange_val_32_acq(mem, newval, oldval) \ +({									      \ +  register __typeof (*(mem)) __acev_tmp __asm ("%g6");			      \ +  register __typeof (mem) __acev_mem __asm ("%g1") = (mem);		      \ +  register __typeof (*(mem)) __acev_oldval __asm ("%g5");		      \ +  __acev_tmp = (newval);						      \ +  __acev_oldval = (oldval);						      \ +  /* .word 0xcde05005 is cas [%g1], %g5, %g6.  Can't use cas here though,     \ +     because as will then mark the object file as V8+ arch.  */		      \ +  __asm __volatile (".word 0xcde05005"					      \ +		    : "+r" (__acev_tmp), "=m" (*__acev_mem)		      \ +		    : "r" (__acev_oldval), "m" (*__acev_mem),		      \ +		      "r" (__acev_mem) : "memory");			      \ +  __acev_tmp; }) +#endif + +/* The only basic operation needed is compare and exchange.  */ +#define __v7_compare_and_exchange_val_acq(mem, newval, oldval) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +     __typeof (*mem) __acev_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock (__acev_memp);			      \ +     __acev_ret = *__acev_memp;					      \ +     if (__acev_ret == (oldval))				      \ +       *__acev_memp = __acev_newval;				      \ +     __sparc32_atomic_do_unlock (__acev_memp);			      \ +     __acev_ret; }) + +#define __v7_compare_and_exchange_bool_acq(mem, newval, oldval) \ +  ({ __typeof (mem) __aceb_memp = (mem);			      \ +     int __aceb_ret;						      \ +     __typeof (*mem) __aceb_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock (__aceb_memp);			      \ +     __aceb_ret = 0;						      \ +     if (*__aceb_memp == (oldval))				      \ +       *__aceb_memp = __aceb_newval;				      \ +     else							      \ +       __aceb_ret = 1;						      \ +     __sparc32_atomic_do_unlock (__aceb_memp);			      \ +     __aceb_ret; }) + +#define __v7_exchange_acq(mem, newval) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +     __typeof (*mem) __acev_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock (__acev_memp);			      \ +     __acev_ret = *__acev_memp;					      \ +     *__acev_memp = __acev_newval;				      \ +     __sparc32_atomic_do_unlock (__acev_memp);			      \ +     __acev_ret; }) + +#define __v7_exchange_and_add(mem, value) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +								      \ +     __sparc32_atomic_do_lock (__acev_memp);			      \ +     __acev_ret = *__acev_memp;					      \ +     *__acev_memp = __acev_ret + (value);			      \ +     __sparc32_atomic_do_unlock (__acev_memp);			      \ +     __acev_ret; }) + +/* Special versions, which guarantee that top 8 bits of all values +   are cleared and use those bits as the ldstub lock.  */ +#define __v7_compare_and_exchange_val_24_acq(mem, newval, oldval) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +     __typeof (*mem) __acev_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock24 (__acev_memp);			      \ +     __acev_ret = *__acev_memp & 0xffffff;			      \ +     if (__acev_ret == (oldval))				      \ +       *__acev_memp = __acev_newval;				      \ +     else							      \ +       __sparc32_atomic_do_unlock24 (__acev_memp);		      \ +     __asm __volatile ("" ::: "memory");			      \ +     __acev_ret; }) + +#define __v7_exchange_24_rel(mem, newval) \ +  ({ __typeof (mem) __acev_memp = (mem);			      \ +     __typeof (*mem) __acev_ret;				      \ +     __typeof (*mem) __acev_newval = (newval);			      \ +								      \ +     __sparc32_atomic_do_lock24 (__acev_memp);			      \ +     __acev_ret = *__acev_memp & 0xffffff;			      \ +     *__acev_memp = __acev_newval;				      \ +     __asm __volatile ("" ::: "memory");			      \ +     __acev_ret; }) + +#ifdef SHARED + +/* When dynamically linked, we assume pre-v9 libraries are only ever +   used on pre-v9 CPU.  */ +# define __atomic_is_v9 0 + +# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ +  __v7_compare_and_exchange_val_acq (mem, newval, oldval) + +# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ +  __v7_compare_and_exchange_bool_acq (mem, newval, oldval) + +# define atomic_exchange_acq(mem, newval) \ +  __v7_exchange_acq (mem, newval) + +# define atomic_exchange_and_add(mem, value) \ +  __v7_exchange_and_add (mem, value) + +# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ +  ({								      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     __v7_compare_and_exchange_val_24_acq (mem, newval, oldval); }) + +# define atomic_exchange_24_rel(mem, newval) \ +  ({								      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     __v7_exchange_24_rel (mem, newval); }) + +#else + + + +/* +   Here's what we'd like to do: + +   In libc.a/libpthread.a etc. we don't know if we'll be run on +   pre-v9 or v9 CPU.  To be interoperable with dynamically linked +   apps on v9 CPUs e.g. with process shared primitives, use cas insn +   on v9 CPUs and ldstub on pre-v9. + +   However, we have no good way to test at run time that I know of, +   so resort to the lowest common denominator (v7 ops) -austinf + */ +#define __atomic_is_v9 0 + +# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ +  ({								      \ +     __typeof (*mem) __acev_wret;				      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       __acev_wret						      \ +	 = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ +     else							      \ +       __acev_wret						      \ +	 = __v7_compare_and_exchange_val_acq (mem, newval, oldval);   \ +     __acev_wret; }) + +# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ +  ({								      \ +     int __acev_wret;						      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       {							      \ +	 __typeof (oldval) __acev_woldval = (oldval);		      \ +	 __acev_wret						      \ +	   = __v9_compare_and_exchange_val_32_acq (mem, newval,	      \ +						   __acev_woldval)    \ +	     != __acev_woldval;					      \ +       }							      \ +     else							      \ +       __acev_wret						      \ +	 = __v7_compare_and_exchange_bool_acq (mem, newval, oldval);  \ +     __acev_wret; }) + +# define atomic_exchange_rel(mem, newval) \ +  ({								      \ +     __typeof (*mem) __acev_wret;				      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       {							      \ +	 __typeof (mem) __acev_wmemp = (mem);			      \ +	 __typeof (*(mem)) __acev_wval = (newval);		      \ +	 do							      \ +	   __acev_wret = *__acev_wmemp;				      \ +	 while (__builtin_expect				      \ +		  (__v9_compare_and_exchange_val_32_acq (__acev_wmemp,\ +							 __acev_wval, \ +							 __acev_wret) \ +		   != __acev_wret, 0));				      \ +       }							      \ +     else							      \ +       __acev_wret = __v7_exchange_acq (mem, newval);		      \ +     __acev_wret; }) + +# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ +  ({								      \ +     __typeof (*mem) __acev_wret;				      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       __acev_wret						      \ +	 = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ +     else							      \ +       __acev_wret						      \ +	 = __v7_compare_and_exchange_val_24_acq (mem, newval, oldval);\ +     __acev_wret; }) + +# define atomic_exchange_24_rel(mem, newval) \ +  ({								      \ +     __typeof (*mem) __acev_w24ret;				      \ +     if (sizeof (*mem) != 4)					      \ +       abort ();						      \ +     if (__atomic_is_v9)					      \ +       __acev_w24ret = atomic_exchange_rel (mem, newval);	      \ +     else							      \ +       __acev_w24ret = __v7_exchange_24_rel (mem, newval);	      \ +     __acev_w24ret; }) + +#endif + +#endif	/* bits/atomic.h */ diff --git a/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h b/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h index 1dbfa2b55..2d8cdd78b 100644 --- a/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h @@ -36,7 +36,7 @@  #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__  /* define if target supports CFI pseudo ops */ -#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ +#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__  /* define if target supports IEEE signed zero floats */  #define __UCLIBC_HAVE_SIGNED_ZERO__ diff --git a/libc/sysdeps/linux/sparc/clone.S b/libc/sysdeps/linux/sparc/clone.S index 0e41ee0cb..2b6609531 100644 --- a/libc/sysdeps/linux/sparc/clone.S +++ b/libc/sysdeps/linux/sparc/clone.S @@ -1,4 +1,5 @@ -/* Copyright (C) 1996, 1997, 1998, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2007 +   Free Software Foundation, Inc.     This file is part of the GNU C Library.     Contributed by Richard Henderson (rth@tamu.edu). @@ -20,47 +21,87 @@  /* clone() is even more special than fork() as it mucks with stacks     and invokes a function in the right context after its all over.  */ -#include <features.h> +#include <asm/errno.h>  #include <asm/unistd.h> +#include <tcb-offsets.h> +#include <sysdep.h> -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ +#define CLONE_VM	0x00000100 +#define CLONE_THREAD	0x00010000 -.text -.global clone -.type   clone,%function -.align 4 +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, +	     pid_t *ptid, void *tls, pid_t *ctid); */ -clone: +	.text +ENTRY (__clone)  	save	%sp,-96,%sp +	cfi_def_cfa_register(%fp) +	cfi_window_save +	cfi_register(%o7, %i7)  	/* sanity check arguments */ -	tst	%i0 -	be	__error -	orcc	%i1,%g0,%o1 -	be	__error -	mov	%i2,%o0 +	orcc	%i0,%g0,%g2 +	be	.Leinval +	 orcc	%i1,%g0,%o1 +	be	.Leinval +	 mov	%i2,%o0 + +	/* The child_stack is the top of the stack, allocate one +	   whole stack frame from that as this is what the kernel +	   expects.  */ +	sub	%o1, 96, %o1 +	mov	%i3, %g3 +	mov	%i2, %g4 + +	/* ptid */ +	mov	%i4,%o2 +	/* tls */ +	mov	%i5,%o3 +	/* ctid */ +	ld	[%fp+92],%o4  	/* Do the system call */  	set	__NR_clone,%g1  	ta	0x10 -	bcs	__error -	tst	%o1 +	bcs	.Lerror +	 tst	%o1  	bne	__thread_start -	nop -	ret -	restore %o0,%g0,%o0 - -__error: -	jmp __syscall_error +	 nop +	jmpl	%i7 + 8, %g0 +	 restore %o0,%g0,%o0 -.size clone,.-clone - -.type __thread_start,%function +.Leinval: +	mov	EINVAL, %o0 +.Lerror: +	call	__errno_location +	 mov	%o0, %i0 +	st	%i0,[%o0] +	jmpl	%i7 + 8, %g0 +	 restore %g0,-1,%o0 +END(__clone) +	.type	__thread_start,@function  __thread_start: -	call	%i0 -	mov	%i3,%o0 -	call	HIDDEN_JUMPTARGET(_exit),0 -	nop +#ifdef RESET_PID +	sethi	%hi(CLONE_THREAD), %l0 +	andcc	%g4, %l0, %g0 +	bne	1f +	 andcc	%g4, CLONE_VM, %g0 +	bne,a	2f +	 mov	-1,%o0 +	set	__NR_getpid,%g1 +	ta	0x10 +2: +	st	%o0,[%g7 + PID] +	st	%o0,[%g7 + TID] +1: +#endif +	mov	%g0, %fp	/* terminate backtrace */ +	call	%g2 +	 mov	%g3,%o0 +	call	exit,0 +	 nop + +	.size	__thread_start, .-__thread_start -.size __thread_start,.-__thread_start +weak_alias (__clone, clone) diff --git a/libc/sysdeps/linux/sparc/sparcv9/clone.S b/libc/sysdeps/linux/sparc/sparcv9/clone.S new file mode 100644 index 000000000..9d101e239 --- /dev/null +++ b/libc/sysdeps/linux/sparc/sparcv9/clone.S @@ -0,0 +1,102 @@ +/* Copyright (C) 1997, 2000, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Richard Henderson (rth@tamu.edu). + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* clone() is even more special than fork() as it mucks with stacks +   and invokes a function in the right context after its all over.  */ + +#include <asm/errno.h> +#include <asm/unistd.h> +#include <tcb-offsets.h> +#include <sysdep.h> + +#define CLONE_VM	0x00000100 +#define CLONE_THREAD	0x00010000 + +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, +	     pid_t *ptid, void *tls, pid_t *ctid); */ + +	.register	%g2,#scratch +	.register	%g3,#scratch + +	.text + +ENTRY (__clone) +	save	%sp, -192, %sp +	cfi_def_cfa_register(%fp) +	cfi_window_save +	cfi_register(%o7, %i7) + +	/* sanity check arguments */ +	brz,pn	%i0, 99f		/* fn non-NULL? */ +	 mov	%i0, %g2 +	brz,pn	%i1, 99f		/* child_stack non-NULL? */ +	 mov	%i2, %o0		/* clone flags */ + +	/* The child_stack is the top of the stack, allocate one +	   whole stack frame from that as this is what the kernel +	   expects.  Also, subtract STACK_BIAS.  */ +	sub	%i1, 192 + 0x7ff, %o1 +	mov	%i3, %g3 +	mov	%i2, %g4 + +	mov	%i4,%o2			/* PTID */ +	mov	%i5,%o3			/* TLS */ +	ldx	[%fp+0x7ff+176],%o4	/* CTID */ + +	/* Do the system call */ +	set	__NR_clone, %g1 +	ta	0x6d +	bcs,pn	%xcc, 98f +	 nop +	brnz,pn	%o1, __thread_start +	 nop +	jmpl	%i7 + 8, %g0 +	 restore %o0, %g0, %o0 +99:	mov	EINVAL, %o0 +98:	call	HIDDEN_JUMPTARGET(__errno_location) +	 mov	%o0, %i0 +	st	%i0, [%o0] +	jmpl	%i7 + 8, %g0 +	 restore %g0,-1,%o0 +END(__clone) + +	.type __thread_start,@function +__thread_start: +#ifdef RESET_PID +	sethi	%hi(CLONE_THREAD), %l0 +	andcc	%g4, %l0, %g0 +	bne,pt	%icc, 1f +	 andcc	%g4, CLONE_VM, %g0 +	bne,a,pn %icc, 2f +	 mov	-1,%o0 +	set	__NR_getpid,%g1 +	ta	0x6d +2:	st	%o0,[%g7 + PID] +	st	%o0,[%g7 + TID] +1: +#endif +	mov	%g0, %fp	/* terminate backtrace */ +	call	%g2 +	 mov	%g3,%o0 +	call	HIDDEN_JUMPTARGET(_exit),0 +	 nop + +	.size	__thread_start, .-__thread_start + +weak_alias (__clone, clone) diff --git a/libc/sysdeps/linux/x86_64/Makefile.arch b/libc/sysdeps/linux/x86_64/Makefile.arch index 044f97f95..de7ce7285 100644 --- a/libc/sysdeps/linux/x86_64/Makefile.arch +++ b/libc/sysdeps/linux/x86_64/Makefile.arch @@ -5,7 +5,15 @@  # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.  # -CSRC := brk.c sigaction.c __syscall_error.c mmap.c +CSRC := brk.c __syscall_error.c mmap.c + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +endif  SSRC := \ -	__longjmp.S vfork.S setjmp.S syscall.S bsd-setjmp.S bsd-_setjmp.S clone.S +	__longjmp.S setjmp.S syscall.S bsd-setjmp.S bsd-_setjmp.S + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +SSRC += vfork.S clone.S +endif diff --git a/libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h b/libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h index 748e544bb..1d966aee4 100644 --- a/libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/x86_64/bits/uClibc_arch_features.h @@ -36,7 +36,7 @@  #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__  /* define if target supports CFI pseudo ops */ -#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ +#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__  /* define if target supports IEEE signed zero floats */  #define __UCLIBC_HAVE_SIGNED_ZERO__ diff --git a/libc/sysdeps/linux/x86_64/clone.S b/libc/sysdeps/linux/x86_64/clone.S index dc5eeb0a0..8f53a8412 100644 --- a/libc/sysdeps/linux/x86_64/clone.S +++ b/libc/sysdeps/linux/x86_64/clone.S @@ -112,3 +112,4 @@ clone:  	call	HIDDEN_JUMPTARGET(_exit)  .size clone,.-clone +weak_alias(clone, __clone) diff --git a/libc/sysdeps/linux/x86_64/vfork.S b/libc/sysdeps/linux/x86_64/vfork.S index 2dadbbfe0..97c9c5b67 100644 --- a/libc/sysdeps/linux/x86_64/vfork.S +++ b/libc/sysdeps/linux/x86_64/vfork.S @@ -1,4 +1,4 @@ -/* Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2002, 2004, 2008 Free Software Foundation, Inc.     This file is part of the GNU C Library.     The GNU C Library is free software; you can redistribute it and/or @@ -31,7 +31,7 @@  .text  .global __vfork  .hidden __vfork -.type	__vfork,%function +.type   __vfork,%function  __vfork: @@ -39,6 +39,10 @@ __vfork:  	   is preserved by the syscall and that we're allowed to destroy. */  	popq	%rdi +#ifdef SAVE_PID +	SAVE_PID +#endif +  	/* Stuff the syscall number in RAX and enter into the kernel.  */  	movl	$__NR_vfork, %eax  	syscall @@ -46,6 +50,10 @@ __vfork:  	/* Push back the return PC.  */  	pushq	%rdi +#ifdef RESTORE_PID +	RESTORE_PID +#endif +  	cmpl	$-4095, %eax  	jae __syscall_error		/* Branch forward if it failed.  */ | 
