]> granicus.if.org Git - postgresql/commitdiff
Fix spinlock implementation for some !solaris sparc platforms.
authorAndres Freund <andres@anarazel.de>
Mon, 8 Sep 2014 22:47:32 +0000 (00:47 +0200)
committerAndres Freund <andres@anarazel.de>
Tue, 9 Sep 2014 21:48:03 +0000 (23:48 +0200)
Some Sparc CPUs can be run in various coherence models, ranging from
RMO (relaxed) over PSO (partial) to TSO (total). Solaris has always
run CPUs in TSO mode while in userland, but linux didn't use to and
the various *BSDs still don't. Unfortunately the sparc TAS/S_UNLOCK
were only correct under TSO. Fix that by adding the necessary memory
barrier instructions. On sparcv8+, which should be all relevant CPUs,
these are treated as NOPs if the current consistency model doesn't
require the barriers.

Discussion: 20140630222854.GW26930@awork2.anarazel.de

Will be backpatched to all released branches once a few buildfarm
cycles haven't shown up problems. As I've no access to sparc, this is
blindly written.

src/backend/port/tas/sunstudio_sparc.s
src/include/storage/s_lock.h

index 60e6e6d8087967448edfb1ab4366918762961e62..b71d1a75fdf13b1a7681ad2c64aecd5cf8d54d89 100644 (file)
@@ -37,6 +37,8 @@ pg_atomic_cas:
        !
        !   http://cvs.opensolaris.org/source/xref/on/usr/src/lib/libc/sparc/threads/sparc.il
        !
+       ! NB: We're assuming we're running on a TSO system here - solaris
+       ! userland luckily always has done so.
 
 #if defined(__sparcv9) || defined(__sparcv8plus)
        cas     [%o0],%o2,%o1
index cb4080f46478a0de0d190aedc7c558eb0bfd24c8..bc15e224efcd633255a6c711b6b49cdc00c674a2 100644 (file)
@@ -321,6 +321,12 @@ tas(volatile slock_t *lock)
 
 
 #if defined(__sparc__)         /* Sparc */
+/*
+ * Solaris has always run sparc processors in TSO (total store) mode, but
+ * linux didn't use to and the *BSDs still don't. So, be careful about
+ * acquire/release semantics. The CPU will treat superflous membars as NOPs,
+ * so it's just code space.
+ */
 #define HAS_TEST_AND_SET
 
 typedef unsigned char slock_t;
@@ -342,9 +348,50 @@ tas(volatile slock_t *lock)
 :              "=r"(_res), "+m"(*lock)
 :              "r"(lock)
 :              "memory");
+#if defined(__sparcv7)
+       /*
+        * No stbar or membar available, luckily no actually produced hardware
+        * requires a barrier.
+        */
+#elif defined(__sparcv8)
+       /* stbar is available (and required for both PSO, RMO), membar isn't */
+       __asm__ __volatile__ ("stbar     \n":::"memory");
+#else
+       /*
+        * #LoadStore (RMO) | #LoadLoad (RMO) together are the appropriate acquire
+        * barrier for sparcv8+ upwards.
+        */
+       __asm__ __volatile__ ("membar #LoadStore | #LoadLoad \n":::"memory");
+#endif
        return (int) _res;
 }
 
+#if defined(__sparcv7)
+/*
+ * No stbar or membar available, luckily no actually produced hardware
+ * requires a barrier.
+ */
+#define S_UNLOCK(lock)         (*((volatile slock_t *) (lock)) = 0)
+#elif  __sparcv8
+/* stbar is available (and required for both PSO, RMO), membar isn't */
+#define S_UNLOCK(lock) \
+do \
+{ \
+       __asm__ __volatile__ ("stbar     \n":::"memory"); \
+       *((volatile slock_t *) (lock)) = 0; \
+} while (0)
+#else
+/*
+ * #LoadStore (RMO) | #StoreStore (RMO, PSO) together are the appropriate
+ * release barrier for sparcv8+ upwards.
+ */
+do \
+{ \
+       __asm__ __volatile__ ("membar #LoadStore | #StoreStore \n":::"memory"); \
+       *((volatile slock_t *) (lock)) = 0; \
+} while (0)
+#endif
+
 #endif  /* __sparc__ */
 
 
@@ -823,8 +870,6 @@ typedef struct mutex slock_t;
 #endif  /* nextstep */
 
 
-/* These are in s_lock.c */
-
 
 #if defined(sun3)              /* Sun3 */
 #define HAS_TEST_AND_SET
@@ -832,6 +877,7 @@ typedef struct mutex slock_t;
 typedef unsigned char slock_t;
 #endif
 
+/* These are in sunstudio_(sparc|x86).s */
 
 #if defined(__SUNPRO_C) && (defined(__i386) || defined(__x86_64__) || defined(__sparc__) || defined(__sparc))
 #define HAS_TEST_AND_SET