summaryrefslogtreecommitdiff
path: root/libpthread
diff options
context:
space:
mode:
authorYann Sionneau <ysionneau@kalray.eu>2020-10-02 16:24:55 +0200
committerWaldemar Brodkorb <wbx@openadk.org>2020-10-02 19:10:36 +0200
commit672a303852353ba9299f6f50190fca8b3abe4c1d (patch)
treef204ea8dc0b5a3e4b2bd4251b8daf5f0783ae260 /libpthread
parent4acf6f072cbc255b0b0d6cfd598a100f95d84f2a (diff)
kvx: add support for kvx arch to uClibc-ng
This commit adds support for Kalray VLIW family (kvx) Kalray kv3 core is embedded in Kalray Coolidge SoC. This core which is the third of the KV family has the following features: 32/64 bits execution mode 6-issue VLIW architecture 64 x 64bits general purpose registers SIMD instructions little-endian In order to build a usable toolchain, build scripts are provided at the following address: https://github.com/kalray/build-scripts. Kalray uses FOSS which is available at https://github.com/kalray This includes Linux kernel, uClibc-ng, gcc, binutils, etc. Signed-off-by: Clément Léger <cleger@kalray.eu> Signed-off-by: Guillaume Thouvenin <gthouvenin@kalray.eu> Signed-off-by: Laurent Thevenoux <lthevenoux@kalray.eu> Signed-off-by: Marc Poulhies <mpoulhies@kalray.eu> Signed-off-by: Marius Gligor <mgligor@kalray.eu> Signed-off-by: Yann Sionneau <ysionneau@kalray.eu>
Diffstat (limited to 'libpthread')
-rw-r--r--libpthread/nptl/sysdeps/kvx/Makefile.arch9
-rw-r--r--libpthread/nptl/sysdeps/kvx/dl-tls.h47
-rw-r--r--libpthread/nptl/sysdeps/kvx/libc-tls.c26
-rw-r--r--libpthread/nptl/sysdeps/kvx/pthread_spin_lock.c60
-rw-r--r--libpthread/nptl/sysdeps/kvx/pthread_spin_trylock.c26
-rw-r--r--libpthread/nptl/sysdeps/kvx/pthreaddef.h26
-rw-r--r--libpthread/nptl/sysdeps/kvx/tcb-offsets.sym6
-rw-r--r--libpthread/nptl/sysdeps/kvx/tls.h160
-rw-r--r--libpthread/nptl/sysdeps/kvx/unwind-forcedunwind.c165
-rw-r--r--libpthread/nptl/sysdeps/pthread/Makefile.in2
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/kvx/Makefile13
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/kvx/Makefile.arch14
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/kvx/bits/pthreadtypes.h166
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/kvx/bits/semaphore.h30
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/kvx/createthread.c14
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/kvx/fork.c11
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/kvx/pthread_once.c77
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/kvx/sysdep-cancel.h43
18 files changed, 895 insertions, 0 deletions
diff --git a/libpthread/nptl/sysdeps/kvx/Makefile.arch b/libpthread/nptl/sysdeps/kvx/Makefile.arch
new file mode 100644
index 000000000..b2ad58197
--- /dev/null
+++ b/libpthread/nptl/sysdeps/kvx/Makefile.arch
@@ -0,0 +1,9 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2019 Kalray
+#
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+#
+
+libc_arch_a_CSRC = unwind-forcedunwind.c libc-tls.c
+CFLAGS-unwind-forcedunwind.c = -fexceptions -fasynchronous-unwind-tables
diff --git a/libpthread/nptl/sysdeps/kvx/dl-tls.h b/libpthread/nptl/sysdeps/kvx/dl-tls.h
new file mode 100644
index 000000000..61b810db6
--- /dev/null
+++ b/libpthread/nptl/sysdeps/kvx/dl-tls.h
@@ -0,0 +1,47 @@
+/*
+ * This file is subject to the terms and conditions of the LGPL V2.1
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2019 Kalray Inc.
+ */
+
+#ifndef _KVX_DL_TLS_H
+#define _KVX_DL_TLS_H 1
+
+/* Type used to represent a TLS descriptor in the GOT. */
+struct tlsdesc
+{
+ ptrdiff_t (*entry) (struct tlsdesc *);
+ void *arg;
+};
+
+typedef struct dl_tls_index
+{
+ unsigned long int ti_module;
+ unsigned long int ti_offset;
+} tls_index;
+
+/* Type used as the argument in a TLS descriptor for a symbol that
+ needs dynamic TLS offsets. */
+struct tlsdesc_dynamic_arg
+{
+ tls_index tlsinfo;
+ size_t gen_count;
+};
+
+extern ptrdiff_t attribute_hidden
+_dl_tlsdesc_return (struct tlsdesc *);
+
+# ifdef SHARED
+extern void *_dl_make_tlsdesc_dynamic (struct link_map *, size_t);
+
+extern ptrdiff_t attribute_hidden
+_dl_tlsdesc_dynamic (struct tlsdesc *);
+# endif
+
+extern void *__tls_get_addr (tls_index *ti);
+
+#define TLS_DTV_UNALLOCATED ((void *) -1l)
+
+#endif
diff --git a/libpthread/nptl/sysdeps/kvx/libc-tls.c b/libpthread/nptl/sysdeps/kvx/libc-tls.c
new file mode 100644
index 000000000..5fd9e7e70
--- /dev/null
+++ b/libpthread/nptl/sysdeps/kvx/libc-tls.c
@@ -0,0 +1,26 @@
+/*
+ * This file is subject to the terms and conditions of the LGPL V2.1
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2020 Kalray Inc.
+ */
+
+#include <sysdeps/generic/libc-tls.c>
+#include <dl-tls.h>
+
+#if defined(USE_TLS) && USE_TLS
+
+/* On kvx, linker optimizations are not required, so __tls_get_addr
+ can be called even in statically linked binaries. In this case module
+ must be always 1 and PT_TLS segment exist in the binary, otherwise it
+ would not link. */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+ dtv_t *dtv = THREAD_DTV ();
+ return (char *) dtv[1].pointer.val + ti->ti_offset;
+}
+
+#endif
diff --git a/libpthread/nptl/sysdeps/kvx/pthread_spin_lock.c b/libpthread/nptl/sysdeps/kvx/pthread_spin_lock.c
new file mode 100644
index 000000000..6f77c6250
--- /dev/null
+++ b/libpthread/nptl/sysdeps/kvx/pthread_spin_lock.c
@@ -0,0 +1,60 @@
+/* pthread_spin_lock -- lock a spin lock. Generic version.
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <atomic.h>
+#include "pthreadP.h"
+
+/* A machine-specific version can define SPIN_LOCK_READS_BETWEEN_CMPXCHG
+ to the number of plain reads that it's optimal to spin on between uses
+ of atomic_compare_and_exchange_val_acq. If spinning forever is optimal
+ then use -1. If no plain reads here would ever be optimal, use 0. */
+#define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+ /* atomic_exchange usually takes less instructions than
+ atomic_compare_and_exchange. On the other hand,
+ atomic_compare_and_exchange potentially generates less bus traffic
+ when the lock is locked.
+ We assume that the first try mostly will be successful, and we use
+ atomic_exchange. For the subsequent tries we use
+ atomic_compare_and_exchange. */
+ if (atomic_exchange_acq (lock, 1) == 0)
+ return 0;
+
+ do {
+ /* The lock is contended and we need to wait. Going straight back
+ to cmpxchg is not a good idea on many targets as that will force
+ expensive memory synchronizations among processors and penalize other
+ running threads.
+ On the other hand, we do want to update memory state on the local core
+ once in a while to avoid spinning indefinitely until some event that
+ will happen to update local memory as a side-effect. */
+ if (SPIN_LOCK_READS_BETWEEN_CMPXCHG >= 0) {
+ int wait = SPIN_LOCK_READS_BETWEEN_CMPXCHG;
+
+ while (*lock != 0 && wait > 0)
+ --wait;
+ } else {
+ while (*lock != 0)
+ ;
+ }
+ } while (atomic_compare_and_exchange_val_acq (lock, 1, 0) != 0);
+
+ return 0;
+}
diff --git a/libpthread/nptl/sysdeps/kvx/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/kvx/pthread_spin_trylock.c
new file mode 100644
index 000000000..4e9aa64d3
--- /dev/null
+++ b/libpthread/nptl/sysdeps/kvx/pthread_spin_trylock.c
@@ -0,0 +1,26 @@
+/* pthread_spin_trylock -- trylock a spin lock. Generic version.
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+ return atomic_exchange_acq (lock, 1) ? EBUSY : 0;
+}
diff --git a/libpthread/nptl/sysdeps/kvx/pthreaddef.h b/libpthread/nptl/sysdeps/kvx/pthreaddef.h
new file mode 100644
index 000000000..6e1485998
--- /dev/null
+++ b/libpthread/nptl/sysdeps/kvx/pthreaddef.h
@@ -0,0 +1,26 @@
+/*
+ * This file is subject to the terms and conditions of the LGPL V2.1
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2019 Kalray Inc.
+ */
+
+/* Default stack size. */
+#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning. */
+#define STACK_ALIGN 32
+
+/* Minimal stack size after allocating thread descriptor and guard size. */
+#define MINIMAL_REST_STACK 2048
+
+/* Alignment requirement for TCB. */
+#define TCB_ALIGNMENT 32
+
+/* Location of current stack frame. */
+#define CURRENT_STACK_FRAME __builtin_frame_address (0)
+
+/* XXX Until we have a better place keep the definitions here. */
+#define __exit_thread_inline(val) \
+ INLINE_SYSCALL (exit, 1, (val))
diff --git a/libpthread/nptl/sysdeps/kvx/tcb-offsets.sym b/libpthread/nptl/sysdeps/kvx/tcb-offsets.sym
new file mode 100644
index 000000000..238647dd4
--- /dev/null
+++ b/libpthread/nptl/sysdeps/kvx/tcb-offsets.sym
@@ -0,0 +1,6 @@
+#include <sysdep.h>
+#include <tls.h>
+
+PTHREAD_MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads)
+PTHREAD_TID_OFFSET offsetof (struct pthread, tid)
+PTHREAD_SIZEOF sizeof (struct pthread)
diff --git a/libpthread/nptl/sysdeps/kvx/tls.h b/libpthread/nptl/sysdeps/kvx/tls.h
new file mode 100644
index 000000000..a3e7fa97b
--- /dev/null
+++ b/libpthread/nptl/sysdeps/kvx/tls.h
@@ -0,0 +1,160 @@
+/*
+ * This file is subject to the terms and conditions of the LGPL V2.1
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2019 Kalray Inc.
+ */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv. */
+typedef union dtv
+{
+ size_t counter;
+ struct
+ {
+ void *val;
+ bool is_static;
+ } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+/* We require TLS support in the tools. */
+#define HAVE_TLS_SUPPORT 1
+#define HAVE_TLS_MODEL_ATTRIBUTE 1
+#define HAVE___THREAD 1
+
+/* Signal that TLS support is available. */
+#define USE_TLS 1
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information. */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks. */
+# define TLS_DTV_AT_TP 1
+
+/* Get the thread descriptor definition. */
+# include <../../descr.h>
+
+typedef struct
+{
+ dtv_t *dtv;
+} tcbhead_t;
+
+/* Thread Pointer $tp is $r13 */
+register tcbhead_t *__thread_self __asm__("$r13");
+
+/* This is the size of the initial TCB. */
+# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB. */
+# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB. */
+# define TLS_TCB_SIZE sizeof (tcbhead_t)
+
+/* This is the size we need before TCB. */
+# define TLS_PRE_TCB_SIZE sizeof (struct pthread)
+
+/* Alignment requirements for the TCB. */
+# define TLS_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* Install the dtv pointer. The pointer passed is to the element with
+ index -1 which contain the length. */
+# define INSTALL_DTV(tcbp, dtvp) \
+ (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread. */
+# define INSTALL_NEW_DTV(dtv) \
+ (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor. */
+# define GET_DTV(tcbp) \
+ (((tcbhead_t *) (tcbp))->dtv)
+
+/* Code to initially initialize the thread pointer.
+ *
+ * Set TP to the address _after_ tcbhead_t. This will allow us
+ * to change the size of tcbhead_t without having to re-link everything.
+ *
+ * secondcall has something to do with USE__THREAD,
+ * seems to always be 0 so we don't care about it.
+ *
+ * This has to return NULL on success (or a string with the failure text).
+ * It's hard to fail this, so return NULL always.
+ */
+# define TLS_INIT_TP(tcbp, secondcall) \
+ ({__thread_self = ((tcbhead_t *)tcbp + 1); NULL;})
+
+/* Return the address of the dtv for the current thread.
+ *
+ * Dereference TP, offset to dtv - really straightforward.
+ * Remember that we made TP point to after tcb, so we need to reverse that.
+ */
+# define THREAD_DTV() \
+ ((((tcbhead_t *)__thread_self)-1)->dtv)
+
+/* Return the thread descriptor for the current thread.
+ *
+ * Return a pointer to the TLS_PRE area where we allocated space for
+ * a struct pthread. Again, TP points to after tcbhead_t, compensate with
+ * TLS_INIT_TCB_SIZE.
+ *
+ * I regard this is a seperate system from the "normal" TLS.
+ */
+# define THREAD_SELF \
+ ((struct pthread *) ((char *) __thread_self - TLS_INIT_TCB_SIZE \
+ - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF. */
+# define DB_THREAD_SELF \
+ CONST_THREAD_AREA (64, sizeof (struct pthread))
+
+/* Access to data in the thread descriptor is easy. */
+# define THREAD_GETMEM(descr, member) \
+ descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+ descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+ descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+ descr->member[idx] = (value)
+
+/* Get and set the global scope generation counter in struct pthread. */
+# define THREAD_GSCOPE_FLAG_UNUSED 0
+# define THREAD_GSCOPE_FLAG_USED 1
+# define THREAD_GSCOPE_FLAG_WAIT 2
+# define THREAD_GSCOPE_RESET_FLAG() \
+ do \
+ { int __res \
+ = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \
+ THREAD_GSCOPE_FLAG_UNUSED); \
+ if (__res == THREAD_GSCOPE_FLAG_WAIT) \
+ lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+ } \
+ while (0)
+# define THREAD_GSCOPE_SET_FLAG() \
+ do \
+ { \
+ THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \
+ atomic_write_barrier (); \
+ } \
+ while (0)
+# define THREAD_GSCOPE_WAIT() \
+ GL(dl_wait_lookup_done) ()
+
+# endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/libpthread/nptl/sysdeps/kvx/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/kvx/unwind-forcedunwind.c
new file mode 100644
index 000000000..b9618dead
--- /dev/null
+++ b/libpthread/nptl/sysdeps/kvx/unwind-forcedunwind.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ 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; see the file COPYING.LIB. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unwind.h>
+#include <pthreadP.h>
+#include <sysdep.h>
+#include <libgcc_s.h>
+#include <unwind-resume.h>
+
+#define __libc_dlopen(x) dlopen(x, (RTLD_LOCAL | RTLD_LAZY))
+#define __libc_dlsym dlsym
+#define __libc_dlclose dlclose
+
+static void *libgcc_s_handle;
+void (*__libgcc_s_resume) (struct _Unwind_Exception *exc)
+ attribute_hidden __attribute__ ((noreturn));
+static _Unwind_Reason_Code (*libgcc_s_personality) PERSONALITY_PROTO;
+static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
+ (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
+static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
+static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *);
+static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *);
+
+void
+__attribute_noinline__
+pthread_cancel_init (void)
+{
+ void *resume;
+ void *personality;
+ void *forcedunwind;
+ void *getcfa;
+ void *handle;
+ void *sjlj_register, *sjlj_unregister;
+
+ if (__builtin_expect (libgcc_s_handle != NULL, 1))
+ {
+ /* Force gcc to reload all values. */
+ __asm__ __volatile__ ("" ::: "memory");
+ return;
+ }
+
+ handle = __libc_dlopen (LIBGCC_S_SO);
+
+ resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume");
+ personality = __libc_dlsym (handle, "__gcc_personality_sj0");
+ forcedunwind = __libc_dlsym (handle, "_Unwind_SjLj_ForcedUnwind");
+ getcfa = __libc_dlsym (handle, "_Unwind_GetCFA");
+ sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register");
+ sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister");
+
+ if ((handle == NULL)
+ || (resume == NULL)
+ || (personality == NULL)
+ || (forcedunwind == NULL)
+ || (getcfa == NULL)
+ || (sjlj_register == NULL)
+ || (sjlj_unregister == NULL)
+#ifdef ARCH_CANCEL_INIT
+ || ARCH_CANCEL_INIT (handle)
+#endif
+ )
+ {
+ fprintf (stderr,
+ LIBGCC_S_SO " must be installed for pthread_cancel to work\n");
+ abort();
+ }
+
+ __libgcc_s_resume = resume;
+ libgcc_s_personality = personality;
+ libgcc_s_forcedunwind = forcedunwind;
+ libgcc_s_sjlj_register = sjlj_register;
+ libgcc_s_sjlj_unregister = sjlj_unregister;
+ libgcc_s_getcfa = getcfa;
+ /* Make sure libgcc_s_handle is written last. Otherwise,
+ pthread_cancel_init might return early even when the pointer the
+ caller is interested in is not initialized yet. */
+ atomic_write_barrier ();
+ libgcc_s_handle = handle;
+}
+
+void
+__libc_freeres_fn_section
+__unwind_freeres (void)
+{
+ void *handle = libgcc_s_handle;
+ if (handle != NULL)
+ {
+ libgcc_s_handle = NULL;
+ __libc_dlclose (handle);
+ }
+}
+
+#if !HAVE_ARCH_UNWIND_RESUME
+void attribute_hidden
+_Unwind_Resume (struct _Unwind_Exception *exc)
+{
+ if (__builtin_expect (libgcc_s_handle == NULL, 0))
+ pthread_cancel_init ();
+
+ __libgcc_s_resume(exc);
+}
+#endif
+
+_Unwind_Reason_Code attribute_hidden
+__gcc_personality_v0 PERSONALITY_PROTO
+{
+ if (__builtin_expect (libgcc_s_handle == NULL, 0))
+ pthread_cancel_init ();
+
+ return libgcc_s_personality PERSONALITY_ARGS;
+}
+
+_Unwind_Reason_Code attribute_hidden
+_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
+ void *stop_argument)
+{
+ if (__builtin_expect (libgcc_s_handle == NULL, 0))
+ pthread_cancel_init ();
+
+ return libgcc_s_forcedunwind (exc, stop, stop_argument);
+}
+
+_Unwind_Word attribute_hidden
+_Unwind_GetCFA (struct _Unwind_Context *context)
+{
+ if (__builtin_expect (libgcc_s_handle == NULL, 0))
+ pthread_cancel_init ();
+
+ return libgcc_s_getcfa (context);
+}
+
+void
+_Unwind_SjLj_Register (struct SjLj_Function_Context *fc)
+{
+ if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0))
+ pthread_cancel_init ();
+
+ libgcc_s_sjlj_register (fc);
+}
+
+void
+_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc)
+{
+ if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0))
+ pthread_cancel_init ();
+
+ libgcc_s_sjlj_unregister (fc);
+}
diff --git a/libpthread/nptl/sysdeps/pthread/Makefile.in b/libpthread/nptl/sysdeps/pthread/Makefile.in
index 6c09e7b7e..70546bc0e 100644
--- a/libpthread/nptl/sysdeps/pthread/Makefile.in
+++ b/libpthread/nptl/sysdeps/pthread/Makefile.in
@@ -44,7 +44,9 @@ CFLAGS-unwind-forcedunwind.c = -fexceptions -fasynchronous-unwind-tables
CFLAGS-OMIT-librt-cancellation.c = -DIS_IN_libpthread
CFLAGS-librt-cancellation.c = -DIS_IN_librt \
-fexceptions -fasynchronous-unwind-tables
+ifneq ($(TARGET_ARCH),kvx)
libpthread-so-y += $(patsubst %,$(libpthread_pthread_OUT)/%.oS, unwind-forcedunwind)
+endif
librt-pt-routines-y = librt-cancellation.c
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/Makefile
new file mode 100644
index 000000000..0d6f2f45d
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2019 Kalray
+#
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../../../../
+top_builddir=../../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/Makefile.arch
new file mode 100644
index 000000000..8af56320c
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/Makefile.arch
@@ -0,0 +1,14 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2019 Kalray
+#
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+#
+
+libpthread_linux_arch_SSRC =
+libpthread_linux_arch_CSRC = pthread_once.c
+
+libc_linux_arch_CSRC = fork.c
+
+CFLAGS += $(SSP_ALL_CFLAGS)
+
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/bits/pthreadtypes.h
new file mode 100644
index 000000000..e1bfe51cf
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/bits/pthreadtypes.h
@@ -0,0 +1,166 @@
+/*
+ * This file is subject to the terms and conditions of the LGPL V2.1
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2019 Kalray Inc.
+ */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H 1
+
+#include <endian.h>
+
+#define __SIZEOF_PTHREAD_ATTR_T 64
+#define __SIZEOF_PTHREAD_MUTEX_T 48
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 8
+#define __SIZEOF_PTHREAD_COND_T 72
+#define __SIZEOF_PTHREAD_COND_COMPAT_T 48
+#define __SIZEOF_PTHREAD_CONDATTR_T 8
+#define __SIZEOF_PTHREAD_RWLOCK_T 80
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 16
+#define __SIZEOF_PTHREAD_BARRIER_T 32
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 16
+
+#define __PTHREAD_RWLOCK_INT_FLAGS_SHARED 1
+
+/* Thread identifiers. The structure of the attribute type is not
+ exposed on purpose. */
+typedef unsigned long int pthread_t;
+
+
+union pthread_attr_t
+{
+ char __size[__SIZEOF_PTHREAD_ATTR_T];
+ long int __align;
+};
+#ifndef __have_pthread_attr_t
+typedef union pthread_attr_t pthread_attr_t;
+# define __have_pthread_attr_t1
+#endif
+
+typedef struct __pthread_internal_list
+{
+ struct __pthread_internal_list *__prev;
+ struct __pthread_internal_list *__next;
+} __pthread_list_t;
+
+
+/* Data structures for mutex handling. The structure of the attribute
+ type is not exposed on purpose. */
+typedef union
+{
+ struct __pthread_mutex_s
+ {
+ int __lock;
+ unsigned int __count;
+ int __owner;
+ unsigned int __nusers;
+ /* KIND must stay at this position in the structure to maintain
+ binary compatibility with static initializers. */
+ int __kind;
+ int __spins;
+ __pthread_list_t __list;
+#define __PTHREAD_MUTEX_HAVE_PREV 1
+ } __data;
+ char __size[__SIZEOF_PTHREAD_MUTEX_T];
+ long int __align;
+} pthread_mutex_t;
+
+/* Mutex __spins initializer used by PTHREAD_MUTEX_INITIALIZER. */
+#define __PTHREAD_SPINS 0
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+ long int __align;
+} pthread_mutexattr_t;
+
+/* Data structure for conditional variable handling. The structure of
+ the attribute type is not exposed on purpose. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __futex;
+ __extension__ unsigned long long int __total_seq;
+ __extension__ unsigned long long int __wakeup_seq;
+ __extension__ unsigned long long int __woken_seq;
+ void *__mutex;
+ unsigned int __nwaiters;
+ unsigned int __broadcast_seq;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_COND_T];
+ __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+ int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling. The
+ structure of the attribute type is not exposed on purpose. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __nr_readers;
+ unsigned int __readers_wakeup;
+ unsigned int __writer_wakeup;
+ unsigned int __nr_readers_queued;
+ unsigned int __nr_writers_queued;
+ int __writer;
+ int __shared;
+ unsigned long int __pad1;
+ unsigned long int __pad2;
+ unsigned int __flags;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+ long int __align;
+} pthread_rwlock_t;
+
+#define __PTHREAD_RWLOCK_ELISION_EXTRA 0
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+ long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type. */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type. The structure of the type is
+ deliberately not exposed. */
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIER_T];
+ long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+ int __align;
+} pthread_barrierattr_t;
+#endif
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/bits/semaphore.h
new file mode 100644
index 000000000..0acafdbb0
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/bits/semaphore.h
@@ -0,0 +1,30 @@
+/*
+ * This file is subject to the terms and conditions of the LGPL V2.1
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2019 Kalray Inc.
+ */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_SEM_T 32
+#else
+# define __SIZEOF_SEM_T 16
+#endif
+
+
+/* Value returned if `sem_open' failed. */
+#define SEM_FAILED ((sem_t *) 0)
+
+
+typedef union
+{
+ char __size[__SIZEOF_SEM_T];
+ long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/createthread.c
new file mode 100644
index 000000000..1b82c9190
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/createthread.c
@@ -0,0 +1,14 @@
+/*
+ * This file is subject to the terms and conditions of the LGPL V2.1
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2019 Kalray Inc.
+ */
+
+/* Value passed to 'clone' for initialization of the thread register. */
+#define TLS_VALUE ((void *) (pd) \
+ + TLS_PRE_TCB_SIZE + TLS_INIT_TCB_SIZE)
+
+/* Get the real implementation. */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/fork.c
new file mode 100644
index 000000000..4f7044a0b
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/fork.c
@@ -0,0 +1,11 @@
+#include <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+#define ARCH_FORK() \
+ INLINE_SYSCALL (clone, 5, \
+ CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \
+ NULL, &THREAD_SELF->tid, NULL)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/pthread_once.c
new file mode 100644
index 000000000..0d2749edf
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/pthread_once.c
@@ -0,0 +1,77 @@
+/*
+ * This file is subject to the terms and conditions of the LGPL V2.1
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2019 Kalray Inc.
+ */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+unsigned long int __fork_generation attribute_hidden;
+
+static void
+clear_once_control (void *arg)
+{
+ pthread_once_t *once_control = (pthread_once_t *) arg;
+
+ *once_control = 0;
+ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+
+int
+__pthread_once (once_control, init_routine)
+ pthread_once_t *once_control;
+ void (*init_routine) (void);
+{
+ while (1)
+ {
+ int oldval, val, newval;
+
+ val = *once_control;
+ do
+ {
+ /* Check if the initialized has already been done. */
+ if ((val & 2) != 0)
+ return 0;
+
+ oldval = val;
+ newval = (oldval & 3) | __fork_generation | 1;
+ val = atomic_compare_and_exchange_val_acq (once_control, newval, oldval);
+ } while (__builtin_expect (val != oldval, 0));
+
+ /* Check if another thread already runs the initializer. */
+ if ((oldval & 1) != 0)
+ {
+ /* Check whether the initializer execution was interrupted
+ * by a fork. */
+ if (((oldval ^ newval) & -4) == 0)
+ {
+ /* Same generation, some other thread was faster. Wait. */
+ lll_futex_wait (once_control, newval, LLL_PRIVATE);
+ continue;
+ }
+ }
+ /* This thread is the first here. Do the initialization.
+ * Register a cleanup handler so that in case the thread gets
+ * interrupted the initialization can be restarted. */
+ pthread_cleanup_push (clear_once_control, once_control);
+
+ init_routine ();
+
+ pthread_cleanup_pop (0);
+
+ /* Add one to *once_control. */
+ atomic_increment (once_control);
+
+ /* Wake up all other threads. */
+ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+ break;
+ }
+
+ return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/sysdep-cancel.h
new file mode 100644
index 000000000..09f538fc2
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kvx/sysdep-cancel.h
@@ -0,0 +1,43 @@
+/*
+ * This file is subject to the terms and conditions of the LGPV V2.1
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2019 Kalray Inc.
+ */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# if defined IS_IN_libpthread
+# define __local_multiple_threads __pthread_multiple_threads
+# elif !defined NOT_IN_libc
+# define __local_multiple_threads __libc_multiple_threads
+# endif
+
+# if defined IS_IN_libpthread || !defined NOT_IN_libc
+extern int __local_multiple_threads attribute_hidden;
+# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
+# else
+/* There is no __local_multiple_threads for librt, so use the TCB. */
+# define SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
+# endif
+
+#else
+
+/* For rtld, et cetera. */
+# define SINGLE_THREAD_P 1
+# define NO_CANCELLATION 1
+
+#endif
+
+# define RTLD_SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)