[libgee/atomic] Change atomic
- From: Maciej Marcin Piechotka <mpiechotka src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgee/atomic] Change atomic
- Date: Mon, 4 Mar 2013 17:08:31 +0000 (UTC)
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]