summaryrefslogtreecommitdiff
path: root/libpthread/linuxthreads
diff options
context:
space:
mode:
Diffstat (limited to 'libpthread/linuxthreads')
-rw-r--r--libpthread/linuxthreads/condvar.c7
-rw-r--r--libpthread/linuxthreads/manager.c37
-rw-r--r--libpthread/linuxthreads/semaphore.c10
-rw-r--r--libpthread/linuxthreads/signals.c17
-rw-r--r--libpthread/linuxthreads/sysdeps/arm/pt-machine.h36
-rw-r--r--libpthread/linuxthreads/sysdeps/riscv32/pt-machine.h61
-rw-r--r--libpthread/linuxthreads/sysdeps/riscv64/pt-machine.h61
-rw-r--r--libpthread/linuxthreads/sysdeps/xtensa/pt-machine.h69
8 files changed, 244 insertions, 54 deletions
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/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)