aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/pg_config.h.in3
-rw-r--r--src/include/storage/s_lock.h25
2 files changed, 26 insertions, 2 deletions
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 5d38f25d263..ecb0e41aadd 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -173,6 +173,9 @@
/* Define to 1 if your compiler understands __FUNCTION__. */
#undef HAVE_FUNCNAME__FUNCTION
+/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */
+#undef HAVE_GCC_INT_ATOMICS
+
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7fe01aac616..987fb9c58d2 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -252,13 +252,33 @@ tas(volatile slock_t *lock)
#endif /* __ia64__ || __ia64 */
+/*
+ * On ARM, we use __sync_lock_test_and_set(int *, int) if available, and if
+ * not fall back on the SWPB instruction. SWPB does not work on ARMv6 or
+ * later, so the compiler builtin is preferred if available. Note also that
+ * the int-width variant of the builtin works on more chips than other widths.
+ */
#if defined(__arm__) || defined(__arm)
#define HAS_TEST_AND_SET
-typedef unsigned char slock_t;
-
#define TAS(lock) tas(lock)
+#ifdef HAVE_GCC_INT_ATOMICS
+
+typedef int slock_t;
+
+static __inline__ int
+tas(volatile slock_t *lock)
+{
+ return __sync_lock_test_and_set(lock, 1);
+}
+
+#define S_UNLOCK(lock) __sync_lock_release(lock)
+
+#else /* !HAVE_GCC_INT_ATOMICS */
+
+typedef unsigned char slock_t;
+
static __inline__ int
tas(volatile slock_t *lock)
{
@@ -272,6 +292,7 @@ tas(volatile slock_t *lock)
return (int) _res;
}
+#endif /* HAVE_GCC_INT_ATOMICS */
#endif /* __arm__ */