[libgee/atomic] Change atomic



commit d207de3ac96bfe2d977eeba64c7e1eb9f9a37242
Author: Maciej Piechotka <uzytkownik2 gmail com>
Date:   Mon Dec 17 21:10:56 2012 +0100

    Change atomic

 gee/Makefile.am        |    1 +
 gee/gee-internal.h     |  295 ++++++++++++++++++++++++++++++++++++++++++++++++
 gee/gee-internal.vapi  |   25 ++++
 gee/hazardpointer.vala |   50 ++++-----
 4 files changed, 343 insertions(+), 28 deletions(-)
---
diff --git a/gee/Makefile.am b/gee/Makefile.am
index aeaffcd..b85950b 100644
--- a/gee/Makefile.am
+++ b/gee/Makefile.am
@@ -76,6 +76,7 @@ libgee_0_8_la_VALAFLAGS = \
        -h gee-internals.h \
        --internal-vapi gee-internals-0.8.vapi \
        --library gee-0.8 --gir Gee-0.8.gir \
+       --pkg gee-internal --vapidir $(top_srcdir)/gee \
        $(COVERAGE_VALAFLAGS) \
        $(VALAFLAGS) \
        $(NULL)
diff --git a/gee/gee-internal.h b/gee/gee-internal.h
new file mode 100644
index 0000000..fa03e12
--- /dev/null
+++ b/gee/gee-internal.h
@@ -0,0 +1,295 @@
+
+typedef enum {
+  GEE_INTERNAL_ATOMIC_IMPL_STD,
+  GEE_INTERNAL_ATOMIC_IMPL_GCC,
+  GEE_INTERNAL_ATOMIC_IMPL_CLANG,
+  GEE_INTERNAL_ATOMIC_IMPL_OPS,
+  GEE_INTERNAL_ATOMIC_GLIB
+} GeeInternalAtomicImpl;
+
+#if __STDC_VERSION__ >= 201112L && !__STDC_NO_ATOMICS__ && !defined(GEE_FORCE_ATOMIC_OPS) && 
!defined(GEE_FORCE_GLIB)
+#include <stdatomic.h>
+
+#define gee_internal_atomic_get_impl() GEE_INTERNAL_ATOMIC_STD
+
+typedef _Atomic(void *) GeeInternalAtomic;
+
+typedef enum {
+  GEE_INTERNAL_MEMORY_ORDERING_RELAXED = memory_order_relaxed,
+  GEE_INTERNAL_MEMORY_ORDERING_CONSUME = memory_order_consume,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQUIRE = memory_order_acquire,
+  GEE_INTERNAL_MEMORY_ORDERING_RELEASE = memory_order_release,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQ_REL = memory_order_acq_rel,
+  GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST = memory_order_seq_cst
+} GeeInternalMemoryOrdering;
+
+#define gee_internal_atomic_init(ptr, val) \
+  atomic_init(ptr, val);
+#define gee_internal_atomic_load(ptr, memorder) \
+  atomic_load_explicit(ptr, memorder)
+#define gee_internal_atomic_store(ptr, val, memorder)  \
+  atomic_store_explicit(ptr, val, memorder)
+#define gee_internal_atomic_exchange(ptr, val, memorder)       \
+  atomic_exchange_explicit(ptr, val, memorder)
+#define gee_internal_atomic_compare_and_exchange(ptr, oldval, newval, success_memorder, failure_memorder) \
+  atomic_compare_and_exchange_explicit_strong(ptr, oldval, newval, success_memorder, failure_memorder)
+#define gee_internal_atomic_compare_and_exchange_weak(ptr, oldval, newval, success_memorder, 
failure_memorder) \
+  atomic_compare_and_exchange_explicit_weak(ptr, oldval, newval, 0, success_memorder, failure_memorder)
+#define gee_internal_atomic_fence(memorder)    \
+  __atomic_thread_fence(memorder)
+
+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) && !defined(GEE_FORCE_ATOMIC_OPS) && 
!defined(GEE_FORCE_GLIB)
+
+#define gee_internal_atomic_get_impl() GEE_INTERNAL_ATOMIC_GCC
+
+typedef void * volatile GeeInternalAtomic;
+
+typedef enum {
+  GEE_INTERNAL_MEMORY_ORDERING_RELAXED = __ATOMIC_RELAXED,
+  GEE_INTERNAL_MEMORY_ORDERING_CONSUME = __ATOMIC_CONSUME,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQUIRE = __ATOMIC_ACQUIRE,
+  GEE_INTERNAL_MEMORY_ORDERING_RELEASE = __ATOMIC_RELEASE,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQ_REL = __ATOMIC_ACQ_REL,
+  GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST = __ATOMIC_SEQ_CST
+} GeeInternalMemoryOrdering;
+
+#define gee_internal_atomic_init(ptr, val) \
+  gee_internal_atomic_store(ptr, val, GEE_INTERNAL_MEMORY_ORDERING_RELEASE)
+#define gee_internal_atomic_load(ptr, memorder) \
+  __atomic_load_n(ptr, memorder)
+#define gee_internal_atomic_store(ptr, val, memorder)  \
+  __atomic_store_n(ptr, val, memorder)
+#define gee_internal_atomic_exchange(ptr, val, memorder)       \
+  __atomic_exchange_n(ptr, val, memorder)
+#define gee_internal_atomic_compare_and_exchange(ptr, oldval, newval, success_memorder, failure_memorder) \
+  __atomic_compare_exchange_n(ptr, oldval, newval, 1, success_memorder, failure_memorder)
+#define gee_internal_atomic_compare_and_exchange_weak(ptr, oldval, newval, success_memorder, 
failure_memorder) \
+  __atomic_compare_exchange_n(ptr, oldval, newval, 0, success_memorder, failure_memorder)
+#define gee_internal_atomic_fence(memorder)    \
+  __atomic_thread_fence(memorder)
+
+#elif __has_extension(c_atomic) && !defined(GEE_FORCE_ATOMIC_OPS) && !defined(GEE_FORCE_GLIB)
+
+#define gee_internal_atomic_get_impl() GEE_INTERNAL_ATOMIC_CLANG
+
+typedef _Atomic(void *) GeeInternalAtomic;
+
+typedef enum {
+  GEE_INTERNAL_MEMORY_ORDERING_RELAXED = 0,
+  GEE_INTERNAL_MEMORY_ORDERING_CONSUME = 1,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQUIRE = 2,
+  GEE_INTERNAL_MEMORY_ORDERING_RELEASE = 3,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQ_REL = 4,
+  GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST = 5
+} GeeInternalMemoryOrdering;
+
+#define gee_internal_atomic_init(ptr, val) \
+  __c11_atomic_init(ptr, val)
+#define gee_internal_atomic_load(ptr, memorder) \
+  __c11_atomic_load(ptr, memorder)
+#define gee_internal_atomic_store(ptr, val, memorder)  \
+  __c11_atomic_store(ptr, memorder)
+#define gee_internal_atomic_exchange(ptr, val, memorder)       \
+  __c11_atomic_exchange(ptr, val, memorder)
+#define gee_internal_atomic_compare_and_exchange(ptr, oldval, newval, success_memorder, failure_memorder) \
+  __c11_atomic_compare_exchange_strong(ptr, oldval, newval, success_memorder, failure_memorder)
+#define gee_internal_atomic_compare_and_exchange_weak(ptr, oldval, newval, success_memorder, 
failure_memorder) \
+  __c11_atomic_compare_exchange_weak(ptr, oldval, newval, success_memorder, failure_memorder)
+#define gee_internal_atomic_fence(memorder)    \
+  __c11_atomic_thread_fence(order)
+
+#elif !defined(GEE_FORCE_GLIB)
+
+#define gee_internal_atomic_get_impl() GEE_INTERNAL_ATOMIC_OPS
+
+#include <atomic_ops.h>
+#include <glib.h>
+
+typedef enum {
+  GEE_INTERNAL_MEMORY_ORDERING_RELAXED,
+  GEE_INTERNAL_MEMORY_ORDERING_CONSUME,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQUIRE,
+  GEE_INTERNAL_MEMORY_ORDERING_RELEASE,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQ_REL,
+  GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST
+} GeeInternalMemoryOrdering;
+
+typedef void * volatile GeeInternalAtomic;
+
+AO_INLINE void
+gee_internal_atomic_init(GeeInternalAtomic *ptr, void *val)
+{
+  AO_store (ptr, val);
+}
+
+AO_INLINE void *
+gee_internal_atomic_load(GeeInternalAtomic *ptr, GeeInternalMemoryOrdering model)
+{
+  switch (model)
+    {
+        case GEE_INTERNAL_MEMORY_ORDERING_RELAXED:
+            return AO_load(ptr);
+        case GEE_INTERNAL_MEMORY_ORDERING_CONSUME:
+        case GEE_INTERNAL_MEMORY_ORDERING_ACQUIRE:
+            return AO_load_acquire(ptr);
+        case GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST:
+            return AO_load_full(ptr);
+        default:
+            g_assert_not_reached ();
+    }
+}
+
+AO_INLINE void
+gee_internal_atomic_store(GeeInternalAtomic *ptr, void *val, GeeInternalMemoryOrdering model)
+{
+  switch (model)
+    {
+        case GEE_INTERNAL_MEMORY_ORDERING_RELAXED:
+            return AO_store(ptr, val);
+        case GEE_INTERNAL_MEMORY_ORDERING_RELEASE:
+            return AO_store_release(ptr, val);
+        case GEE_INTERNAL_MEMORY_ORDERING_ACQ_REL:
+        case GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST:
+            return AO_store_full(ptr, val);
+        default:
+            g_assert_not_reached ();
+    }
+}
+
+AO_INLINE void *
+gee_internal_atomic_exchange(GeeInternalAtomic *ptr, void *val, GeeInternalMemoryOrdering memorder)
+{
+  void *old = gee_internal_atomic_load(ptr, GEE_INTERNAL_MEMORY_ORDERING_RELAXED);
+  while (!GEE_INTERNAL_ATOMIC_COMPARE_AND_EXCHANGE_weak(ptr, &old, val, memorder, memorder));
+  return old;
+}
+
+AO_INLINE gboolean
+gee_internal_atomic_compare_and_exchange(GeeInternalAtomic *ptr, void **oldval, void *newval, 
GeeInternalMemoryOrdering success_memorder, GeeInternalMemoryOrdering failure_memorder)
+{
+  void *ooldval = *oldval;
+  while (!GEE_INTERNAL_ATOMIC_COMPARE_AND_EXCHANGE_weak (ptr, oldval, newval, success_memorder, 
failure_memorder) && ooldval == *oldval);
+  return ooldval == *oldval;
+}
+
+AO_INLINE gboolean
+gee_internal_atomic_compare_and_exchange_weak(GeeInternalAtomic *ptr, void **oldval, void *newval, 
GeeInternalMemoryOrdering success_memorder, GeeInternalMemoryOrdering failure_memorder)
+{
+  bool success = false;
+  switch (success_model)
+    {
+        case GEE_INTERNAL_MEMORY_ORDERING_RELAXED:
+            sucess = AO_compare_double_and_swap(ptr, *oldval, newval);
+        case GEE_INTERNAL_MEMORY_ORDERING_CONSUME:
+        case GEE_INTERNAL_MEMORY_ORDERING_ACQUIRE:
+            success = AO_compare_double_and_swap_acquire(ptr, *oldval, newval);
+        case GEE_INTERNAL_MEMORY_ORDERING_RELEASE:
+            success = AO_compare_double_and_swap_release(ptr, *oldval, newval);
+        case GEE_INTERNAL_MEMORY_ORDERING_ACQ_REL:
+        case GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST:
+            success = AO_compare_double_and_swap_full(ptr, *oldval, newval);
+        default:
+            g_assert_not_reached ();
+    }
+  if (!success)) {
+    *oldval = AO_load(ptr);
+  }
+  return success;
+}
+
+AO_INLINE void
+gee_internal_atomic_fence(GeeInternalMemoryOrdering memorder)
+{
+  switch (success_model)
+    {
+      case GEE_INTERNAL_MEMORY_ORDERING_RELAXED:
+        AO_nop ();
+        break;
+      case GEE_INTERNAL_MEMORY_ORDERING_CONSUME:
+      case GEE_INTERNAL_MEMORY_ORDERING_ACQUIRE:
+        AO_nop_acquire ();
+        break;
+      case GEE_INTERNAL_MEMORY_ORDERING_RELEASE:
+        AO_nop_release ();
+        break;
+      case GEE_INTERNAL_MEMORY_ORDERING_ACQ_REL:
+      case GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST:
+        AO_nop_full ();
+        break;
+      default:
+        g_assert_not_reached ();
+    }
+}
+
+#else
+
+#define gee_internal_atomic_get_impl() GEE_INTERNAL_ATOMIC_GLIB
+
+#include <glib-object.h>
+
+typedef enum {
+  GEE_INTERNAL_MEMORY_ORDERING_RELAXED,
+  GEE_INTERNAL_MEMORY_ORDERING_CONSUME,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQUIRE,
+  GEE_INTERNAL_MEMORY_ORDERING_RELEASE,
+  GEE_INTERNAL_MEMORY_ORDERING_ACQ_REL,
+  GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST
+} GeeInternalMemoryOrdering;
+
+typedef void * volatile GeeInternalAtomic;
+
+G_INLINE_FUNC void
+gee_internal_atomic_init(GeeInternalAtomic *ptr, void *val)
+{
+  g_atomic_pointer_set (ptr, val);
+}
+
+G_INLINE_FUNC void *
+gee_internal_atomic_load(GeeInternalAtomic *ptr, GeeInternalMemoryOrdering memorder)
+{
+  return g_atomic_pointer_get (ptr);
+}
+
+G_INLINE_FUNC void
+gee_internal_atomic_store(GeeInternalAtomic *ptr, void *val, GeeInternalMemoryOrdering memorder)
+{
+  g_atomic_pointer_set (ptr, val);
+}
+
+G_INLINE_FUNC void *
+gee_internal_atomic_exchange(GeeInternalAtomic *ptr, void *val, GeeInternalMemoryOrdering memorder)
+{
+  void *old = g_atomic_pointer_get(ptr);
+  while (!gee_internal_atomic_compare_and_exchange (ptr, old, val, GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST, 
GEE_INTERNAL_MEMORY_ORDERING_SEQ_CST));
+  return old;
+}
+
+G_INLINE_FUNC gboolean
+gee_internal_atomic_compare_and_exchange(GeeInternalAtomic *ptr, void **oldval, void *newval, 
GeeInternalMemoryOrdering success_memorder, GeeInternalMemoryOrdering failure_memorder)
+{
+  void *ooldval = *oldval;
+  while (!gee_internal_atomic_compare_and_exchange_weak (ptr, *oldval, newval, success_memorder, 
failure_memorder) && *oldval == ooldval);
+  return *oldval == ooldval;
+}
+
+G_INLINE_FUNC gboolean
+gee_internal_atomic_compare_and_exchange_weak(GeeInternalAtomic *ptr, void **oldval, void *newval, 
GeeInternalMemoryOrdering success_memorder, GeeInternalMemoryOrdering failure_memorder)
+{
+  gboolean success = g_pointer_compare_and_exchange (ptr, *oldval, newval);
+  if (!success)
+    {
+      *oldval = g_pointer_get (ptr);
+    }
+  return success;
+}
+
+G_INLINE_FUNC void
+gee_internal_atomic_fence(GeeInternalMemoryOrdering memorder)
+{
+  void * volatile ptr;
+  g_pointer_set (&ptr, &ptr);
+}
+
+#endif
+
+#define gee_internal_get_destroy_notify(type, dup, destroy) (destroy)
diff --git a/gee/gee-internal.vapi b/gee/gee-internal.vapi
new file mode 100644
index 0000000..639376b
--- /dev/null
+++ b/gee/gee-internal.vapi
@@ -0,0 +1,25 @@
+[CCode (gir_namespace = "Gee.Internal", gir_version = "0.8")]
+namespace Gee {
+       [CCode (cheader_filename = "gee-internal.h")]
+       namespace Internal {
+               public struct Atomic<G> {
+                       [CCode (cname="gee_internal_atomic_init")]
+                       public Atomic (G val);
+                       public unowned G load (MemoryOrdering order = MemoryOrdering.SEQ_CST);
+                       public void store (G val, MemoryOrdering order = MemoryOrdering.SEQ_CST);
+                       public unowned G exchange (G val, MemoryOrdering order = MemoryOrdering.SEQ_CST);
+                       public bool compare_and_exchange (ref unowned G oldval, G newval, MemoryOrdering 
success = MemoryOrdering.SEQ_CST, MemoryOrdering failure = MemoryOrdering.SEQ_CST);
+                       public bool compare_and_exchange_weak (ref unowned G oldval, G newval, MemoryOrdering 
success = MemoryOrdering.SEQ_CST, MemoryOrdering failure = MemoryOrdering.SEQ_CST);
+                       public static void fence (MemoryOrdering order = MemoryOrdering.SEQ_CST);
+               }
+               public enum MemoryOrdering {
+                       RELAXED,
+                       CONSUME,
+                       ACQUIRE,
+                       RELEASE,
+                       ACQ_REL,
+                       SEQ_CST
+               }
+               GLib.DestroyNotify get_destroy_notify<G> ();
+       }
+}
diff --git a/gee/hazardpointer.vala b/gee/hazardpointer.vala
index 1436d26..d5aab9c 100644
--- a/gee/hazardpointer.vala
+++ b/gee/hazardpointer.vala
@@ -636,10 +636,8 @@ public class Gee.HazardPointer<G> { // FIXME: Make it a struct
                        if (curr.activate ())
                                return curr;
                Node *node = new Node ();
+               node->insert (_head);
                Node *old_head = null;
-               do {
-                       node->set_next (old_head = (Node *)AtomicPointer.get (&_head));
-               } while (!AtomicPointer.compare_and_exchange (&_head, old_head, node));
                return  node;
        }
 
