From d05ecf05cf6abb524216e0a8416fdd78c3d7e6bf Mon Sep 17 00:00:00 2001 From: swcompiler Date: Fri, 29 Nov 2024 13:59:09 +0800 Subject: [PATCH 06/23] Sw64: Atomic and Locking Implementation --- sysdeps/sw_64/atomic-machine.h | 393 ++++++++++++++++++ sysdeps/sw_64/nptl/bits/struct_rwlock.h | 43 ++ sysdeps/sw_64/nptl/pthread_spin_lock.S | 55 +++ sysdeps/sw_64/nptl/pthread_spin_trylock.S | 56 +++ sysdeps/sw_64/sw8a/atomic-machine.h | 371 +++++++++++++++++ sysdeps/sw_64/sw8a/nptl/bits/struct_rwlock.h | 43 ++ sysdeps/sw_64/sw8a/nptl/pthread_spin_lock.S | 43 ++ .../sw_64/sw8a/nptl/pthread_spin_trylock.S | 44 ++ 8 files changed, 1048 insertions(+) create mode 100644 sysdeps/sw_64/atomic-machine.h create mode 100644 sysdeps/sw_64/nptl/bits/struct_rwlock.h create mode 100644 sysdeps/sw_64/nptl/pthread_spin_lock.S create mode 100644 sysdeps/sw_64/nptl/pthread_spin_trylock.S create mode 100644 sysdeps/sw_64/sw8a/atomic-machine.h create mode 100644 sysdeps/sw_64/sw8a/nptl/bits/struct_rwlock.h create mode 100644 sysdeps/sw_64/sw8a/nptl/pthread_spin_lock.S create mode 100644 sysdeps/sw_64/sw8a/nptl/pthread_spin_trylock.S diff --git a/sysdeps/sw_64/atomic-machine.h b/sysdeps/sw_64/atomic-machine.h new file mode 100644 index 00000000..7f379fbe --- /dev/null +++ b/sysdeps/sw_64/atomic-machine.h @@ -0,0 +1,393 @@ +/* Copyright (C) 2003-2023 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, see + . */ + +#include + +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; + +#define __HAVE_64B_ATOMICS 1 +#define USE_ATOMIC_COMPILER_BUILTINS 0 + +/* XXX Is this actually correct? */ +#define ATOMIC_EXCHANGE_USES_CAS 1 + +#define __MB " memb\n" + +/* Compare and exchange. For all of the "xxx" routines, we expect a + "__prev" and a "__cmp" variable to be provided by the enclosing scope, + in which values are returned. */ +// delete memb after the rd_f +#define __arch_compare_and_exchange_xxx_8_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __tmp, __snew, __addr64; \ + __asm__ __volatile__( \ + mb1 " bic %[__addr8],7,%[__addr64]\n" \ + " ins0b %[__new],%[__addr8],%[__snew]\n" \ + "1: lldl %[__tmp],0(%[__addr64])\n" \ + " ext0b %[__tmp],%[__addr8],%[__prev]\n" \ + " cmpeq %[__prev],%[__old],%[__cmp]\n" \ + " wr_f %[__cmp]\n" \ + " mask0b %[__tmp],%[__addr8],%[__tmp]\n" \ + " or %[__snew],%[__tmp],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr64])\n" \ + " rd_f %[__tmp]\n" \ + " beq %[__cmp],2f\n" \ + " beq %[__tmp],1b\n" \ + "2:" \ + : [__prev] "=&r"(__prev), [__snew] "=&r"(__snew), \ + [__tmp] "=&r"(__tmp), [__cmp] "=&r"(__cmp), \ + [__addr64] "=&r"(__addr64) \ + : [__addr8] "r"(mem), \ + [__old] "Ir"((uint64_t) (uint8_t) (uint64_t) (old)), \ + [__new] "r"(new) \ + : "memory"); \ + }) + +#define __arch_compare_and_exchange_xxx_16_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __tmp, __snew, __addr64; \ + __asm__ __volatile__( \ + mb1 " bic %[__addr16],7,%[__addr64]\n" \ + " ins1b %[__new],%[__addr16],%[__snew]\n" \ + "1: lldl %[__tmp],0(%[__addr64])\n" \ + " ext1b %[__tmp],%[__addr16],%[__prev]\n" \ + " cmpeq %[__prev],%[__old],%[__cmp]\n" \ + " wr_f %[__cmp]\n" \ + " mask1b %[__tmp],%[__addr16],%[__tmp]\n" \ + " or %[__snew],%[__tmp],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr64])\n" \ + " rd_f %[__tmp]\n" \ + " beq %[__cmp],2f\n" \ + " beq %[__tmp],1b\n" \ + "2:" \ + : [__prev] "=&r"(__prev), [__snew] "=&r"(__snew), \ + [__tmp] "=&r"(__tmp), [__cmp] "=&r"(__cmp), \ + [__addr64] "=&r"(__addr64) \ + : [__addr16] "r"(mem), \ + [__old] "Ir"((uint64_t) (uint16_t) (uint64_t) (old)), \ + [__new] "r"(new) \ + : "memory"); \ + }) +#define __arch_compare_and_exchange_xxx_32_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __addr, __tmp; \ + __asm__ __volatile__( \ + mb1 " ldi %[__addr],%[__mem]\n" \ + "1: lldw %[__prev],0(%[__addr])\n" \ + " cmpeq %[__prev],%[__old],%[__tmp]\n" \ + " wr_f %[__tmp]\n" \ + " mov %[__new],%[__cmp]\n" \ + " lstw %[__cmp],0(%[__addr])\n" \ + " rd_f %[__cmp]\n" \ + " beq %[__tmp],2f\n" \ + " beq %[__cmp],1b\n" \ + "2:" \ + : [__prev] "=&r"(__prev), [__cmp] "=&r"(__cmp), [__tmp] "=&r"(__tmp), \ + [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), \ + [__old] "Ir"((uint64_t) (atomic32_t) (uint64_t) (old)), \ + [__new] "Ir"(new) \ + : "memory"); \ + }) + +#define __arch_compare_and_exchange_xxx_64_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __addr, __tmp; \ + __asm__ __volatile__(mb1 " ldi %[__addr],%[__mem]\n" \ + "1: lldl %[__prev],0(%[__addr])\n" \ + " cmpeq %[__prev],%[__old],%[__tmp]\n" \ + " wr_f %[__tmp]\n" \ + " mov %[__new],%[__cmp]\n" \ + " lstl %[__cmp],0(%[__addr])\n" \ + " rd_f %[__cmp]\n" \ + " beq %[__tmp],2f\n" \ + " beq %[__cmp],1b\n" \ + "2:" \ + : [__prev] "=&r"(__prev), [__cmp] "=&r"(__cmp), \ + [__tmp] "=&r"(__tmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), \ + [__old] "Ir"((uint64_t) (old)), [__new] "Ir"(new) \ + : "memory"); \ + }) +/* For all "bool" routines, we return FALSE if exchange succesful. */ + +#define __arch_compare_and_exchange_bool_8_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_8_int (mem, new, old, mb1, mb2); \ + !__cmp; \ + }) + +#define __arch_compare_and_exchange_bool_16_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_16_int (mem, new, old, mb1, mb2); \ + !__cmp; \ + }) + +#define __arch_compare_and_exchange_bool_32_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_32_int (mem, new, old, mb1, mb2); \ + !__cmp; \ + }) + +#define __arch_compare_and_exchange_bool_64_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_64_int (mem, new, old, mb1, mb2); \ + !__cmp; \ + }) + +/* For all "val" routines, return the old value whether exchange + successful or not. */ + +#define __arch_compare_and_exchange_val_8_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_8_int (mem, new, old, mb1, mb2); \ + (typeof (*mem)) __prev; \ + }) + +#define __arch_compare_and_exchange_val_16_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_16_int (mem, new, old, mb1, mb2); \ + (typeof (*mem)) __prev; \ + }) + +#define __arch_compare_and_exchange_val_32_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_32_int (mem, new, old, mb1, mb2); \ + (typeof (*mem)) __prev; \ + }) + +#define __arch_compare_and_exchange_val_64_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_64_int (mem, new, old, mb1, mb2); \ + (typeof (*mem)) __prev; \ + }) + +/* Compare and exchange with "acquire" semantics, ie barrier after. */ + +#define atomic_compare_and_exchange_bool_acq(mem, new, old) \ + __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, mem, new, old, \ + "", __MB) + +#define atomic_compare_and_exchange_val_acq(mem, new, old) \ + __atomic_val_bysize (__arch_compare_and_exchange_val, int, mem, new, old, \ + "", __MB) + +/* Compare and exchange with "release" semantics, ie barrier before. */ + +#define atomic_compare_and_exchange_val_rel(mem, new, old) \ + __atomic_val_bysize (__arch_compare_and_exchange_val, int, mem, new, old, \ + __MB, "") + +/* Atomically store value and return the previous value. */ + +#define __arch_exchange_8_int(mem, value, mb1, mb2) \ + ({ \ + unsigned long __tmp, __addr64, __sval, __tmp1; \ + __typeof (*mem) __ret; \ + __asm__ __volatile__( \ + mb1 " bic %[__addr8],7,%[__addr64]\n" \ + " ins0b %[__value],%[__addr8],%[__sval]\n" \ + "1: lldl %[__tmp],0(%[__addr64])\n" \ + " ldi %[__tmp1],1\n" \ + " wr_f %[__tmp1]\n" \ + " ext0b %[__tmp],%[__addr8],%[__ret]\n" \ + " mask0b %[__tmp],%[__addr8],%[__tmp]\n" \ + " or %[__sval],%[__tmp],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr64])\n" \ + " rd_f %[__tmp]\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__sval] "=&r"(__sval), [__tmp] "=&r"(__tmp), \ + [__tmp1] "=&r"(__tmp1), [__addr64] "=&r"(__addr64) \ + : [__addr8] "r"(mem), [__value] "r"(value) \ + : "memory"); \ + __ret; \ + }) + +#define __arch_exchange_16_int(mem, value, mb1, mb2) \ + ({ \ + unsigned long __tmp, __addr64, __sval, __tmp1; \ + __typeof (*mem) __ret; \ + __asm__ __volatile__( \ + mb1 " bic %[__addr16],7,%[__addr64]\n" \ + " ins1b %[__value],%[__addr16],%[__sval]\n" \ + "1: lldl %[__tmp],0(%[__addr64])\n" \ + " ldi %[__tmp1],1\n" \ + " wr_f %[__tmp1]\n" \ + " ext1b %[__tmp],%[__addr16],%[__ret]\n" \ + " mask1b %[__tmp],%[__addr16],%[__tmp]\n" \ + " or %[__sval],%[__tmp],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr64])\n" \ + " rd_f %[__tmp]\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__sval] "=&r"(__sval), [__tmp] "=&r"(__tmp), \ + [__tmp1] "=&r"(__tmp1), [__addr64] "=&r"(__addr64) \ + : [__addr16] "r"(mem), [__value] "r"(value) \ + : "memory"); \ + __ret; \ + }) +#define __arch_exchange_32_int(mem, value, mb1, mb2) \ + ({ \ + signed int __tmp; \ + __typeof (*mem) __ret; \ + unsigned long __addr; \ + __asm__ __volatile__( \ + mb1 " ldi %[__addr],%[__mem]\n" \ + "1: lldw %[__ret],0(%[__addr])\n" \ + " ldi %[__tmp],1\n" \ + " wr_f %[__tmp]\n" \ + " mov %[__val],%[__tmp]\n" \ + " lstw %[__tmp],0(%[__addr])\n" \ + " rd_f %[__tmp]\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__tmp] "=&r"(__tmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), [__val] "Ir"(value) \ + : "memory"); \ + __ret; \ + }) + +#define __arch_exchange_64_int(mem, value, mb1, mb2) \ + ({ \ + unsigned long __tmp, __addr; \ + __typeof (*mem) __ret; \ + __asm__ __volatile__( \ + mb1 " ldi %[__addr],%[__mem]\n" \ + "1: lldl %[__ret],0(%[__addr])\n" \ + " ldi %[__tmp],1\n" \ + " wr_f %[__tmp]\n" \ + " mov %[__val],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr])\n" \ + " rd_f %[__tmp]\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__tmp] "=&r"(__tmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), [__val] "Ir"(value) \ + : "memory"); \ + __ret; \ + }) + +#define atomic_exchange_acq(mem, value) \ + __atomic_val_bysize (__arch_exchange, int, mem, value, "", __MB) + +#define atomic_exchange_rel(mem, value) \ + __atomic_val_bysize (__arch_exchange, int, mem, value, __MB, "") + +/* Atomically add value and return the previous (unincremented) value. */ + +#define __arch_exchange_and_add_8_int(mem, value, mb1, mb2) \ + ({ \ + __builtin_trap (); \ + 0; \ + }) + +#define __arch_exchange_and_add_16_int(mem, value, mb1, mb2) \ + ({ \ + __builtin_trap (); \ + 0; \ + }) + +#define __arch_exchange_and_add_32_int(mem, value, mb1, mb2) \ + ({ \ + signed int __tmp; \ + __typeof (*mem) __ret; \ + unsigned long __addr; \ + __asm__ __volatile__( \ + mb1 " ldi %[__addr],%[__mem]\n" \ + "1: lldw %[__ret],0(%[__addr])\n" \ + " ldi %[__tmp],1\n" \ + " wr_f %[__tmp]\n" \ + " addw %[__ret],%[__val],%[__tmp]\n" \ + " lstw %[__tmp],0(%[__addr])\n" \ + " rd_f %[__tmp]\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__tmp] "=&r"(__tmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), [__val] "Ir"((signed int) (value)) \ + : "memory"); \ + __ret; \ + }) + +#define __arch_exchange_and_add_64_int(mem, value, mb1, mb2) \ + ({ \ + unsigned long __tmp, __addr; \ + __typeof (*mem) __ret; \ + __asm__ __volatile__( \ + mb1 " ldi %[__addr],%[__mem]\n" \ + "1: lldl %[__ret],0(%[__addr])\n" \ + " ldi %[__tmp],1\n" \ + " wr_f %[__tmp]\n" \ + " addl %[__ret],%[__val],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr])\n" \ + " rd_f %[__tmp]\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__tmp] "=&r"(__tmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), [__val] "Ir"((unsigned long) (value)) \ + : "memory"); \ + __ret; \ + }) + +/* ??? Barrier semantics for atomic_exchange_and_add appear to be + undefined. Use full barrier for now, as that's safe. */ +#define atomic_exchange_and_add(mem, value) \ + __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, __MB, __MB) + +/* ??? Blah, I'm lazy. Implement these later. Can do better than the + compare-and-exchange loop provided by generic code. + +#define atomic_decrement_if_positive(mem) +#define atomic_bit_test_set(mem, bit) + +*/ +#define atomic_full_barrier() __asm("memb" : : : "memory"); +#define atomic_read_barrier() __asm("memb" : : : "memory"); +#define atomic_write_barrier() __asm("memb" : : : "memory"); diff --git a/sysdeps/sw_64/nptl/bits/struct_rwlock.h b/sysdeps/sw_64/nptl/bits/struct_rwlock.h new file mode 100644 index 00000000..8cbeefc1 --- /dev/null +++ b/sysdeps/sw_64/nptl/bits/struct_rwlock.h @@ -0,0 +1,43 @@ +/* Sw_64 internal rwlock struct definitions. + Copyright (C) 2019-2023 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, see + . */ + +#ifndef _RWLOCK_INTERNAL_H +#define _RWLOCK_INTERNAL_H + +struct __pthread_rwlock_arch_t +{ + unsigned int __readers; + unsigned int __writers; + unsigned int __wrphase_futex; + unsigned int __writers_futex; + unsigned int __pad3; + unsigned int __pad4; + int __cur_writer; + int __shared; + unsigned long int __pad1; + unsigned long int __pad2; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; +}; + +#define __PTHREAD_RWLOCK_INITIALIZER(__flags) \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, __flags + +#endif diff --git a/sysdeps/sw_64/nptl/pthread_spin_lock.S b/sysdeps/sw_64/nptl/pthread_spin_lock.S new file mode 100644 index 00000000..b7e44839 --- /dev/null +++ b/sysdeps/sw_64/nptl/pthread_spin_lock.S @@ -0,0 +1,55 @@ +/* Copyright (C) 2003-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson , 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, see + . */ + +#include + + .text + .align 4 + + .globl __pthread_spin_lock + .ent __pthread_spin_lock +__pthread_spin_lock: + .frame $sp, 0, $26, 0 + .prologue 0 + + memb +0: lldw $1, 0($16) + xor $1, 1, $1 + ldi $0, 0 + wr_f $1 + + ldi $2, 1 + lstw $2, 0($16) + rd_f $2 + beq $2, 1f + ret + +1: ldw $1, 0($16) + bne $1, 1b + unop + br 0b + + + + + .end __pthread_spin_lock +versioned_symbol (libc, __pthread_spin_lock, pthread_spin_lock, GLIBC_2_34) + +#if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_2, GLIBC_2_34) +compat_symbol (libpthread, __pthread_spin_lock, pthread_spin_lock, GLIBC_2_2) +#endif diff --git a/sysdeps/sw_64/nptl/pthread_spin_trylock.S b/sysdeps/sw_64/nptl/pthread_spin_trylock.S new file mode 100644 index 00000000..8551c34a --- /dev/null +++ b/sysdeps/sw_64/nptl/pthread_spin_trylock.S @@ -0,0 +1,56 @@ +/* Copyright (C) 2003-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson , 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, see + . */ + +#include + +#define _ERRNO_H 1 +#include + + .text + .align 4 + + .globl __pthread_spin_trylock + .ent __pthread_spin_trylock +__pthread_spin_trylock: + .frame $sp, 0, $26, 0 + .prologue 0 + + memb +0: lldw $1, 0($16) + xor $1, 1, $1 + ldi $2, 1 + ldi $0, EBUSY + wr_f $1 + + lstw $2, 0($16) + rd_f $2 + beq $1, 1f + beq $2, 2f + ldi $0, 0 + +1: ret +2: br 0b + + .end __pthread_spin_trylock +versioned_symbol (libc, __pthread_spin_trylock, pthread_spin_trylock, + GLIBC_2_34) + +#if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_2, GLIBC_2_34) +compat_symbol (libpthread, __pthread_spin_trylock, pthread_spin_trylock, + GLIBC_2_2) +#endif diff --git a/sysdeps/sw_64/sw8a/atomic-machine.h b/sysdeps/sw_64/sw8a/atomic-machine.h new file mode 100644 index 00000000..db3320fc --- /dev/null +++ b/sysdeps/sw_64/sw8a/atomic-machine.h @@ -0,0 +1,371 @@ +/* Copyright (C) 2003-2023 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, see + . */ + +#include + +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; + +#define __HAVE_64B_ATOMICS 1 +#define USE_ATOMIC_COMPILER_BUILTINS 0 + +/* XXX Is this actually correct? */ +#define ATOMIC_EXCHANGE_USES_CAS 1 + +#ifdef UP +# define __MB /* nothing */ +#else +# define __MB " memb\n" +#endif + +/* Compare and exchange. For all of the "xxx" routines, we expect a + "__prev" and a "__cmp" variable to be provided by the enclosing scope, + in which values are returned. */ +// delete memb after the rd_f +#define __arch_compare_and_exchange_xxx_8_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __tmp, __snew, __addr64; \ + __asm__ __volatile__( \ + " bic %[__addr8],7,%[__addr64]\n" \ + " inslb %[__new],%[__addr8],%[__snew]\n" \ + "1: lldl %[__tmp],0(%[__addr64])\n" \ + " extlb %[__tmp],%[__addr8],%[__prev]\n" \ + " cmpeq %[__prev],%[__old],%[__cmp]\n" \ + " beq %[__cmp],2f\n" \ + " masklb %[__tmp],%[__addr8],%[__tmp]\n" \ + " or %[__snew],%[__tmp],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr64])\n" \ + " beq %[__tmp],1b\n" \ + "2:" \ + : [__prev] "=&r"(__prev), [__snew] "=&r"(__snew), \ + [__tmp] "=&r"(__tmp), [__cmp] "=&r"(__cmp), \ + [__addr64] "=&r"(__addr64) \ + : [__addr8] "r"(mem), \ + [__old] "Ir"((uint64_t) (uint8_t) (uint64_t) (old)), \ + [__new] "r"(new) \ + : "memory"); \ + }) + +#define __arch_compare_and_exchange_xxx_16_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __tmp, __snew, __addr64; \ + __asm__ __volatile__( \ + " bic %[__addr16],7,%[__addr64]\n" \ + " inslh %[__new],%[__addr16],%[__snew]\n" \ + "1: lldl %[__tmp],0(%[__addr64])\n" \ + " extlh %[__tmp],%[__addr16],%[__prev]\n" \ + " cmpeq %[__prev],%[__old],%[__cmp]\n" \ + " beq %[__cmp],2f\n" \ + " masklh %[__tmp],%[__addr16],%[__tmp]\n" \ + " or %[__snew],%[__tmp],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr64])\n" \ + " beq %[__tmp],1b\n" \ + "2:" \ + : [__prev] "=&r"(__prev), [__snew] "=&r"(__snew), \ + [__tmp] "=&r"(__tmp), [__cmp] "=&r"(__cmp), \ + [__addr64] "=&r"(__addr64) \ + : [__addr16] "r"(mem), \ + [__old] "Ir"((uint64_t) (uint16_t) (uint64_t) (old)), \ + [__new] "r"(new) \ + : "memory"); \ + }) +#define __arch_compare_and_exchange_xxx_32_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __addr; \ + __asm__ __volatile__( \ + " ldi %[__addr],%[__mem]\n" \ + "1: lldw %[__prev],0(%[__addr])\n" \ + " cmpeq %[__prev],%[__old],%[__cmp]\n" \ + " beq %[__cmp],2f\n" \ + " mov %[__new],%[__cmp]\n" \ + " lstw %[__cmp],0(%[__addr])\n" \ + " beq %[__cmp],1b\n" \ + "2:" \ + : \ + [__prev] "=&r"(__prev), [__cmp] "=&r"(__cmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), \ + [__old] "Ir"((uint64_t) (atomic32_t) (uint64_t) (old)), \ + [__new] "Ir"(new) \ + : "memory"); \ + }) + +#define __arch_compare_and_exchange_xxx_64_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __addr; \ + __asm__ __volatile__(" ldi %[__addr],%[__mem]\n" \ + "1: lldl %[__prev],0(%[__addr])\n" \ + " cmpeq %[__prev],%[__old],%[__cmp]\n" \ + " beq %[__cmp],2f\n" \ + " mov %[__new],%[__cmp]\n" \ + " lstl %[__cmp],0(%[__addr])\n" \ + " beq %[__cmp],1b\n" \ + "2:" \ + : [__prev] "=&r"(__prev), [__cmp] "=&r"(__cmp), \ + [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), \ + [__old] "Ir"((uint64_t) (old)), [__new] "Ir"(new) \ + : "memory"); \ + }) +/* For all "bool" routines, we return FALSE if exchange succesful. */ + +#define __arch_compare_and_exchange_bool_8_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_8_int (mem, new, old, mb1, mb2); \ + !__cmp; \ + }) + +#define __arch_compare_and_exchange_bool_16_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_16_int (mem, new, old, mb1, mb2); \ + !__cmp; \ + }) + +#define __arch_compare_and_exchange_bool_32_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_32_int (mem, new, old, mb1, mb2); \ + !__cmp; \ + }) + +#define __arch_compare_and_exchange_bool_64_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_64_int (mem, new, old, mb1, mb2); \ + !__cmp; \ + }) + +/* For all "val" routines, return the old value whether exchange + successful or not. */ + +#define __arch_compare_and_exchange_val_8_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_8_int (mem, new, old, mb1, mb2); \ + (typeof (*mem)) __prev; \ + }) + +#define __arch_compare_and_exchange_val_16_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_16_int (mem, new, old, mb1, mb2); \ + (typeof (*mem)) __prev; \ + }) + +#define __arch_compare_and_exchange_val_32_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_32_int (mem, new, old, mb1, mb2); \ + (typeof (*mem)) __prev; \ + }) + +#define __arch_compare_and_exchange_val_64_int(mem, new, old, mb1, mb2) \ + ({ \ + unsigned long __prev; \ + int __cmp; \ + __arch_compare_and_exchange_xxx_64_int (mem, new, old, mb1, mb2); \ + (typeof (*mem)) __prev; \ + }) + +/* Compare and exchange with "acquire" semantics, ie barrier after. */ + +#define atomic_compare_and_exchange_bool_acq(mem, new, old) \ + __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, mem, new, old, \ + "", __MB) + +#define atomic_compare_and_exchange_val_acq(mem, new, old) \ + __atomic_val_bysize (__arch_compare_and_exchange_val, int, mem, new, old, \ + "", __MB) + +/* Compare and exchange with "release" semantics, ie barrier before. */ + +#define atomic_compare_and_exchange_val_rel(mem, new, old) \ + __atomic_val_bysize (__arch_compare_and_exchange_val, int, mem, new, old, \ + __MB, "") + +/* Atomically store value and return the previous value. */ + +#define __arch_exchange_8_int(mem, value, mb1, mb2) \ + ({ \ + unsigned long __tmp, __addr64, __sval; \ + __typeof (*mem) __ret; \ + __asm__ __volatile__(" bic %[__addr8],7,%[__addr64]\n" \ + " inslb %[__value],%[__addr8],%[__sval]\n" \ + "1: lldl %[__tmp],0(%[__addr64])\n" \ + " extlb %[__tmp],%[__addr8],%[__ret]\n" \ + " masklb %[__tmp],%[__addr8],%[__tmp]\n" \ + " or %[__sval],%[__tmp],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr64])\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__sval] "=&r"(__sval), \ + [__tmp] "=&r"(__tmp), [__addr64] "=&r"(__addr64) \ + : [__addr8] "r"(mem), [__value] "r"(value) \ + : "memory"); \ + __ret; \ + }) + +#define __arch_exchange_16_int(mem, value, mb1, mb2) \ + ({ \ + unsigned long __tmp, __addr64, __sval, __tmp1; \ + __typeof (*mem) __ret; \ + __asm__ __volatile__(" bic %[__addr16],7,%[__addr64]\n" \ + " inslh %[__value],%[__addr16],%[__sval]\n" \ + "1: lldl %[__tmp],0(%[__addr64])\n" \ + " extlh %[__tmp],%[__addr16],%[__ret]\n" \ + " masklh %[__tmp],%[__addr16],%[__tmp]\n" \ + " or %[__sval],%[__tmp],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr64])\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__sval] "=&r"(__sval), \ + [__tmp] "=&r"(__tmp), [__addr64] "=&r"(__addr64) \ + : [__addr16] "r"(mem), [__value] "r"(value) \ + : "memory"); \ + __ret; \ + }) +#define __arch_exchange_32_int(mem, value, mb1, mb2) \ + ({ \ + signed int __tmp; \ + __typeof (*mem) __ret; \ + unsigned long __addr; \ + __asm__ __volatile__( \ + " ldi %[__addr],%[__mem]\n" \ + "1: lldw %[__ret],0(%[__addr])\n" \ + " mov %[__val],%[__tmp]\n" \ + " lstw %[__tmp],0(%[__addr])\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__tmp] "=&r"(__tmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), [__val] "Ir"(value) \ + : "memory"); \ + __ret; \ + }) + +#define __arch_exchange_64_int(mem, value, mb1, mb2) \ + ({ \ + unsigned long __tmp, __addr; \ + __typeof (*mem) __ret; \ + __asm__ __volatile__( \ + " ldi %[__addr],%[__mem]\n" \ + "1: lldl %[__ret],0(%[__addr])\n" \ + " mov %[__val],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr])\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__tmp] "=&r"(__tmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), [__val] "Ir"(value) \ + : "memory"); \ + __ret; \ + }) + +#define atomic_exchange_acq(mem, value) \ + __atomic_val_bysize (__arch_exchange, int, mem, value, "", __MB) + +#define atomic_exchange_rel(mem, value) \ + __atomic_val_bysize (__arch_exchange, int, mem, value, __MB, "") + +/* Atomically add value and return the previous (unincremented) value. */ + +#define __arch_exchange_and_add_8_int(mem, value, mb1, mb2) \ + ({ \ + __builtin_trap (); \ + 0; \ + }) + +#define __arch_exchange_and_add_16_int(mem, value, mb1, mb2) \ + ({ \ + __builtin_trap (); \ + 0; \ + }) + +#define __arch_exchange_and_add_32_int(mem, value, mb1, mb2) \ + ({ \ + signed int __tmp; \ + __typeof (*mem) __ret; \ + unsigned long __addr; \ + __asm__ __volatile__( \ + " ldi %[__addr],%[__mem]\n" \ + "1: lldw %[__ret],0(%[__addr])\n" \ + " addw %[__ret],%[__val],%[__tmp]\n" \ + " lstw %[__tmp],0(%[__addr])\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__tmp] "=&r"(__tmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), [__val] "Ir"((signed int) (value)) \ + : "memory"); \ + __ret; \ + }) + +#define __arch_exchange_and_add_64_int(mem, value, mb1, mb2) \ + ({ \ + unsigned long __tmp, __addr; \ + __typeof (*mem) __ret; \ + __asm__ __volatile__( \ + " ldi %[__addr],%[__mem]\n" \ + "1: lldl %[__ret],0(%[__addr])\n" \ + " addl %[__ret],%[__val],%[__tmp]\n" \ + " lstl %[__tmp],0(%[__addr])\n" \ + " beq %[__tmp],1b\n" \ + : [__ret] "=&r"(__ret), [__tmp] "=&r"(__tmp), [__addr] "=&r"(__addr) \ + : [__mem] "m"(*(mem)), [__val] "Ir"((unsigned long) (value)) \ + : "memory"); \ + __ret; \ + }) + +/* ??? Barrier semantics for atomic_exchange_and_add appear to be + undefined. Use full barrier for now, as that's safe. */ +#define atomic_exchange_and_add(mem, value) \ + __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, __MB, __MB) + +/* ??? Blah, I'm lazy. Implement these later. Can do better than the + compare-and-exchange loop provided by generic code. + +#define atomic_decrement_if_positive(mem) +#define atomic_bit_test_set(mem, bit) + +*/ +# ifndef UP +# define atomic_full_barrier() __asm ("memb" : : : "memory"); +# define atomic_read_barrier() __asm ("memb" : : : "memory"); +# define atomic_write_barrier() __asm ("memb" : : : "memory"); +# endif diff --git a/sysdeps/sw_64/sw8a/nptl/bits/struct_rwlock.h b/sysdeps/sw_64/sw8a/nptl/bits/struct_rwlock.h new file mode 100644 index 00000000..8cbeefc1 --- /dev/null +++ b/sysdeps/sw_64/sw8a/nptl/bits/struct_rwlock.h @@ -0,0 +1,43 @@ +/* Sw_64 internal rwlock struct definitions. + Copyright (C) 2019-2023 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, see + . */ + +#ifndef _RWLOCK_INTERNAL_H +#define _RWLOCK_INTERNAL_H + +struct __pthread_rwlock_arch_t +{ + unsigned int __readers; + unsigned int __writers; + unsigned int __wrphase_futex; + unsigned int __writers_futex; + unsigned int __pad3; + unsigned int __pad4; + int __cur_writer; + int __shared; + unsigned long int __pad1; + unsigned long int __pad2; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; +}; + +#define __PTHREAD_RWLOCK_INITIALIZER(__flags) \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, __flags + +#endif diff --git a/sysdeps/sw_64/sw8a/nptl/pthread_spin_lock.S b/sysdeps/sw_64/sw8a/nptl/pthread_spin_lock.S new file mode 100644 index 00000000..ab3408a3 --- /dev/null +++ b/sysdeps/sw_64/sw8a/nptl/pthread_spin_lock.S @@ -0,0 +1,43 @@ + + +/* Copyright (C) 2003-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson , 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, see + . */ + +/* SHIPS20171102_LOCK_READ_CONDITION_WRITE. */ + .text + .align 4 + + .globl pthread_spin_lock + .ent pthread_spin_lock +pthread_spin_lock: + .frame $sp, 0, $26, 0 + .prologue 0 +0: lldw $1, 0($16) + ldi $2, 1 + ldi $0, 0 + bne $1, 1f + + lstw $2, 0($16) + beq $2, 1f + ret + +1: ldw $1, 0($16) + bne $1, 1b + unop + br 0b + .end pthread_spin_lock diff --git a/sysdeps/sw_64/sw8a/nptl/pthread_spin_trylock.S b/sysdeps/sw_64/sw8a/nptl/pthread_spin_trylock.S new file mode 100644 index 00000000..374dccae --- /dev/null +++ b/sysdeps/sw_64/sw8a/nptl/pthread_spin_trylock.S @@ -0,0 +1,44 @@ + + +/* Copyright (C) 2003-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson , 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, see + . */ + +/* SHIPS20171102_LOCK_READ_CONDITION_WRITE. */ +#define _ERRNO_H 1 +#include + + .text + .align 4 + + .globl pthread_spin_trylock + .ent pthread_spin_trylock +pthread_spin_trylock: + .frame $sp, 0, $26, 0 + .prologue 0 +0: lldw $1, 0($16) + ldi $2, 1 + ldi $0, EBUSY + bne $1, 1f + + lstw $2, 0($16) + beq $2, 2f + ldi $0, 0 + +1: ret +2: br 0b + .end pthread_spin_trylock -- 2.25.1