summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2021-02-15 04:25:38 +0100
committerBruno Haible <bruno@clisp.org>2021-02-15 04:25:38 +0100
commit0a6dc3028b79ce4f1051bbd3e9d458372d385690 (patch)
tree07d06aaec4046aa78c696c983b4f33425e52d937
parent74a0cdfeff8bc2fd136d966e84f9a276c5a2f6f8 (diff)
downloadgnulib-0a6dc3028b79ce4f1051bbd3e9d458372d385690.tar.gz
gnulib-0a6dc3028b79ce4f1051bbd3e9d458372d385690.tar.bz2
simple-atomic: New module.
* lib/simple-atomic.h: New file. * lib/simple-atomic.c: New file, based on lib/asyncsafe-spin.c. * modules/simple-atomic: New file.
-rw-r--r--ChangeLog7
-rw-r--r--lib/simple-atomic.c355
-rw-r--r--lib/simple-atomic.h49
-rw-r--r--modules/simple-atomic25
4 files changed, 436 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 9b357957c4..5d7337c36f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2021-02-14 Bruno Haible <bruno@clisp.org>
+ simple-atomic: New module.
+ * lib/simple-atomic.h: New file.
+ * lib/simple-atomic.c: New file, based on lib/asyncsafe-spin.c.
+ * modules/simple-atomic: New file.
+
+2021-02-14 Bruno Haible <bruno@clisp.org>
+
Fix distinction of 32-bit/64-bit mode with xlc 13.1.3 on AIX.
* m4/host-cpu-c-abi.m4 (gl_HOST_CPU_C_ABI, gl_HOST_CPU_C_ABI_32BIT):
Test __LP64__ instead of _ARCH_PPC64.
diff --git a/lib/simple-atomic.c b/lib/simple-atomic.c
new file mode 100644
index 0000000000..17625fb068
--- /dev/null
+++ b/lib/simple-atomic.c
@@ -0,0 +1,355 @@
+/* Simple atomic operations for multithreading.
+ Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2021. */
+
+#include <config.h>
+
+/* Specification. */
+#include "simple-atomic.h"
+
+#if defined _WIN32 && ! defined __CYGWIN__
+/* Native Windows. */
+
+# include <windows.h>
+
+void
+memory_barrier (void)
+{
+ /* MemoryBarrier
+ <https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-memorybarrier> */
+ MemoryBarrier ();
+}
+
+unsigned int
+atomic_compare_and_swap (unsigned int volatile *vp,
+ unsigned int cmp,
+ unsigned int newval)
+{
+ /* InterlockedCompareExchange
+ <https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchange> */
+ return InterlockedCompareExchange ((LONG volatile *) vp,
+ (LONG) newval, (LONG) cmp);
+}
+
+uintptr_t
+atomic_compare_and_swap_ptr (uintptr_t volatile *vp,
+ uintptr_t cmp,
+ uintptr_t newval)
+{
+ /* InterlockedCompareExchangePointer
+ <https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchangepointer> */
+ return InterlockedCompareExchangePointer ((void * volatile *) vp,
+ (void *) newval, (void *) cmp);
+}
+
+#elif HAVE_PTHREAD_H
+/* Some other platform that supports multi-threading.
+
+ We don't use the C11 <stdatomic.h> (available in GCC >= 4.9) because it would
+ require to link with -latomic. */
+
+# if (((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) \
+ && !defined __sparc__) \
+ || __clang_major__ >= 3) \
+ && !defined __ibmxl__
+/* Use GCC built-ins (available in GCC >= 4.1, except on SPARC, and
+ clang >= 3.0).
+ Documentation:
+ <https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html> */
+
+void
+memory_barrier (void)
+{
+ __sync_synchronize ();
+}
+
+unsigned int
+atomic_compare_and_swap (unsigned int volatile *vp,
+ unsigned int cmp,
+ unsigned int newval)
+{
+ return __sync_val_compare_and_swap (vp, cmp, newval);
+}
+
+uintptr_t
+atomic_compare_and_swap_ptr (uintptr_t volatile *vp,
+ uintptr_t cmp,
+ uintptr_t newval)
+{
+ return __sync_val_compare_and_swap (vp, cmp, newval);
+}
+
+# elif defined _AIX
+/* AIX */
+/* For older versions of GCC or xlc, use inline assembly.
+ __compare_and_swap and __compare_and_swaplp are not sufficient here. */
+
+void
+memory_barrier (void)
+{
+ asm volatile ("sync");
+}
+
+unsigned int
+atomic_compare_and_swap (unsigned int volatile *vp,
+ unsigned int cmp,
+ unsigned int newval)
+{
+ asm volatile ("sync");
+
+ unsigned int oldval;
+ asm volatile (
+# if defined __GNUC__ || defined __clang__
+ "1: lwarx %0,0,%1\n"
+ " cmpw 0,%0,%2\n"
+ " bne 0,2f\n"
+ " stwcx. %3,0,%1\n"
+ " bne 0,1b\n"
+ "2:"
+# else /* another label syntax */
+ ".L01: lwarx %0,0,%1\n"
+ " cmpw 0,%0,%2\n"
+ " bne 0,.L02\n"
+ " stwcx. %3,0,%1\n"
+ " bne 0,.L01\n"
+ ".L02:"
+# endif
+ : "=&r" (oldval)
+ : "r" (vp), "r" (cmp), "r" (newval)
+ : "cr0");
+
+ asm volatile ("isync");
+ return oldval;
+}
+
+uintptr_t
+atomic_compare_and_swap_ptr (uintptr_t volatile *vp,
+ uintptr_t cmp,
+ uintptr_t newval)
+{
+ asm volatile ("sync");
+
+ uintptr_t oldval;
+ asm volatile (
+# if defined __GNUC__ || defined __clang__
+# if defined __powerpc64__ || defined __LP64__
+ "1: ldarx %0,0,%1\n"
+ " cmpd 0,%0,%2\n"
+ " bne 0,2f\n"
+ " stdcx. %3,0,%1\n"
+ " bne 0,1b\n"
+ "2:"
+# else
+ "1: lwarx %0,0,%1\n"
+ " cmpw 0,%0,%2\n"
+ " bne 0,2f\n"
+ " stwcx. %3,0,%1\n"
+ " bne 0,1b\n"
+ "2:"
+# endif
+# else /* another label syntax */
+# if defined __powerpc64__ || defined __LP64__
+ ".L01: ldarx %0,0,%1\n"
+ " cmpd 0,%0,%2\n"
+ " bne 0,.L02\n"
+ " stdcx. %3,0,%1\n"
+ " bne 0,.L01\n"
+ ".L02:"
+# else
+ ".L01: lwarx %0,0,%1\n"
+ " cmpw 0,%0,%2\n"
+ " bne 0,.L02\n"
+ " stwcx. %3,0,%1\n"
+ " bne 0,.L01\n"
+ ".L02:"
+# endif
+# endif
+ : "=&r" (oldval)
+ : "r" (vp), "r" (cmp), "r" (newval)
+ : "cr0");
+
+ asm volatile ("isync");
+ return oldval;
+}
+
+# elif (defined __GNUC__ || defined __clang__ || defined __SUNPRO_C) && (defined __sparc || defined __i386 || defined __x86_64__)
+/* For older versions of GCC or clang, use inline assembly.
+ GCC, clang, and the Oracle Studio C 12 compiler understand GCC's extended
+ asm syntax, but the plain Oracle Studio C 11 compiler understands only
+ simple asm. */
+
+void
+memory_barrier (void)
+{
+# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590
+# if defined __i386 || defined __x86_64__
+ asm volatile ("mfence");
+# endif
+# if defined __sparc
+ asm volatile ("membar 2");
+# endif
+# else
+# if defined __i386 || defined __x86_64__
+ asm ("mfence");
+# endif
+# if defined __sparc
+ asm ("membar 2");
+# endif
+# endif
+}
+
+unsigned int
+atomic_compare_and_swap (unsigned int volatile *vp,
+ unsigned int cmp,
+ unsigned int newval)
+{
+# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590
+ unsigned int oldval;
+# if defined __i386 || defined __x86_64__
+ asm volatile (" lock\n cmpxchgl %3,(%1)"
+ : "=a" (oldval) : "r" (vp), "a" (cmp), "r" (newval) : "memory");
+# endif
+# if defined __sparc
+ asm volatile (" cas [%1],%2,%3\n"
+ " mov %3,%0"
+ : "=r" (oldval) : "r" (vp), "r" (cmp), "r" (newval) : "memory");
+# endif
+ return oldval;
+# else /* __SUNPRO_C */
+# if defined __x86_64__
+ asm (" movl %esi,%eax\n"
+ " lock\n cmpxchgl %edx,(%rdi)");
+# elif defined __i386
+ asm (" movl 16(%ebp),%ecx\n"
+ " movl 12(%ebp),%eax\n"
+ " movl 8(%ebp),%edx\n"
+ " lock\n cmpxchgl %ecx,(%edx)");
+# endif
+# if defined __sparc
+ asm (" cas [%i0],%i1,%i2\n"
+ " mov %i2,%i0");
+# endif
+# endif
+}
+
+uintptr_t
+atomic_compare_and_swap_ptr (uintptr_t volatile *vp,
+ uintptr_t cmp,
+ uintptr_t newval)
+{
+# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590
+ uintptr_t oldval;
+# if defined __x86_64__
+ asm volatile (" lock\n cmpxchgq %3,(%1)"
+ : "=a" (oldval) : "r" (vp), "a" (cmp), "r" (newval) : "memory");
+# elif defined __i386
+ asm volatile (" lock\n cmpxchgl %3,(%1)"
+ : "=a" (oldval) : "r" (vp), "a" (cmp), "r" (newval) : "memory");
+# endif
+# if defined __sparc && (defined __sparcv9 || defined __arch64__)
+ asm volatile (" casx [%1],%2,%3\n"
+ " mov %3,%0"
+ : "=r" (oldval) : "r" (vp), "r" (cmp), "r" (newval) : "memory");
+# elif defined __sparc
+ asm volatile (" cas [%1],%2,%3\n"
+ " mov %3,%0"
+ : "=r" (oldval) : "r" (vp), "r" (cmp), "r" (newval) : "memory");
+# endif
+ return oldval;
+# else /* __SUNPRO_C */
+# if defined __x86_64__
+ asm (" movl %rsi,%rax\n"
+ " lock\n cmpxchgq %rdx,(%rdi)");
+# elif defined __i386
+ asm (" movl 16(%ebp),%ecx\n"
+ " movl 12(%ebp),%eax\n"
+ " movl 8(%ebp),%edx\n"
+ " lock\n cmpxchgl %ecx,(%edx)");
+# endif
+# if defined __sparc && (defined __sparcv9 || defined __arch64__)
+ asm (" casx [%i0],%i1,%i2\n"
+ " mov %i2,%i0");
+# elif defined __sparc
+ asm (" cas [%i0],%i1,%i2\n"
+ " mov %i2,%i0");
+# endif
+# endif
+}
+
+# else
+/* Fallback code. It has some race conditions. The unit test will fail. */
+
+void
+memory_barrier (void)
+{
+}
+
+unsigned int
+atomic_compare_and_swap (unsigned int volatile *vp,
+ unsigned int cmp,
+ unsigned int newval)
+{
+ unsigned int oldval = *vp;
+ if (oldval == cmp)
+ *vp = newval;
+ return oldval;
+}
+
+uintptr_t
+atomic_compare_and_swap_ptr (uintptr_t volatile *vp,
+ uintptr_t cmp,
+ uintptr_t newval)
+{
+ uintptr_t oldval = *vp;
+ if (oldval == cmp)
+ *vp = newval;
+ return oldval;
+}
+
+# endif
+
+#else
+/* A platform that does not support multi-threading. */
+
+void
+memory_barrier (void)
+{
+}
+
+unsigned int
+atomic_compare_and_swap (unsigned int volatile *vp,
+ unsigned int cmp,
+ unsigned int newval)
+{
+ unsigned int oldval = *vp;
+ if (oldval == cmp)
+ *vp = newval;
+ return oldval;
+}
+
+uintptr_t
+atomic_compare_and_swap_ptr (uintptr_t volatile *vp,
+ uintptr_t cmp,
+ uintptr_t newval)
+{
+ uintptr_t oldval = *vp;
+ if (oldval == cmp)
+ *vp = newval;
+ return oldval;
+}
+
+#endif
diff --git a/lib/simple-atomic.h b/lib/simple-atomic.h
new file mode 100644
index 0000000000..5a34e66318
--- /dev/null
+++ b/lib/simple-atomic.h
@@ -0,0 +1,49 @@
+/* Simple atomic operations for multithreading.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2021. */
+
+#ifndef _SIMPLE_ATOMIC_H
+#define _SIMPLE_ATOMIC_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Guarantees that memory stores that are in code before this call
+ are finished before this call, and that memory loads that are in code
+ after this call are started after this call. */
+extern void memory_barrier (void);
+
+/* Stores NEWVAL in *VP if the old value *VP is == CMP.
+ Returns the old value. */
+extern unsigned int atomic_compare_and_swap (unsigned int volatile *vp,
+ unsigned int cmp,
+ unsigned int newval);
+
+/* Stores NEWVAL in *VP if the old value *VP is == CMP.
+ Returns the old value. */
+extern uintptr_t atomic_compare_and_swap_ptr (uintptr_t volatile *vp,
+ uintptr_t cmp,
+ uintptr_t newval);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SIMPLE_ATOMIC_H */
diff --git a/modules/simple-atomic b/modules/simple-atomic
new file mode 100644
index 0000000000..5f3f63d109
--- /dev/null
+++ b/modules/simple-atomic
@@ -0,0 +1,25 @@
+Description:
+Simple atomic operations for multithreading.
+
+Files:
+lib/simple-atomic.h
+lib/simple-atomic.c
+
+Depends-on:
+stdint
+sparcv8+
+
+configure.ac:
+AC_CHECK_HEADERS_ONCE([pthread.h])
+
+Makefile.am:
+lib_SOURCES += simple-atomic.c
+
+Include:
+"simple-atomic.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+all

Return to:

Send suggestions and report system problems to the System administrator.