benchmark silo added
[c11concurrency-benchmarks.git] / silo / masstree / nodeversion.hh
diff --git a/silo/masstree/nodeversion.hh b/silo/masstree/nodeversion.hh
new file mode 100644 (file)
index 0000000..92cbcf0
--- /dev/null
@@ -0,0 +1,343 @@
+/* Masstree
+ * Eddie Kohler, Yandong Mao, Robert Morris
+ * Copyright (c) 2012-2013 President and Fellows of Harvard College
+ * Copyright (c) 2012-2013 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, subject to the conditions
+ * listed in the Masstree LICENSE file. These conditions include: you must
+ * preserve this copyright notice, and you cannot mention the copyright
+ * holders in advertising related to the Software without their permission.
+ * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
+ * notice is a summary of the Masstree LICENSE file; the license in that file
+ * is legally binding.
+ */
+#ifndef MASSTREE_NODEVERSION_HH
+#define MASSTREE_NODEVERSION_HH
+#include "compiler.hh"
+
+template <typename P>
+class basic_nodeversion {
+  public:
+    typedef P traits_type;
+    typedef typename P::value_type value_type;
+
+    basic_nodeversion() {
+    }
+    explicit basic_nodeversion(bool isleaf) {
+        v_ = isleaf ? (value_type) P::isleaf_bit : 0;
+    }
+
+    bool isleaf() const {
+        return v_ & P::isleaf_bit;
+    }
+
+    basic_nodeversion<P> stable() const {
+        return stable(relax_fence_function());
+    }
+    template <typename SF>
+    basic_nodeversion<P> stable(SF spin_function) const {
+        value_type x = v_;
+        while (x & P::dirty_mask) {
+            spin_function();
+            x = v_;
+        }
+        acquire_fence();
+        return x;
+    }
+    template <typename SF>
+    basic_nodeversion<P> stable_annotated(SF spin_function) const {
+        value_type x = v_;
+        while (x & P::dirty_mask) {
+            spin_function(basic_nodeversion<P>(x));
+            x = v_;
+        }
+        acquire_fence();
+        return x;
+    }
+
+    bool locked() const {
+        return v_ & P::lock_bit;
+    }
+    bool inserting() const {
+        return v_ & P::inserting_bit;
+    }
+    bool splitting() const {
+        return v_ & P::splitting_bit;
+    }
+    bool deleted() const {
+        return v_ & P::deleted_bit;
+    }
+    bool has_changed(basic_nodeversion<P> x) const {
+        fence();
+        return (x.v_ ^ v_) > P::lock_bit;
+    }
+    bool has_split() const {
+        return !(v_ & P::root_bit);
+    }
+    bool has_split(basic_nodeversion<P> x) const {
+        fence();
+        return (x.v_ ^ v_) >= P::vsplit_lowbit;
+    }
+    bool simple_has_split(basic_nodeversion<P> x) const {
+        return (x.v_ ^ v_) >= P::vsplit_lowbit;
+    }
+
+    basic_nodeversion<P> lock() {
+        return lock(*this);
+    }
+    basic_nodeversion<P> lock(basic_nodeversion<P> expected) {
+        return lock(expected, relax_fence_function());
+    }
+    template <typename SF>
+    basic_nodeversion<P> lock(basic_nodeversion<P> expected, SF spin_function) {
+        while (1) {
+            if (!(expected.v_ & P::lock_bit)
+                && bool_cmpxchg(&v_, expected.v_,
+                                expected.v_ | P::lock_bit))
+                break;
+            spin_function();
+            expected.v_ = v_;
+        }
+        masstree_invariant(!(expected.v_ & P::dirty_mask));
+        expected.v_ |= P::lock_bit;
+        acquire_fence();
+        masstree_invariant(expected.v_ == v_);
+        return expected;
+    }
+
+    void unlock() {
+        unlock(*this);
+    }
+    void unlock(basic_nodeversion<P> x) {
+        masstree_invariant((fence(), x.v_ == v_));
+        masstree_invariant(x.v_ & P::lock_bit);
+        if (x.v_ & P::splitting_bit)
+            x.v_ = (x.v_ + P::vsplit_lowbit) & P::split_unlock_mask;
+        else
+            x.v_ = (x.v_ + ((x.v_ & P::inserting_bit) << 2)) & P::unlock_mask;
+        release_fence();
+        v_ = x.v_;
+    }
+
+    void mark_insert() {
+        masstree_invariant(locked());
+        v_ |= P::inserting_bit;
+        acquire_fence();
+    }
+    basic_nodeversion<P> mark_insert(basic_nodeversion<P> current_version) {
+        masstree_invariant((fence(), v_ == current_version.v_));
+        masstree_invariant(current_version.v_ & P::lock_bit);
+        v_ = (current_version.v_ |= P::inserting_bit);
+        acquire_fence();
+        return current_version;
+    }
+    void mark_split() {
+        masstree_invariant(locked());
+        v_ |= P::splitting_bit;
+        acquire_fence();
+    }
+    void mark_change(bool is_split) {
+        masstree_invariant(locked());
+        v_ |= (is_split + 1) << P::inserting_shift;
+        acquire_fence();
+    }
+    basic_nodeversion<P> mark_deleted() {
+        masstree_invariant(locked());
+        v_ |= P::deleted_bit | P::splitting_bit;
+        acquire_fence();
+        return *this;
+    }
+    void mark_deleted_tree() {
+        masstree_invariant(locked() && !has_split());
+        v_ |= P::deleted_bit;
+        acquire_fence();
+    }
+    void mark_root() {
+        v_ |= P::root_bit;
+        acquire_fence();
+    }
+    void mark_nonroot() {
+        v_ &= ~P::root_bit;
+        acquire_fence();
+    }
+
+    void assign_version(basic_nodeversion<P> x) {
+        v_ = x.v_;
+    }
+
+    value_type version_value() const {
+        return v_;
+    }
+    value_type unlocked_version_value() const {
+        return v_ & P::unlock_mask;
+    }
+
+  private:
+    value_type v_;
+
+    basic_nodeversion(value_type v)
+        : v_(v) {
+    }
+};
+
+
+template <typename P>
+class basic_singlethreaded_nodeversion {
+  public:
+    typedef P traits_type;
+    typedef typename P::value_type value_type;
+
+    basic_singlethreaded_nodeversion() {
+    }
+    explicit basic_singlethreaded_nodeversion(bool isleaf) {
+        v_ = isleaf ? (value_type) P::isleaf_bit : 0;
+    }
+
+    bool isleaf() const {
+        return v_ & P::isleaf_bit;
+    }
+
+    basic_singlethreaded_nodeversion<P> stable() const {
+        return *this;
+    }
+    template <typename SF>
+    basic_singlethreaded_nodeversion<P> stable(SF) const {
+        return *this;
+    }
+    template <typename SF>
+    basic_singlethreaded_nodeversion<P> stable_annotated(SF) const {
+        return *this;
+    }
+
+    bool locked() const {
+        return false;
+    }
+    bool inserting() const {
+        return false;
+    }
+    bool splitting() const {
+        return false;
+    }
+    bool deleted() const {
+        return false;
+    }
+    bool has_changed(basic_singlethreaded_nodeversion<P>) const {
+        return false;
+    }
+    bool has_split() const {
+        return !(v_ & P::root_bit);
+    }
+    bool has_split(basic_singlethreaded_nodeversion<P>) const {
+        return false;
+    }
+    bool simple_has_split(basic_singlethreaded_nodeversion<P>) const {
+        return false;
+    }
+
+    basic_singlethreaded_nodeversion<P> lock() {
+        return *this;
+    }
+    basic_singlethreaded_nodeversion<P> lock(basic_singlethreaded_nodeversion<P>) {
+        return *this;
+    }
+    template <typename SF>
+    basic_singlethreaded_nodeversion<P> lock(basic_singlethreaded_nodeversion<P>, SF) {
+        return *this;
+    }
+
+    void unlock() {
+    }
+    void unlock(basic_singlethreaded_nodeversion<P>) {
+    }
+
+    void mark_insert() {
+    }
+    basic_singlethreaded_nodeversion<P> mark_insert(basic_singlethreaded_nodeversion<P>) {
+        return *this;
+    }
+    void mark_split() {
+        v_ &= ~P::root_bit;
+    }
+    void mark_change(bool is_split) {
+        if (is_split)
+            mark_split();
+    }
+    basic_singlethreaded_nodeversion<P> mark_deleted() {
+        return *this;
+    }
+    void mark_deleted_tree() {
+        v_ |= P::deleted_bit;
+    }
+    void mark_root() {
+        v_ |= P::root_bit;
+    }
+    void mark_nonroot() {
+        v_ &= ~P::root_bit;
+    }
+
+    void assign_version(basic_singlethreaded_nodeversion<P> x) {
+        v_ = x.v_;
+    }
+
+    value_type version_value() const {
+        return v_;
+    }
+    value_type unlocked_version_value() const {
+        return v_;
+    }
+
+  private:
+    value_type v_;
+};
+
+
+struct nodeversion32_parameters {
+    enum {
+        lock_bit = (1U << 0),
+        inserting_shift = 1,
+        inserting_bit = (1U << 1),
+        splitting_bit = (1U << 2),
+        dirty_mask = inserting_bit | splitting_bit,
+        vinsert_lowbit = (1U << 3), // == inserting_bit << 2
+        vsplit_lowbit = (1U << 9),
+        unused1_bit = (1U << 28),
+        deleted_bit = (1U << 29),
+        root_bit = (1U << 30),
+        isleaf_bit = (1U << 31),
+        split_unlock_mask = ~(root_bit | unused1_bit | (vsplit_lowbit - 1)),
+        unlock_mask = ~(unused1_bit | (vinsert_lowbit - 1)),
+        top_stable_bits = 4
+    };
+
+    typedef uint32_t value_type;
+};
+
+
+struct nodeversion64_parameters {
+    enum {
+        lock_bit = (1ULL << 8),
+        inserting_shift = 9,
+        inserting_bit = (1ULL << 9),
+        splitting_bit = (1ULL << 10),
+        dirty_mask = inserting_bit | splitting_bit,
+        vinsert_lowbit = (1ULL << 11), // == inserting_bit << 2
+        vsplit_lowbit = (1ULL << 27),
+        unused1_bit = (1ULL << 60),
+        deleted_bit = (1ULL << 61),
+        root_bit = (1ULL << 62),
+        isleaf_bit = (1ULL << 63),
+        split_unlock_mask = ~(root_bit | unused1_bit | (vsplit_lowbit - 1)),
+        unlock_mask = ~(unused1_bit | (vinsert_lowbit - 1)),
+        top_stable_bits = 4
+    };
+
+    typedef uint64_t value_type;
+};
+
+
+typedef basic_nodeversion<nodeversion32_parameters> nodeversion;
+typedef basic_singlethreaded_nodeversion<nodeversion32_parameters> singlethreaded_nodeversion;
+
+#endif