aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-01-07 15:38:59 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2012-01-07 15:38:59 -0500
commit068e08eebbb2204f525647daad3fe15063b77820 (patch)
treedc0d36f5c7e313f9953546b6879941d3b07580fc /src
parentf517ece06379125a554472c94eb55f7fc82ff658 (diff)
downloadpostgresql-068e08eebbb2204f525647daad3fe15063b77820.tar.gz
postgresql-068e08eebbb2204f525647daad3fe15063b77820.zip
Use __sync_lock_test_and_set() for spinlocks on ARM, if available.
Historically we've used the SWPB instruction for TAS() on ARM, but this is deprecated and not available on ARMv6 and later. Instead, make use of a GCC builtin if available. We'll still fall back to SWPB if not, so as not to break existing ports using older GCC versions. Eventually we might want to try using __sync_lock_test_and_set() on some other architectures too, but for now that seems to present only risk and not reward. Back-patch to all supported versions, since people might want to use any of them on more recent ARM chips. Martin Pitt
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__ */