diff options
Diffstat (limited to 'libpthread/linuxthreads')
| -rw-r--r-- | libpthread/linuxthreads/Makefile.in | 2 | ||||
| -rw-r--r-- | libpthread/linuxthreads/condvar.c | 7 | ||||
| -rw-r--r-- | libpthread/linuxthreads/manager.c | 37 | ||||
| -rw-r--r-- | libpthread/linuxthreads/semaphore.c | 10 | ||||
| -rw-r--r-- | libpthread/linuxthreads/signals.c | 17 | ||||
| -rw-r--r-- | libpthread/linuxthreads/sysdeps/arm/pt-machine.h | 36 | ||||
| -rw-r--r-- | libpthread/linuxthreads/sysdeps/pthread/not-cancel.h | 2 | ||||
| -rw-r--r-- | libpthread/linuxthreads/sysdeps/riscv32/pt-machine.h | 61 | ||||
| -rw-r--r-- | libpthread/linuxthreads/sysdeps/riscv64/pt-machine.h | 61 | ||||
| -rw-r--r-- | libpthread/linuxthreads/sysdeps/xtensa/pt-machine.h | 69 | 
10 files changed, 248 insertions, 54 deletions
| diff --git a/libpthread/linuxthreads/Makefile.in b/libpthread/linuxthreads/Makefile.in index ffdd5d4eb..cc2a5f285 100644 --- a/libpthread/linuxthreads/Makefile.in +++ b/libpthread/linuxthreads/Makefile.in @@ -16,6 +16,8 @@ libpthread_OUT := $(top_builddir)libpthread/linuxthreads  -include $(libpthread_DIR)/sysdeps/$(TARGET_ARCH)/Makefile.arch +CFLAGS-signals.c = -fexceptions -fasynchronous-unwind-tables +  libpthread_SRC := \  	attr.c cancel.c condvar.c errno.c events.c join.c lockfile.c manager.c \  	mutex.c pt-machine.c ptfork.c pthread.c ptlongjmp.c \ diff --git a/libpthread/linuxthreads/condvar.c b/libpthread/linuxthreads/condvar.c index 6ac1622da..01359ac83 100644 --- a/libpthread/linuxthreads/condvar.c +++ b/libpthread/linuxthreads/condvar.c @@ -18,6 +18,7 @@  #include <errno.h>  #include <sched.h>  #include <stddef.h> +#include <string.h>  #include <sys/time.h>  #include "pthread.h"  #include "internals.h" @@ -273,7 +274,7 @@ int pthread_cond_broadcast(pthread_cond_t *cond)  }  libpthread_hidden_def(pthread_cond_broadcast) -int pthread_condattr_init(pthread_condattr_t *attr attribute_unused) +int pthread_condattr_init(pthread_condattr_t *attr)  {    memset (attr, '\0', sizeof (*attr));    return 0; @@ -328,7 +329,11 @@ int pthread_condattr_setclock (pthread_condattr_t *attr, clockid_t clock_id)  	  INTERNAL_SYSCALL_DECL (err);  	  int val; +#if defined(__UCLIBC_USE_TIME64__) && defined(__NR_clock_getres_time64) +	  val = INTERNAL_SYSCALL (clock_getres_time64, err, 2, CLOCK_MONOTONIC, &ts); +#else  	  val = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); +#endif  	  avail = INTERNAL_SYSCALL_ERROR_P (val, err) ? -1 : 1;  	} diff --git a/libpthread/linuxthreads/manager.c b/libpthread/linuxthreads/manager.c index 2a1ee62af..73fd1dcdb 100644 --- a/libpthread/linuxthreads/manager.c +++ b/libpthread/linuxthreads/manager.c @@ -47,6 +47,15 @@  # define USE_SELECT  #endif +/* MAP_FIXED_NOREPLACE is not supported in kernel <= 4.17 + * If it's not already defined, define it to 0. + * We check the results of mmap to ensure the correct + * results, and error out otherwise. + */ +#ifndef MAP_FIXED_NOREPLACE +#define MAP_FIXED_NOREPLACE 0 +#endif +  /* Array of active threads. Entry 0 is reserved for the initial thread. */  struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =  { { __LOCK_INITIALIZER, &__pthread_initial_thread, 0}, @@ -371,12 +380,19 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,        /* Allocate space for stack and thread descriptor at default address */        new_thread = default_new_thread;        new_thread_bottom = (char *) (new_thread + 1) - stacksize; -      if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE), +      void * new_stack_addr = NULL; +      new_stack_addr = mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE),                 INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, -               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -               -1, 0) == MAP_FAILED) +               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_GROWSDOWN, +               -1, 0); +      if (new_stack_addr == MAP_FAILED){          /* Bad luck, this segment is already mapped. */          return -1; +      } else if ( new_stack_addr != (caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE)) { +        /* Worse luck, we almost overwrote an existing page */ +        munmap(new_stack_addr, INITIAL_STACK_SIZE); +        return -2; +      }        /* We manage to get a stack.  Now see whether we need a guard           and allocate it if necessary.  Notice that the default           attributes (stack_size = STACK_SIZE - pagesize) do not need @@ -439,7 +455,7 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,         * the kernel chokes on a non-aligned stack frame. Choose the lower         * available word boundary.         */ -      new_thread = ((pthread_descr) ((int)(new_thread_bottom + stacksize) & -sizeof(void*))) - 1; +      new_thread = ((pthread_descr) ((long)(new_thread_bottom + stacksize) & -sizeof(void*))) - 1;        guardaddr = NULL;        guardsize = 0; @@ -496,9 +512,10 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,  	return EAGAIN;        if (__pthread_handles[sseg].h_descr != NULL)  	continue; -      if (pthread_allocate_stack(attr, thread_segment(sseg), pagesize, +      int res = pthread_allocate_stack(attr, thread_segment(sseg), pagesize,                                   &new_thread, &new_thread_bottom, -                                 &guardaddr, &guardsize) == 0) +                                 &guardaddr, &guardsize); +      if ( res == 0)          break;  #ifndef __ARCH_USE_MMU__        else @@ -507,6 +524,14 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,           * use the next one. However, when there is no MMU, malloc () is used.           * It's waste of CPU cycles to continue to try if it fails.  */          return EAGAIN; +#else +      else if (res == -2) +        /*  When there is an MMU, if pthread_allocate_stack failed with -2, +         *  it indicates that we are attempting to mmap in address space which +         *  is already allocated. Any additional attempts will result in failure +         *  since we have exhausted our stack area. +         */ +        return EAGAIN;  #endif      }    __pthread_handles_num++; diff --git a/libpthread/linuxthreads/semaphore.c b/libpthread/linuxthreads/semaphore.c index 9025dfee6..9464204a9 100644 --- a/libpthread/linuxthreads/semaphore.c +++ b/libpthread/linuxthreads/semaphore.c @@ -61,7 +61,6 @@ int sem_wait(sem_t * sem)    volatile pthread_descr self = thread_self();    pthread_extricate_if extr;    int already_canceled = 0; -  int spurious_wakeup_count;    /* Set up extrication interface */    extr.pu_object = sem; @@ -90,7 +89,6 @@ int sem_wait(sem_t * sem)    }    /* Wait for sem_post or cancellation, or fall through if already canceled */ -  spurious_wakeup_count = 0;    while (1)      {        suspend(self); @@ -98,8 +96,7 @@ int sem_wait(sem_t * sem)  	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0  	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))  	{ -	  /* Count resumes that don't belong to us. */ -	  spurious_wakeup_count++; +	  /* Resume does not belong to us. */  	  continue;  	}        break; @@ -213,7 +210,6 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)    pthread_descr self = thread_self();    pthread_extricate_if extr;    int already_canceled = 0; -  int spurious_wakeup_count;    __pthread_lock(&sem->__sem_lock, self);    if (sem->__sem_value > 0) { @@ -250,7 +246,6 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);    } -  spurious_wakeup_count = 0;    while (1)      {        if (timedsuspend(self, abstime) == 0) { @@ -277,8 +272,7 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)  	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0  	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))  	{ -	  /* Count resumes that don't belong to us. */ -	  spurious_wakeup_count++; +	  /* Resume does not belong to us. */  	  continue;  	}        break; diff --git a/libpthread/linuxthreads/signals.c b/libpthread/linuxthreads/signals.c index 0c0f2b6b1..91b88e2c7 100644 --- a/libpthread/linuxthreads/signals.c +++ b/libpthread/linuxthreads/signals.c @@ -134,6 +134,7 @@ int sigaction(int sig, const struct sigaction * act,  {    struct sigaction newact;    struct sigaction *newactp; +  void *save = NULL;  #ifdef DEBUG_PT  printf(__FUNCTION__": pthreads wrapper!\n"); @@ -142,6 +143,8 @@ printf(__FUNCTION__": pthreads wrapper!\n");        sig == __pthread_sig_cancel ||        (sig == __pthread_sig_debug && __pthread_sig_debug > 0))      return EINVAL; +  if (sig > 0 && sig < NSIG) +    save = sighandler[sig].old;    if (act)      {        newact = *act; @@ -154,22 +157,24 @@ printf(__FUNCTION__": pthreads wrapper!\n");  	    newact.sa_handler = (__sighandler_t) pthread_sighandler;  	}        newactp = &newact; +      if (sig > 0 && sig < NSIG) +	sighandler[sig].old = (arch_sighandler_t) act->sa_handler;      }    else      newactp = NULL;    if (__libc_sigaction(sig, newactp, oact) == -1) -    return -1; +    { +      if (act && sig > 0 && sig < NSIG) +	sighandler[sig].old = save; +      return -1; +    }  #ifdef DEBUG_PT  printf(__FUNCTION__": sighandler installed, sigaction successful\n");  #endif    if (sig > 0 && sig < NSIG)      {        if (oact != NULL) -	oact->sa_handler = (__sighandler_t) sighandler[sig].old; -      if (act) -	/* For the assignment is does not matter whether it's a normal -	   or real-time signal.  */ -	sighandler[sig].old = (arch_sighandler_t) act->sa_handler; +	oact->sa_handler = save;      }    return 0;  } diff --git a/libpthread/linuxthreads/sysdeps/arm/pt-machine.h b/libpthread/linuxthreads/sysdeps/arm/pt-machine.h index fc17e9bc7..3250961cf 100644 --- a/libpthread/linuxthreads/sysdeps/arm/pt-machine.h +++ b/libpthread/linuxthreads/sysdeps/arm/pt-machine.h @@ -28,36 +28,20 @@  # define PT_EI __extern_always_inline  #endif -#if defined(__thumb2__) -PT_EI long int ldrex(int *spinlock) -{ -	long int ret; -	__asm__ __volatile__( -		"ldrex %0, [%1]\n" -		: "=r"(ret) -		: "r"(spinlock) : "memory"); -	return ret; -} - -PT_EI long int strex(int val, int *spinlock) -{ -	long int ret; -	__asm__ __volatile__( -		"strex %0, %1, [%2]\n" -		: "=r"(ret) -		: "r" (val), "r"(spinlock) : "memory"); -	return ret; -} - +#if  __ARM_ARCH >= 7 || defined(__thumb2__)  /* Spinlock implementation; required.  */  PT_EI long int  testandset (int *spinlock)  { -  register unsigned int ret; - -  do { -	  ret = ldrex(spinlock); -  } while (strex(1, spinlock)); +  unsigned int ret, tmp, val = 1; + +  __asm__ __volatile__ ( +"0:    ldrex   %0, [%2]       \n" +"      strex   %1, %3, [%2]   \n" +"      cmp     %1, #0         \n" +"      bne     0b" +       : "=&r" (ret), "=&r" (tmp) +       : "r" (spinlock), "r" (val) : "memory", "cc");    return ret;  } diff --git a/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h b/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h index bbdb0739c..6d7c4d70a 100644 --- a/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h +++ b/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h @@ -19,6 +19,7 @@  #include <sys/types.h>  #include <sysdep.h> +#include <time.h>  /* Uncancelable open.  */  #if defined __NR_openat && !defined __NR_open @@ -104,6 +105,7 @@ extern int __openat64_nocancel (int fd, const char *fname, int oflag,  # define nanosleep_not_cancel(requested_time, remaining) \    INLINE_SYSCALL (nanosleep, 2, requested_time, remaining)  #else +extern int __nanosleep_nocancel (const struct timespec *requested_time, struct timespec *remaining);  # define nanosleep_not_cancel(requested_time, remaining) \    __nanosleep_nocancel (requested_time, remaining)  #endif diff --git a/libpthread/linuxthreads/sysdeps/riscv32/pt-machine.h b/libpthread/linuxthreads/sysdeps/riscv32/pt-machine.h new file mode 100644 index 000000000..38f0d8eff --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/riscv32/pt-machine.h @@ -0,0 +1,61 @@ +/* + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H   1 +#include <features.h> + +#ifndef PT_EI +# define PT_EI __extern_always_inline +#endif + +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ +  long int ret, temp; + +  __asm__ __volatile__ +    ("/* Inline compare & swap */\n" +     "1:\n\t" +     "lr.w      %1,%2\n\t" +     "li        %0,0\n\t" +     "bne       %1,%3,2f\n\t" +     "li        %0,1\n\t" +     "sc.w      %1,%4,%2\n\t" +     "bnez      %1,1b\n" +     "2:\n\t" +     "/* End compare & swap */" +     : "=&r" (ret), "=&r" (temp), "+A" (*p) +     : "r" (oldval), "r" (newval) +     : "memory"); + +  return ret; +} + +extern long int testandset (int *spinlock); + +PT_EI long int +testandset (int *spinlock) +{ +        unsigned int old = 1; +        int tmp = 1; + +        __asm__ __volatile__ ( +        "amoswap.w %0, %2, %1" +        : "=r" (old), "+A" (*spinlock) +        : "r" (tmp) +        : "memory"); + +        return old; +} + +/* Get some notion of the current stack.  Need not be exactly the top +   of the stack, just something somewhere in the current frame.  */ +#define CURRENT_STACK_FRAME  stack_pointer +register char * stack_pointer __asm__ ("sp"); + +#else +#error PT_MACHINE already defined +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/riscv64/pt-machine.h b/libpthread/linuxthreads/sysdeps/riscv64/pt-machine.h new file mode 100644 index 000000000..d83057669 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/riscv64/pt-machine.h @@ -0,0 +1,61 @@ +/* + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H   1 +#include <features.h> + +#ifndef PT_EI +# define PT_EI __extern_always_inline +#endif + +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ +  long int ret, temp; + +  __asm__ __volatile__ +    ("/* Inline compare & swap */\n" +     "1:\n\t" +     "lr.d      %1,%2\n\t" +     "li        %0,0\n\t" +     "bne       %1,%3,2f\n\t" +     "li        %0,1\n\t" +     "sc.d      %1,%4,%2\n\t" +     "bnez      %1,1b\n" +     "2:\n\t" +     "/* End compare & swap */" +     : "=&r" (ret), "=&r" (temp), "+A" (*p) +     : "r" (oldval), "r" (newval) +     : "memory"); + +  return ret; +} + +extern long int testandset (int *spinlock); + +PT_EI long int +testandset (int *spinlock) +{ +        unsigned int old = 1; +        int tmp = 1; + +        __asm__ __volatile__ ( +        "amoswap.w %0, %2, %1" +        : "=r" (old), "+A" (*spinlock) +        : "r" (tmp) +        : "memory"); + +        return old; +} + +/* Get some notion of the current stack.  Need not be exactly the top +   of the stack, just something somewhere in the current frame.  */ +#define CURRENT_STACK_FRAME  stack_pointer +register char * stack_pointer __asm__ ("sp"); + +#else +#error PT_MACHINE already defined +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/xtensa/pt-machine.h b/libpthread/linuxthreads/sysdeps/xtensa/pt-machine.h index 2c68ddfb5..0b7f58b63 100644 --- a/libpthread/linuxthreads/sysdeps/xtensa/pt-machine.h +++ b/libpthread/linuxthreads/sysdeps/xtensa/pt-machine.h @@ -21,6 +21,7 @@  #ifndef _PT_MACHINE_H  #define _PT_MACHINE_H   1 +#include <bits/xtensa-config.h>  #include <sys/syscall.h>  #include <asm/unistd.h> @@ -34,16 +35,24 @@  extern long int testandset (int *spinlock);  extern int __compare_and_swap (long int *p, long int oldval, long int newval); +#if XCHAL_HAVE_EXCLUSIVE +  /* Spinlock implementation; required.  */  PT_EI long int  testandset (int *spinlock)  {  	unsigned long tmp;  	__asm__ volatile ( -"	movi	%0, 0			\n" -"	wsr	%0, SCOMPARE1		\n" +"	memw				\n" +"1:	l32ex	%0, %1			\n" +"	bnez	%0, 2f			\n"  "	movi	%0, 1			\n" -"	s32c1i	%0, %1, 0		\n" +"	s32ex	%0, %1			\n" +"	getex	%0			\n" +"	beqz	%0, 1b			\n" +"	movi	%0, 0			\n" +"	memw				\n" +"2:					\n"  	: "=&a" (tmp)  	: "a" (spinlock)  	: "memory" @@ -57,21 +66,67 @@ __compare_and_swap (long int *p, long int oldval, long int newval)          unsigned long tmp;          unsigned long value;          __asm__ volatile ( -"1:     l32i    %0, %2, 0            \n" +"       memw                         \n" +"1:     l32ex   %0, %2               \n" +"       bne     %0, %4, 2f           \n" +"       mov     %1, %3               \n" +"       s32ex   %1, %2               \n" +"       getex   %1                   \n" +"       beqz    %1, 1b               \n" +"       memw                         \n" +"2:                                  \n" +          : "=&a" (tmp), "=&a" (value) +          : "a" (p), "a" (newval), "a" (oldval) +          : "memory" ); + +        return tmp == oldval; +} + +#elif XCHAL_HAVE_S32C1I + +/* Spinlock implementation; required.  */ +PT_EI long int +testandset (int *spinlock) +{ +	unsigned long tmp; +	__asm__ volatile ( +"	movi	%0, 0			\n" +"	wsr	%0, SCOMPARE1		\n" +"	movi	%0, 1			\n" +"	s32c1i	%0, %1			\n" +	: "=&a" (tmp), "+m" (*spinlock) +	:: "memory" +	); +	return tmp; +} + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ +        unsigned long tmp; +        unsigned long value; +        __asm__ volatile ( +"1:     l32i    %0, %2               \n"  "       bne     %0, %4, 2f           \n"  "       wsr     %0, SCOMPARE1        \n"  "       mov     %1, %0               \n"  "       mov     %0, %3               \n" -"       s32c1i  %0, %2, 0            \n" +"       s32c1i  %0, %2               \n"  "       bne     %1, %0, 1b           \n"  "2:                                  \n" -          : "=&a" (tmp), "=&a" (value) -          : "a" (p), "a" (newval), "a" (oldval) +          : "=&a" (tmp), "=&a" (value), "+m" (*p) +          : "a" (newval), "a" (oldval)            : "memory" );          return tmp == oldval;  } +#else + +#error No hardware atomic operations + +#endif +  /* Get some notion of the current stack.  Need not be exactly the top     of the stack, just something somewhere in the current frame.  */  #define CURRENT_STACK_FRAME __builtin_frame_address (0) | 
