summaryrefslogtreecommitdiffstats
path: root/libglusterfs
diff options
context:
space:
mode:
Diffstat (limited to 'libglusterfs')
-rw-r--r--libglusterfs/src/Makefile.am2
-rw-r--r--libglusterfs/src/locking.c28
-rw-r--r--libglusterfs/src/locking.h59
3 files changed, 79 insertions, 10 deletions
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am
index e0acc3c4e58..39ae9e05091 100644
--- a/libglusterfs/src/Makefile.am
+++ b/libglusterfs/src/Makefile.am
@@ -31,7 +31,7 @@ libglusterfs_la_SOURCES = dict.c xlator.c logging.c \
strfd.c parse-utils.c $(CONTRIBDIR)/mount/mntent.c \
$(CONTRIBDIR)/libexecinfo/execinfo.c quota-common-utils.c rot-buffs.c \
$(CONTRIBDIR)/timer-wheel/timer-wheel.c \
- $(CONTRIBDIR)/timer-wheel/find_last_bit.c tw.c default-args.c
+ $(CONTRIBDIR)/timer-wheel/find_last_bit.c tw.c default-args.c locking.c
nodist_libglusterfs_la_SOURCES = y.tab.c graph.lex.c defaults.c
nodist_libglusterfs_la_HEADERS = y.tab.h
diff --git a/libglusterfs/src/locking.c b/libglusterfs/src/locking.c
new file mode 100644
index 00000000000..d3b9754ef76
--- /dev/null
+++ b/libglusterfs/src/locking.c
@@ -0,0 +1,28 @@
+/*
+ Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#if defined(HAVE_SPINLOCK)
+/* None of this matters otherwise. */
+
+#include <pthread.h>
+#include <unistd.h>
+
+#define LOCKING_IMPL
+#include "locking.h"
+
+int use_spinlocks = 0;
+
+static void __attribute__((constructor))
+gf_lock_setup (void)
+{
+ use_spinlocks = (sysconf(_SC_NPROCESSORS_ONLN) > 1);
+}
+
+#endif
diff --git a/libglusterfs/src/locking.h b/libglusterfs/src/locking.h
index 24edf9aed44..71b6a286e6c 100644
--- a/libglusterfs/src/locking.h
+++ b/libglusterfs/src/locking.h
@@ -12,7 +12,8 @@
#define _LOCKING_H
#include <pthread.h>
-#ifdef GF_DARWIN_HOST_OS
+
+#if defined (GF_DARWIN_HOST_OS)
#include <libkern/OSAtomic.h>
#define pthread_spinlock_t OSSpinLock
#define pthread_spin_lock(l) OSSpinLockLock(l)
@@ -21,23 +22,63 @@
#define pthread_spin_init(l, v) (*l = v)
#endif
+#if defined (HAVE_SPINLOCK)
+
+typedef union {
+ pthread_spinlock_t spinlock;
+ pthread_mutex_t mutex;
+} gf_lock_t;
+
+#if !defined(LOCKING_IMPL)
+extern int use_spinlocks;
+
+/*
+ * Using a dispatch table would be unpleasant because we're dealing with two
+ * different types. If the dispatch contains direct pointers to pthread_xx
+ * or mutex_xxx then we have to hope that every possible union alternative
+ * starts at the same address as the union itself. I'm old enough to remember
+ * compilers where this was not the case (for alignment reasons) so I'm a bit
+ * paranoid about that. Also, I don't like casting arguments through "void *"
+ * which we'd also have to do to avoid type errors. The other alternative would
+ * be to define actual functions which pick out the right union member, and put
+ * those in the dispatch tables. Now we have a pointer dereference through the
+ * dispatch table plus a function call, which is likely to be worse than the
+ * branching here from the ?: construct. If it were a clear win it might be
+ * worth the extra complexity, but for now this way seems preferable.
+ */
+
+#define LOCK_INIT(x) (use_spinlocks \
+ ? pthread_spin_init (&((x)->spinlock), 0) \
+ : pthread_mutex_init (&((x)->mutex), 0))
+
+#define LOCK(x) (use_spinlocks \
+ ? pthread_spin_lock (&((x)->spinlock)) \
+ : pthread_mutex_lock (&((x)->mutex)))
+
+#define TRY_LOCK(x) (use_spinlocks \
+ ? pthread_spin_trylock (&((x)->spinlock)) \
+ : pthread_mutex_trylock (&((x)->mutex)))
-#if HAVE_SPINLOCK
-#define LOCK_INIT(x) pthread_spin_init (x, 0)
-#define LOCK(x) pthread_spin_lock (x)
-#define TRY_LOCK(x) pthread_spin_trylock (x)
-#define UNLOCK(x) pthread_spin_unlock (x)
-#define LOCK_DESTROY(x) pthread_spin_destroy (x)
+#define UNLOCK(x) (use_spinlocks \
+ ? pthread_spin_unlock (&((x)->spinlock)) \
+ : pthread_mutex_unlock (&((x)->mutex)))
+
+#define LOCK_DESTROY(x) (use_spinlocks \
+ ? pthread_spin_destroy (&((x)->spinlock)) \
+ : pthread_mutex_destroy (&((x)->mutex)))
+
+#endif
-typedef pthread_spinlock_t gf_lock_t;
#else
+
+typedef pthread_mutex_t gf_lock_t;
+
#define LOCK_INIT(x) pthread_mutex_init (x, 0)
#define LOCK(x) pthread_mutex_lock (x)
#define TRY_LOCK(x) pthread_mutex_trylock (x)
#define UNLOCK(x) pthread_mutex_unlock (x)
#define LOCK_DESTROY(x) pthread_mutex_destroy (x)
-typedef pthread_mutex_t gf_lock_t;
#endif /* HAVE_SPINLOCK */