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) |