summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/atomic.h
diff options
context:
space:
mode:
authorNiels de Vos <ndevos@redhat.com>2017-03-29 13:44:03 +0200
committerJeff Darcy <jeff@pl.atyp.us>2017-04-05 09:14:26 -0400
commit93e3c9abce1a02ac724afa382751852fa5edf713 (patch)
tree887c599c2a31ab65a2f0b2440e5f3fe8b6061afc /libglusterfs/src/atomic.h
parentd6b88e9b8b02813620c3c1a2ea49d58d29062b3e (diff)
libglusterfs: provide standardized atomic operations
The current macros ATOMIC_INCREMENT() and ATOMIC_DECREMENT() expect a lock as first argument. There are at least two issues with this approach: 1. this lock is unused on architectures that have atomic operations 2. some structures use a single lock for multiple variables By defining a gf_atomic_t type, the unused lock can be removed, saving a few bytes on modern architectures. Because the gf_atomic_t type locates the lock for the variable (in case of older architectures), each variable is protected the same on all architectures. This makes the behaviour across all architectures more equal (per variable locking, by a gf_lock_t or compiler optimization). BUG: 1437037 Change-Id: Ic164892b06ea676e6a9566f8a98b7faf0efe76d6 Signed-off-by: Niels de Vos <ndevos@redhat.com> Reviewed-on: https://review.gluster.org/16963 Smoke: Gluster Build System <jenkins@build.gluster.org> Reviewed-by: Xavier Hernandez <xhernandez@datalab.es> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org> CentOS-regression: Gluster Build System <jenkins@build.gluster.org> Reviewed-by: Amar Tumballi <amarts@redhat.com> Reviewed-by: Jeff Darcy <jeff@pl.atyp.us>
Diffstat (limited to 'libglusterfs/src/atomic.h')
-rw-r--r--libglusterfs/src/atomic.h109
1 files changed, 109 insertions, 0 deletions
diff --git a/libglusterfs/src/atomic.h b/libglusterfs/src/atomic.h
new file mode 100644
index 00000000000..71fcb1ee972
--- /dev/null
+++ b/libglusterfs/src/atomic.h
@@ -0,0 +1,109 @@
+/*
+ Copyright (c) 2017 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.
+*/
+
+#ifndef _ATOMIC_H
+#define _ATOMIC_H
+
+#include <inttypes.h>
+
+#if defined(HAVE_ATOMIC_BUILTINS) || defined(HAVE_SYNC_BUILTINS)
+/* optimized implementation, macros only */
+
+typedef struct gf_atomic_t {
+ int64_t cnt;
+} gf_atomic_t;
+
+#if defined(HAVE_ATOMIC_BUILTINS)
+
+/* all macros have a 'gf_atomic_t' as 1st argument */
+#define GF_ATOMIC_INIT(op, n) __atomic_store (&(op.cnt), __ATOMIC_RELEASE)
+#define GF_ATOMIC_GET(op) __atomic_load (&(op.cnt), __ATOMIC_ACQUIRE)
+#define GF_ATOMIC_INC(op) __atomic_add_and_fetch (&(op.cnt), 1, \
+ __ATOMIC_ACQ_REL)
+#define GF_ATOMIC_DEC(op) __atomic_sub_and_fetch (&(op.cnt), 1, \
+ __ATOMIC_ACQ_REL)
+#define GF_ATOMIC_ADD(op, n) __atomic_add_and_fetch (&(op.cnt), n, \
+ __ATOMIC_ACQ_REL)
+#define GF_ATOMIC_SUB(op, n) __atomic_sub_and_fetch (&(op.cnt), n, \
+ __ATOMIC_ACQ_REL)
+
+#else /* !HAVE_ATOMIC_BUILTINS, but HAVE_SYNC_BUILTINS */
+
+/* all macros have a 'gf_atomic_t' as 1st argument */
+#define GF_ATOMIC_INIT(op, n) ({ op.cnt = n; __sync_synchronize (); })
+#define GF_ATOMIC_GET(op) __sync_add_and_fetch (&(op.cnt), 0)
+#define GF_ATOMIC_INC(op) __sync_add_and_fetch (&(op.cnt), 1)
+#define GF_ATOMIC_DEC(op) __sync_sub_and_fetch (&(op.cnt), 1)
+#define GF_ATOMIC_ADD(op, n) __sync_add_and_fetch (&(op.cnt), n)
+#define GF_ATOMIC_SUB(op, n) __sync_sub_and_fetch (&(op.cnt), n)
+
+#endif /* HAVE_ATOMIC_BUILTINS || HAVE_SYNC_BUILTINS */
+
+#else /* no HAVE_(ATOMIC|SYNC)_BUILTINS */
+/* fallback implementation, using small inline functions to improve type
+ * checking while compiling */
+
+#include "locking.h"
+
+typedef struct gf_atomic_t {
+ int64_t cnt;
+ gf_lock_t lk;
+} gf_atomic_t;
+
+
+static inline void
+gf_atomic_init (gf_atomic_t *op, int64_t cnt)
+{
+ LOCK_INIT (&op->lk);
+ op->cnt = cnt;
+}
+
+
+static inline uint64_t
+gf_atomic_get (gf_atomic_t *op)
+{
+ uint64_t ret;
+
+ LOCK (&op->lk);
+ {
+ ret = op->cnt;
+ }
+ UNLOCK (&op->lk);
+
+ return ret;
+}
+
+
+static inline int64_t
+gf_atomic_add (gf_atomic_t *op, int64_t n)
+{
+ uint64_t ret;
+
+ LOCK (&op->lk);
+ {
+ op->cnt += n;
+ ret = op->cnt;
+ }
+ UNLOCK (&op->lk);
+
+ return ret;
+}
+
+
+#define GF_ATOMIC_INIT(op, cnt) gf_atomic_init (&op, cnt)
+#define GF_ATOMIC_GET(op) gf_atomic_get (&op)
+#define GF_ATOMIC_INC(op) gf_atomic_add (&op, 1)
+#define GF_ATOMIC_DEC(op) gf_atomic_add (&op, -1)
+#define GF_ATOMIC_ADD(op, n) gf_atomic_add (&op, n)
+#define GF_ATOMIC_SUB(op, n) gf_atomic_add (&op, -n)
+
+#endif /* HAVE_ATOMIC_SYNC_OPS */
+
+#endif /* _ATOMIC_H */