>From 7d615831acfdece846a1b40c4d9e6a3f1af364ef Mon Sep 17 00:00:00 2001
From: Nils Goroll <nils.goroll@uplex.de>
Date: Wed, 27 Jun 2012 13:30:48 +0200
Subject: [PATCH] experimental: use pthread mutexes instead of spinlocks.

Should be advantagous on Linux systems with an efficient futex()- based posix
mutex implementation.

compile with CPPFLAGS=-DUSE_PTHREAD_SLOCK
use -DUSE_PTHREAD_MUTEX_ADAPTIVE_NP to use linux non-portable adaptive mutexes
(which are probably less efficient than normal mutexes)
---
 src/backend/storage/lmgr/s_lock.c |   92 +++++++++++++++++++++++++++++++++++++
 src/include/storage/s_lock.h      |   31 ++++++++++++-
 2 files changed, 121 insertions(+), 2 deletions(-)

diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c
index 13f1dae..1e13631 100644
--- a/src/backend/storage/lmgr/s_lock.c
+++ b/src/backend/storage/lmgr/s_lock.c
@@ -20,6 +20,8 @@
 
 #include "storage/s_lock.h"
 
+#ifndef USE_PTHREAD_SLOCK
+
 slock_t		dummy_spinlock;
 
 static int	spins_per_delay = DEFAULT_SPINS_PER_DELAY;
@@ -201,9 +203,98 @@ update_spins_per_delay(int shared_spins_per_delay)
  * because the definitions for these are split between this file and s_lock.h.
  */
 
+#endif /* !USE_PTHREAD_SLOCK */
 
 #ifdef HAVE_SPINLOCKS			/* skip spinlocks if requested */
 
+#ifdef USE_PTHREAD_SLOCK
+#include <pthread.h>
+void
+posix_lock(volatile slock_t *lock, const char *file, int line)
+{
+	struct slock *s_lock = (slock_t *)lock;
+	int ret;
+
+	/* XXX error recovery ! */
+
+	do {
+		ret = pthread_mutex_lock(&s_lock->mutex);
+	} while (ret != 0);
+	s_lock->held = 1;
+}
+
+void
+posix_unlock(volatile slock_t *lock, const char *file, int line)
+{
+	struct slock *s_lock = (slock_t *)lock;
+	int ret;
+
+	/* XXX error recovery ! */
+
+	s_lock->held = 0;
+	do {
+		ret = pthread_mutex_unlock(&s_lock->mutex);
+	} while (ret != 0);
+}
+
+void
+posix_init(volatile slock_t *lock)
+{
+	struct slock *s_lock = (slock_t *)lock;
+	pthread_mutexattr_t attr;
+	int ret;
+
+	if (pthread_mutexattr_init(&attr))
+		ereport(FATAL,
+		    (errmsg("pthread_mutexattr_init failed")));
+
+#ifdef USE_PTHREAD_MUTEX_ADAPTIVE_NP
+	(void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+#else
+	(void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+#endif
+
+#ifdef USE_PRIO_INHERIT
+	/*
+	 * looks like this incurs significant syscall overhead on linux
+	 */
+	(void)pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
+#endif
+
+	if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED))
+		ereport(FATAL,
+		    (errmsg("pthread_mutexattr_setpshared failed")));
+
+	s_lock->held = 0;
+
+	if (pthread_mutex_init(&s_lock->mutex, &attr))
+		ereport(FATAL,
+		    (errmsg("pthread_mutex_init failed")));
+
+	(void)pthread_mutexattr_destroy(&attr);
+}
+
+int
+posix_lock_free(volatile slock_t *lock)
+{
+	struct slock *s_lock = (slock_t *)lock;
+
+	return (s_lock->held == 0);
+}
+
+#if 0
+void
+posix_lock_destroy(slock_t *lock)
+{
+	struct slock *s_lock = lock;
+	int ret;
+
+	ret = pthread_mutex_destroy(&s_lock->mutex);
+	Assert(ret == 0);
+}
+#endif
+
+#else /* !USE_PTHREAD_SLOCK */
 
 #if defined(__GNUC__)
 
@@ -283,6 +374,7 @@ tas_dummy()						/* really means: extern int tas(slock_t
 }
 #endif   /* sun3 */
 #endif   /* not __GNUC__ */
+#endif   /* USE_PTHREAD_SLOCK */
 #endif   /* HAVE_SPINLOCKS */
 
 
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 48dc4de..ef4b3fa 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -98,6 +98,30 @@
 
 #ifdef HAVE_SPINLOCKS	/* skip spinlocks if requested */
 
+#ifdef USE_PTHREAD_SLOCK
+#include <pthread.h>
+struct slock {
+	pthread_mutex_t		mutex;
+	int			held;
+};
+
+typedef struct slock slock_t;
+
+extern void posix_lock(volatile slock_t *lock, const char *file, int line);
+extern void posix_unlock(volatile slock_t *lock, const char *file, int line);
+extern void posix_init(volatile slock_t *lock);
+extern int posix_lock_free(volatile slock_t *lock);
+
+#define S_LOCK(lock)		posix_lock((lock), __FILE__, __LINE__)
+#define S_UNLOCK(lock)		posix_unlock((lock), __FILE__, __LINE__)
+#define S_INIT_LOCK(lock)	posix_init(lock)
+#define S_LOCK_FREE(lock)	posix_lock_free(lock)
+#define SPIN_DELAY()		((void) 0)
+
+#define set_spins_per_delay(s)		((void) 0)
+#define update_spins_per_delay(s)	(0)
+#define DEFAULT_SPINS_PER_DELAY		0
+#else /* !USE_PTHREAD_SLOCK */
 
 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
 /*************************************************************************
@@ -948,7 +972,7 @@ spin_delay(void)
 #error PostgreSQL does not have native spinlock support on this platform.  To continue the compilation, rerun configure using --disable-spinlocks.  However, performance will be poor.  Please report this to pgsql-bugs@postgresql.org.
 #endif
 
-
+#endif  /* USE_PTHREAD_SLOCK */
 #else	/* !HAVE_SPINLOCKS */
 
 
@@ -969,7 +993,6 @@ extern int	tas_sema(volatile slock_t *lock);
 #define S_INIT_LOCK(lock)	s_init_lock_sema(lock)
 #define TAS(lock)	tas_sema(lock)
 
-
 #endif	/* HAVE_SPINLOCKS */
 
 
@@ -994,6 +1017,8 @@ extern int	tas_sema(volatile slock_t *lock);
 #define S_INIT_LOCK(lock)	S_UNLOCK(lock)
 #endif	 /* S_INIT_LOCK */
 
+#ifndef USE_PTHREAD_SLOCK
+
 #if !defined(SPIN_DELAY)
 #define SPIN_DELAY()	((void) 0)
 #endif	 /* SPIN_DELAY */
@@ -1002,6 +1027,7 @@ extern int	tas_sema(volatile slock_t *lock);
 extern int	tas(volatile slock_t *lock);		/* in port/.../tas.s, or
 												 * s_lock.c */
 
+
 #define TAS(lock)		tas(lock)
 #endif	 /* TAS */
 
@@ -1020,5 +1046,6 @@ extern int s_lock(volatile slock_t *lock, const char *file, int line);
 
 extern void set_spins_per_delay(int shared_spins_per_delay);
 extern int	update_spins_per_delay(int shared_spins_per_delay);
+#endif /* !USE_PTHREAD_SLOCK */
 
 #endif	 /* S_LOCK_H */
-- 
1.5.6.5