@@ -682,12 +680,12 @@ public class Gee.HazardPointer<G> { // FIXME: Make it a struct
         * @return Hazard pointer head.
         */
        internal static unowned Node? get_head () {
-               return (Node *)AtomicPointer.get(&_head);
+               return _head.load (Internal.MemoryOrdering.RELAXED);
        }
 
        internal unowned Node _node;
 
-       internal static Node *_head = null;
+       internal static Internal.Atomic<Node *> _head = Internal.Atomic<Node *>(null);
 
        internal static int _default_policy = (int)Policy.TRY_FREE;
        internal static int _thread_exit_policy = (int)Policy.RELEASE;
@@ -718,51 +716,47 @@ public class Gee.HazardPointer<G> { // FIXME: Make it a struct
         */
        [Compact]
        internal class Node {
-               public Node () {
-                       AtomicPointer.set (&_hazard, null);
-                       AtomicInt.set (ref _active, 1);
-               }
-               
                inline ~Node () {
-                       delete _next;
+                       Node *next = _next.load (Internal.MemoryOrdering.ACQUIRE);
+                       delete next;
                }
 
                public void release () {
-                       AtomicPointer.set (&_hazard, null);
-                       AtomicInt.set (ref _active, 0);
+                       _hazard.store (null, Internal.MemoryOrdering.RELEASE);
+                       _active.store (0, Internal.MemoryOrdering.RELEASE);
                }
 
                public inline bool is_active () {
-                       return AtomicInt.get (ref _active) != 0;
+                       return _active.load (Internal.MemoryOrdering.RELAXED) != 0;
                }
 
                public inline bool activate () {
-                       return AtomicInt.compare_and_exchange (ref _active, 0, 1);
+                       int old = 0;
+                       return _active.compare_and_exchange (ref old, 1, Internal.MemoryOrdering.ACQUIRE, 
Internal.MemoryOrdering.RELAXED);
                }
 
                public inline void set (void *ptr) {
-                       AtomicPointer.set (&_hazard, ptr);
+                       _hazard.store (ptr, Internal.MemoryOrdering.RELEASE);
                }
 
                public inline void *get (bool safe = true) {
-                       if (safe) {
-                               return (void *)AtomicPointer.get (&_hazard);
-                       } else {
-                               return (void *)_hazard;
-                       }
+                       return _hazard.load (safe ? Internal.MemoryOrdering.ACQUIRE : 
Internal.MemoryOrdering.RELAXED);
                }
 
-               public inline unowned Node? get_next () {
-                       return (Node *)AtomicPointer.get (&_next);
+               public inline unowned Node get_next () {
+                       return _next.load (Internal.MemoryOrdering.RELAXED);
                }
 
-               public inline void set_next (Node *next) {
-                       AtomicPointer.set (&_next, next);
+               public inline void insert (Internal.Atomic<Node *> head) {
+                       Node *curr_head = head.load (Internal.MemoryOrdering.RELAXED);
+                       do {
+                               _next.store (curr_head, Internal.MemoryOrdering.RELAXED);
+                       } while (_head.compare_and_exchange (ref curr_head, this, 
Internal.MemoryOrdering.RELEASE, Internal.MemoryOrdering.RELAXED));
                }
 
-               public Node *_next;
-               public int _active;
-               public void *_hazard;
+               public Internal.Atomic<Node *> _next = Internal.Atomic<Node *>(null);
+               public Internal.Atomic<int> _active = Internal.Atomic<int>(0);
+               public Internal.Atomic<void *> _hazard = Internal.Atomic<void *>(null);
        }
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]