diff --git a/base_cpp/include/embb/base/atomic.h b/base_cpp/include/embb/base/atomic.h index 990b2e0..d39f494 100644 --- a/base_cpp/include/embb/base/atomic.h +++ b/base_cpp/include/embb/base/atomic.h @@ -478,7 +478,7 @@ class Atomic : public embb::base::internal::atomic:: public: Atomic() : embb::base::internal::atomic:: AtomicPointer() {} - Atomic(BaseType* p) : embb::base::internal::atomic:: + explicit Atomic(BaseType* p) : embb::base::internal::atomic:: AtomicPointer(p) {} BaseType* operator=(BaseType* p) { diff --git a/base_cpp/include/embb/base/internal/atomic/atomic_base.h b/base_cpp/include/embb/base/internal/atomic/atomic_base.h index 258a686..1be01e5 100644 --- a/base_cpp/include/embb/base/internal/atomic/atomic_base.h +++ b/base_cpp/include/embb/base/internal/atomic/atomic_base.h @@ -177,8 +177,7 @@ CompareAndSwap(BaseType& expected, BaseType desired) { compare_and_swap(&AtomicValue, &native_expected, native_desired)) !=0 ? true : false; - if (!return_val) - expected = Load(); + memcpy(&expected, &native_expected, sizeof(expected)); return return_val; } diff --git a/containers_cpp/include/embb/containers/internal/hazard_pointer-inl.h b/containers_cpp/include/embb/containers/internal/hazard_pointer-inl.h index 5f62926..e735eac 100644 --- a/containers_cpp/include/embb/containers/internal/hazard_pointer-inl.h +++ b/containers_cpp/include/embb/containers/internal/hazard_pointer-inl.h @@ -418,6 +418,118 @@ void HazardPointer< GuardType >::EnqueuePointerForDeletion( template const double embb::containers::internal::HazardPointer:: RETIRE_THRESHOLD = 1.25f; + +template +UniqueHazardPointer:: +UniqueHazardPointer() + : hazard_guard_(NULL), undefined_guard_(NULL), active_(false) {} + +template +UniqueHazardPointer:: +UniqueHazardPointer(AtomicTypePtr& hazard_guard, Type* undefined_guard) + : hazard_guard_(&hazard_guard), + undefined_guard_(undefined_guard), + active_(LoadGuardedPointer() == undefined_guard_) {} + +template +UniqueHazardPointer::~UniqueHazardPointer() { + if (IsActive()) ClearHazard(); +} + +template +bool UniqueHazardPointer::ProtectHazard(const AtomicTypePtr& hazard) { + assert(OwnsHazardGuard()); + + // Read the hazard and store it into the guard + StoreGuardedPointer(hazard.Load()); + + // Check whether the guard is valid + SetActive(LoadGuardedPointer() == hazard.Load()); + + // Clear the guard if it is invalid + if (!IsActive()) ClearHazard(); + + return IsActive(); +} + +template +void UniqueHazardPointer::ProtectSafe(Type* safe_ptr) { + assert(OwnsHazardGuard()); + StoreGuardedPointer(safe_ptr); + SetActive(true); +} + +template +UniqueHazardPointer::operator Type* () const { + assert(IsActive()); + return LoadGuardedPointer(); +} + +template +Type* UniqueHazardPointer::operator->() const { + assert(IsActive()); + return LoadGuardedPointer(); +} + +template +Type& UniqueHazardPointer::operator*() const { + assert(IsActive()); + return *(LoadGuardedPointer()); +} + +template +void UniqueHazardPointer::AdoptGuard(const UniqueHazardPointer& other) { + assert(OwnsHazardGuard()); + StoreGuardedPointer(other.LoadGuardedPointer()); + SetActive(other.active_); +} + +template +void UniqueHazardPointer::Swap(UniqueHazardPointer& other) { + std::swap(hazard_guard_, other.hazard_guard_); + std::swap(undefined_guard_, other.undefined_guard_); + std::swap(active_, other.active_); +} + +template +Type* UniqueHazardPointer::ReleaseHazard() { + assert(IsActive()); + Type* released_hazard = LoadGuardedPointer(); + ClearHazard(); + SetActive(false); + return released_hazard; +} + +template +bool UniqueHazardPointer::IsActive() const { + return active_; +} + +template +void UniqueHazardPointer::SetActive(bool active) { + active_ = active; +} + +template +void UniqueHazardPointer::ClearHazard() { + StoreGuardedPointer(undefined_guard_); +} + +template +Type* UniqueHazardPointer::LoadGuardedPointer() const { + return hazard_guard_->Load(); +} + +template +void UniqueHazardPointer::StoreGuardedPointer(Type* ptr) { + hazard_guard_->Store(ptr); +} + +template +bool UniqueHazardPointer::OwnsHazardGuard() const { + return hazard_guard_ != NULL; +} + } // namespace internal } // namespace containers } // namespace embb diff --git a/containers_cpp/include/embb/containers/internal/hazard_pointer.h b/containers_cpp/include/embb/containers/internal/hazard_pointer.h index 7387bf1..f847aa9 100644 --- a/containers_cpp/include/embb/containers/internal/hazard_pointer.h +++ b/containers_cpp/include/embb/containers/internal/hazard_pointer.h @@ -529,6 +529,175 @@ class HazardPointer { */ void EnqueuePointerForDeletion(GuardType guardedElement); }; + +/** + * Ownership wrapper for a hazard pointer + * + * Uses an entry of the hazard table (guard) to provide protection for a single + * hazardous pointer. While providing standard pointer dereference and member + * access operators, it requires special care for pointer assignment (realized + * via 'ProtectHazard' method). + * On destruction, it clears the wrapped hazard table entry, releasing the + * protected hazardous pointer (if any). + * + * \tparam Type Type of the object to be protected by the hazard pointer + */ +template +class UniqueHazardPointer { + public: + /** Typedef for a atomic pointer to the guarded object. */ + typedef embb::base::Atomic AtomicTypePtr; + + /** + * Creates an uninitialized, empty wrapper. + * + * An uninitialized wrapper may only be swapped with another wrapper (using + * \c Swap() method) or checked for being active (using 'IsActive()' method, + * which should always return /c false for an uninitialized wrapper). + */ + UniqueHazardPointer(); + + /** + * Creates a wrapper that uses the given hazard table entry (referred to as + * "guard") to protect hazardous pointers. + * + * \param[IN] hazard_guard Reference to a hazard table entry + * \param[IN] undefined_guard Dummy value used to clear the hazard table entry + */ + explicit + UniqueHazardPointer(AtomicTypePtr& hazard_guard, + Type* undefined_guard = NULL); + + /** + * If initialized and active, clears the hazard table entry. + */ + ~UniqueHazardPointer(); + + /** + * Tries to protect the given hazard using the wrapped guard. + * If it succeeds, the hazard may be safely dereferenced as long as the guard + * is not destroyed or reset to protect another hazard. + * + * \param hazard The hazard to be protected + * \return \c true if the specified hazard is now protected by the guard, + * \c false if the hazard was modified by a concurrent thread + */ + bool ProtectHazard(const AtomicTypePtr& hazard); + + /** + * Uses the wrapped guard to protect a pointer that is not hazardous yet. + * + * \param safe_ptr The pointer to be protected + */ + void ProtectSafe(Type* safe_ptr); + + /** + * Type cast operator. + * + * \return The hazardous pointer protected by this wrapper + */ + operator Type* () const; + + /** + * Pointer member access operator. + * + * \return The hazardous pointer protected by this wrapper + */ + Type* operator->() const; + + /** + * Pointer dereference operator. + * + * \return Reference to the object pointed to by the protected pointer + */ + Type& operator*() const; + + /** + * Protects the hazard that is currently protected by another wrapper (so it + * becomes protected by two guards simultaneously). The other wrapper remains + * unmodified. + * + * \param other Another wrapper those protected pointer is to be protected by + * the calling wrapper + */ + void AdoptGuard(const UniqueHazardPointer& other); + + /** + * Swaps the guard ownership with another wrapper. Swaps not just the + * protected hazards, but the hazard guards themselves. + * + * \param other Another wrapper to swap guards with + */ + void Swap(UniqueHazardPointer& other); + + /** + * Clears the hazard guard and returns the hazard previously protected by that + * guard. + * + * \return The hazardous pointer previously protected by this wrapper + */ + Type* ReleaseHazard(); + + /** + * Check whether the wrapper is active. + * + * \return \c true if the wrapper is initialized and currently protecting some + * hazard, \c false otherwise + */ + bool IsActive() const; + + private: + /** + * Sets the 'active' flag of this wrapper. + * + * \param active The new value for the flag + */ + void SetActive(bool active); + + /** + * Reset the wrapped hazard guard to a state when it is not protecting any + * hazards. + */ + void ClearHazard(); + + /** + * Retrieves the hazardous pointer currently protected by the wrapped guard. + * + * \return The hazardous pointer protected by this wrapper + */ + Type* LoadGuardedPointer() const; + + /** + * Updates the wrapped guard to protect the specified hazardous pointer. + * + * \param ptr Hazardous pointer to be protected + */ + void StoreGuardedPointer(Type* ptr); + + /** + * Check whether the wrapper is initialized (i.e. it wraps some hazard guard) + * + * \return \c true if this wrapper is initialized, \c false otherwise + */ + bool OwnsHazardGuard() const; + + /** + * Disable copy construction and assignment. + */ + UniqueHazardPointer(const UniqueHazardPointer&); + UniqueHazardPointer& operator=(const UniqueHazardPointer&); + + /** + * Pointer to a hazard table entry (the guard) that is used to store the + * hazardous pointers + */ + AtomicTypePtr* hazard_guard_; + /** Dummy value used to clear the hazard guard from any hazards */ + Type* undefined_guard_; + /** Flag set to true when the guard is protecting some hazardous pointer */ + bool active_; +}; + } // namespace internal } // namespace containers } // namespace embb diff --git a/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h b/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h index 0135779..d10ccdd 100644 --- a/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h +++ b/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h @@ -44,8 +44,8 @@ namespace internal { template ChromaticTreeNode:: -ChromaticTreeNode(const Key& key, const Value& value, const int weight, - const ChildPointer& left, const ChildPointer& right) +ChromaticTreeNode(const Key& key, const Value& value, int weight, + Node* left, Node* right) : key_(key), value_(value), weight_(weight), @@ -55,7 +55,7 @@ ChromaticTreeNode(const Key& key, const Value& value, const int weight, template ChromaticTreeNode:: -ChromaticTreeNode(const Key& key, const Value& value, const int weight) +ChromaticTreeNode(const Key& key, const Value& value, int weight) : key_(key), value_(value), weight_(weight), @@ -79,18 +79,44 @@ int ChromaticTreeNode::GetWeight() const { } template -typename ChromaticTreeNode::AtomicChildPointer& +typename ChromaticTreeNode::AtomicNodePtr& ChromaticTreeNode::GetLeft() { return left_; } template -typename ChromaticTreeNode::AtomicChildPointer& +typename ChromaticTreeNode::Node* +ChromaticTreeNode::GetLeft() const { + return left_.Load(); +} + +template +typename ChromaticTreeNode::AtomicNodePtr& ChromaticTreeNode::GetRight() { return right_; } template +typename ChromaticTreeNode::Node* +ChromaticTreeNode::GetRight() const { + return right_.Load(); +} + +template +bool ChromaticTreeNode:: +ReplaceChild(Node* old_child, Node* new_child) { + bool replaced = false; + + if (left_ == old_child) { + replaced = left_.CompareAndSwap(old_child, new_child); + } else if (right_ == old_child) { + replaced = right_.CompareAndSwap(old_child, new_child); + } + + return replaced; +} + +template void ChromaticTreeNode::Retire() { retired_ = true; } @@ -105,133 +131,23 @@ embb::base::Mutex& ChromaticTreeNode::GetMutex() { return mutex_; } -template -UniqueHazardPointer:: -UniqueHazardPointer() - : hazard_guard_(NULL), undefined_guard_(NULL), active_(false) {} - -template -UniqueHazardPointer:: -UniqueHazardPointer(AtomicGuard& hazard_guard, GuardedPtr undefined_guard) - : hazard_guard_(&hazard_guard), - undefined_guard_(undefined_guard), - active_(LoadGuardedPointer() == undefined_guard_) {} - -template -UniqueHazardPointer:: -~UniqueHazardPointer() { - if (IsActive()) ClearHazard(); -} - -template -bool UniqueHazardPointer:: -ProtectHazard(const AtomicGuard& hazard) { - assert(OwnsHazardGuard()); - - // Read the hazard and store it into the guard - StoreGuardedPointer(hazard.Load()); - - // Check whether the guard is valid - SetActive(LoadGuardedPointer() == hazard.Load()); - - // Clear the guard if it is invalid - if (!IsActive()) ClearHazard(); - - return IsActive(); -} - -template -UniqueHazardPointer::operator GuardedPtr () const { - assert(IsActive()); - return LoadGuardedPointer(); -} - -template -typename UniqueHazardPointer::GuardedPtr -UniqueHazardPointer::operator->() const { - assert(IsActive()); - return LoadGuardedPointer(); -} - -template -GuardedType& UniqueHazardPointer::operator*() const { - assert(IsActive()); - return *(LoadGuardedPointer()); -} - -template -void UniqueHazardPointer:: -AdoptGuard(const UniqueHazardPointer& other) { - assert(OwnsHazardGuard()); - StoreGuardedPointer(other.LoadGuardedPointer()); - SetActive(other.active_); -} - -template -void UniqueHazardPointer:: -Swap(UniqueHazardPointer& other) { - std::swap(hazard_guard_, other.hazard_guard_); - std::swap(undefined_guard_, other.undefined_guard_); - std::swap(active_, other.active_); -} - -template -typename UniqueHazardPointer::GuardedPtr -UniqueHazardPointer::ReleaseHazard() { - assert(IsActive()); - GuardedPtr released_hazard = LoadGuardedPointer(); - ClearHazard(); - SetActive(false); - return released_hazard; -} - -template -bool UniqueHazardPointer::IsActive() const { - return active_; -} - -template -void UniqueHazardPointer::SetActive(bool active) { - active_ = active; -} - -template -void UniqueHazardPointer::ClearHazard() { - StoreGuardedPointer(undefined_guard_); -} - -template -typename UniqueHazardPointer::GuardedPtr -UniqueHazardPointer::LoadGuardedPointer() const { - return hazard_guard_->Load(); -} - -template -void UniqueHazardPointer::StoreGuardedPointer(GuardedPtr ptr) { - hazard_guard_->Store(ptr); -} - -template -bool UniqueHazardPointer::OwnsHazardGuard() const { - return hazard_guard_ != NULL; -} - } // namespace internal -template -ChromaticTree:: +template +ChromaticTree:: ChromaticTree(size_t capacity, Key undefined_key, Value undefined_value, Compare compare) #ifdef EMBB_PLATFORM_COMPILER_MSVC #pragma warning(push) #pragma warning(disable:4355) #endif - : free_node_callback_(*this, &ChromaticTree::FreeNode), + : node_hazard_manager_( + embb::base::Function(*this, &ChromaticTree::FreeNode), + NULL, 10), #ifdef EMBB_PLATFORM_COMPILER_MSVC #pragma warning(pop) #endif - node_hazard_manager_(free_node_callback_, NULL, 10), undefined_key_(undefined_key), undefined_value_(undefined_value), compare_(compare), @@ -242,20 +158,20 @@ ChromaticTree(size_t capacity, Key undefined_key, Value undefined_value, entry_(node_pool_.Allocate(undefined_key_, undefined_value_, 1, node_pool_.Allocate(undefined_key_, undefined_value_), - static_cast(NULL))) { + static_cast(NULL))) { assert(entry_ != NULL); - assert(entry_->GetLeft().Load() != NULL); + assert(entry_->GetLeft() != NULL); } -template -ChromaticTree:: +template +ChromaticTree:: ~ChromaticTree() { Destruct(entry_->GetLeft()); FreeNode(entry_); } -template -bool ChromaticTree:: +template +bool ChromaticTree:: Get(const Key& key, Value& value) { HazardNodePtr parent(node_hazard_manager_.GetGuardedPointer(0)); HazardNodePtr leaf (node_hazard_manager_.GetGuardedPointer(1)); @@ -272,19 +188,19 @@ Get(const Key& key, Value& value) { return keys_are_equal; } -template -bool ChromaticTree:: +template +bool ChromaticTree:: TryInsert(const Key& key, const Value& value) { Value old_value; return TryInsert(key, value, old_value); } -template -bool ChromaticTree:: +template +bool ChromaticTree:: TryInsert(const Key& key, const Value& value, Value& old_value) { - NodePtr new_leaf = NULL; - NodePtr new_sibling = NULL; - NodePtr new_parent = NULL; + Node* new_leaf = NULL; + Node* new_sibling = NULL; + Node* new_parent = NULL; bool insertion_succeeded = false; bool added_violation = false; @@ -330,9 +246,7 @@ TryInsert(const Key& key, const Value& value, Value& old_value) { if (new_parent == NULL) break; } - NodePtr expected = leaf; - insertion_succeeded = GetPointerToChild(parent, leaf) - .CompareAndSwap(expected, new_parent); + insertion_succeeded = parent->ReplaceChild(leaf, new_parent); assert(insertion_succeeded); // For now (FGL tree) this CAS may not fail if (!insertion_succeeded) continue; @@ -353,17 +267,17 @@ TryInsert(const Key& key, const Value& value, Value& old_value) { return insertion_succeeded; } -template -bool ChromaticTree:: +template +bool ChromaticTree:: TryDelete(const Key& key) { Value old_value; return TryDelete(key, old_value); } -template -bool ChromaticTree:: +template +bool ChromaticTree:: TryDelete(const Key& key, Value& old_value) { - NodePtr new_leaf = NULL; + Node* new_leaf = NULL; bool deletion_succeeded = false; bool added_violation = false; @@ -396,7 +310,7 @@ TryDelete(const Key& key, Value& old_value) { sibling.ProtectHazard((parent->GetLeft() == leaf) ? parent->GetRight() : parent->GetLeft()); if (parent->IsRetired() || !sibling.IsActive()) continue; - VERIFY_ADDRESS(static_cast(sibling)); + VERIFY_ADDRESS(static_cast(sibling)); // Verify that the leaf is still the parent's child if (!HasChild(parent, leaf)) continue; @@ -419,9 +333,7 @@ TryDelete(const Key& key, Value& old_value) { old_value = leaf->GetValue(); - NodePtr expected = parent; - deletion_succeeded = GetPointerToChild(grandparent, parent) - .CompareAndSwap(expected, new_leaf); + deletion_succeeded = grandparent->ReplaceChild(parent, new_leaf); assert(deletion_succeeded); // For now (FGL tree) this CAS may not fail if (!deletion_succeeded) continue; @@ -441,31 +353,31 @@ TryDelete(const Key& key, Value& old_value) { return deletion_succeeded; } -template -size_t ChromaticTree:: +template +size_t ChromaticTree:: GetCapacity() const { return capacity_; } -template -const Value& ChromaticTree:: -GetUndefinedValue() { +template +const Value& ChromaticTree:: +GetUndefinedValue() const { return undefined_value_; } -template -bool ChromaticTree:: +template +bool ChromaticTree:: IsEmpty() const { return IsLeaf(entry_->GetLeft()); } -template -void ChromaticTree:: +template +void ChromaticTree:: Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent) { bool reached_leaf = false; while (!reached_leaf) { - parent.ProtectHazard(entry_); + parent.ProtectSafe(entry_); leaf.ProtectHazard(entry_->GetLeft()); if (parent->IsRetired() || !leaf.IsActive()) continue; @@ -475,22 +387,22 @@ Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent) { leaf.ProtectHazard((IsSentinel(leaf) || compare_(key, leaf->GetKey())) ? leaf->GetLeft() : leaf->GetRight()); if (parent->IsRetired() || !leaf.IsActive()) break; - VERIFY_ADDRESS(static_cast(leaf)); + VERIFY_ADDRESS(static_cast(leaf)); reached_leaf = IsLeaf(leaf); } } } -template -void ChromaticTree:: +template +void ChromaticTree:: Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent, HazardNodePtr& grandparent) { bool reached_leaf = false; while (!reached_leaf) { - grandparent.ProtectHazard(entry_); - parent.ProtectHazard(entry_); + grandparent.ProtectSafe(entry_); + parent.ProtectSafe(entry_); leaf.ProtectHazard(entry_->GetLeft()); if (parent->IsRetired() || !leaf.IsActive()) continue; @@ -501,42 +413,34 @@ Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent, leaf.ProtectHazard((IsSentinel(leaf) || compare_(key, leaf->GetKey())) ? leaf->GetLeft() : leaf->GetRight()); if (parent->IsRetired() || !leaf.IsActive()) break; - VERIFY_ADDRESS(static_cast(leaf)); + VERIFY_ADDRESS(static_cast(leaf)); reached_leaf = IsLeaf(leaf); } } } -template -bool ChromaticTree:: -IsLeaf(const NodePtr& node) const { +template +bool ChromaticTree:: +IsLeaf(const Node* node) const { return node->GetLeft() == NULL; } -template -bool ChromaticTree:: -IsSentinel(const NodePtr& node) const { +template +bool ChromaticTree:: +IsSentinel(const Node* node) const { return (node == entry_) || (node == entry_->GetLeft()); } -template -bool ChromaticTree:: -HasChild(const NodePtr& parent, const NodePtr& child) const { +template +bool ChromaticTree:: +HasChild(const Node* parent, const Node* child) const { return (parent->GetLeft() == child || parent->GetRight() == child); } -template -typename ChromaticTree::AtomicNodePtr& -ChromaticTree:: -GetPointerToChild(const NodePtr& parent, const NodePtr& child) const { - assert(HasChild(parent, child)); - return (parent->GetLeft() == child) ? parent->GetLeft() : parent->GetRight(); -} - -template -void ChromaticTree:: -Destruct(const NodePtr& node) { +template +void ChromaticTree:: +Destruct(Node* node) { if (!IsLeaf(node)) { Destruct(node->GetLeft()); Destruct(node->GetRight()); @@ -544,9 +448,9 @@ Destruct(const NodePtr& node) { FreeNode(node); } -template -int ChromaticTree:: -GetHeight(const NodePtr& node) const { +template +int ChromaticTree:: +GetHeight(const Node* node) const { int height = 0; if (node != NULL) { height = 1 + ::std::max(GetHeight(node->GetLeft()), @@ -555,21 +459,21 @@ GetHeight(const NodePtr& node) const { return height; } -template -bool ChromaticTree:: +template +bool ChromaticTree:: IsBalanced() const { return IsBalanced(entry_->GetLeft()); } -template -bool ChromaticTree:: -IsBalanced(const NodePtr& node) const { +template +bool ChromaticTree:: +IsBalanced(const Node* node) const { // Overweight violation bool has_violation = node->GetWeight() > 1; if (!has_violation && !IsLeaf(node)) { - NodePtr left = node->GetLeft(); - NodePtr right = node->GetRight(); + const Node* left = node->GetLeft(); + const Node* right = node->GetRight(); // Red-red violation has_violation = node->GetWeight() == 0 && @@ -584,27 +488,27 @@ IsBalanced(const NodePtr& node) const { return !has_violation; } -template -void ChromaticTree:: +template +void ChromaticTree:: RetireHazardousNode(HazardNodePtr& node, UniqueLock& node_lock) { node->Retire(); node_lock.Unlock(); - NodePtr node_to_delete = node.ReleaseHazard(); + Node* node_to_delete = node.ReleaseHazard(); node_hazard_manager_.EnqueuePointerForDeletion(node_to_delete); } -template -void ChromaticTree:: -FreeNode(NodePtr node) { +template +void ChromaticTree:: +FreeNode(Node* node) { #ifdef EMBB_DEBUG - node->GetLeft() = reinterpret_cast(INVALID_POINTER); - node->GetRight() = reinterpret_cast(INVALID_POINTER); + node->GetLeft() = reinterpret_cast(INVALID_POINTER); + node->GetRight() = reinterpret_cast(INVALID_POINTER); #endif node_pool_.Free(node); } -template -bool ChromaticTree:: +template +bool ChromaticTree:: CleanUp(const Key& key) { HazardNodePtr grandgrandparent(node_hazard_manager_.GetGuardedPointer(0)); HazardNodePtr grandparent (node_hazard_manager_.GetGuardedPointer(1)); @@ -615,9 +519,9 @@ CleanUp(const Key& key) { while (!reached_leaf) { bool found_violation = false; - grandgrandparent.ProtectHazard(entry_); - grandparent.ProtectHazard(entry_); - parent.ProtectHazard(entry_); + grandgrandparent.ProtectSafe(entry_); + grandparent.ProtectSafe(entry_); + parent.ProtectSafe(entry_); leaf.ProtectHazard(entry_->GetLeft()); if (parent->IsRetired() || !leaf.IsActive()) continue; @@ -629,7 +533,7 @@ CleanUp(const Key& key) { leaf.ProtectHazard((IsSentinel(leaf) || compare_(key, leaf->GetKey())) ? leaf->GetLeft() : leaf->GetRight()); if (parent->IsRetired() || !leaf.IsActive()) break; - VERIFY_ADDRESS(static_cast(leaf)); + VERIFY_ADDRESS(static_cast(leaf)); found_violation = (leaf->GetWeight() > 1) || (leaf->GetWeight() == 0 && parent->GetWeight() == 0); @@ -659,10 +563,10 @@ CleanUp(const Key& key) { HazardNodePtr node(node_hazard_manager_.GetGuardedPointer(h_num)); \ node.ProtectHazard(parent->method()); \ if (parent->IsRetired() || !node.IsActive()) return EMBB_BUSY; \ - VERIFY_ADDRESS(static_cast(node)) + VERIFY_ADDRESS(static_cast(node)) -template -embb_errors_t ChromaticTree:: +template +embb_errors_t ChromaticTree:: Rebalance(HazardNodePtr& u, HazardNodePtr& ux, HazardNodePtr& uxx, HazardNodePtr& uxxx) { // Protect node 'u' @@ -730,8 +634,8 @@ Rebalance(HazardNodePtr& u, HazardNodePtr& ux, HazardNodePtr& uxx, } } -template -embb_errors_t ChromaticTree:: +template +embb_errors_t ChromaticTree:: OverweightLeft(HazardNodePtr& u, UniqueLock& u_lock, HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxx, UniqueLock& uxx_lock, @@ -876,8 +780,8 @@ OverweightLeft(HazardNodePtr& u, UniqueLock& u_lock, } } -template -embb_errors_t ChromaticTree:: +template +embb_errors_t ChromaticTree:: OverweightRight(HazardNodePtr& u, UniqueLock& u_lock, HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxx, UniqueLock& uxx_lock, diff --git a/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-rebalance.h b/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-rebalance.h index ec9f992..f96d75c 100644 --- a/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-rebalance.h +++ b/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-rebalance.h @@ -37,15 +37,15 @@ embb_errors_t BLK( HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock) { - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), 1, uxl->GetLeft(), uxl->GetRight()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), 1, uxr->GetLeft(), uxr->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), IsSentinel(u) ? 1 : ux->GetWeight() - 1, nxl, nxr); @@ -59,9 +59,7 @@ embb_errors_t BLK( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -78,15 +76,15 @@ embb_errors_t PUSH_L( HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock) { - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), uxl->GetWeight() - 1, uxl->GetLeft(), uxl->GetRight()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), 0, uxr->GetLeft(), uxr->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), IsSentinel(u) ? 1 : ux->GetWeight() + 1, nxl, nxr); @@ -100,9 +98,7 @@ embb_errors_t PUSH_L( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -119,15 +115,15 @@ embb_errors_t PUSH_R( HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock) { - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), uxr->GetWeight() - 1, uxr->GetLeft(), uxr->GetRight()); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), 0, uxl->GetLeft(), uxl->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), IsSentinel(u) ? 1 : ux->GetWeight() + 1, nxl, nxr); @@ -141,9 +137,7 @@ embb_errors_t PUSH_R( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -159,11 +153,11 @@ embb_errors_t RB1_L( HazardNodePtr& u, UniqueLock& u_lock, HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxl, UniqueLock& uxl_lock) { - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 0, uxl->GetRight(), ux->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), ux->GetWeight(), uxl->GetLeft(), nxr); @@ -175,9 +169,7 @@ embb_errors_t RB1_L( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -192,11 +184,11 @@ embb_errors_t RB1_R( HazardNodePtr& u, UniqueLock& u_lock, HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock) { - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 0, ux->GetLeft(), uxr->GetLeft()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), ux->GetWeight(), nxl, uxr->GetRight()); @@ -208,9 +200,7 @@ embb_errors_t RB1_R( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -226,15 +216,15 @@ embb_errors_t RB2_L( HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxlr, UniqueLock& uxlr_lock) { - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), 0, uxl->GetLeft(), uxlr->GetLeft()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 0, uxlr->GetRight(), ux->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxlr->GetKey(), uxlr->GetValue(), ux->GetWeight(), nxl, nxr); @@ -248,9 +238,7 @@ embb_errors_t RB2_L( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -267,15 +255,15 @@ embb_errors_t RB2_R( HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxrl, UniqueLock& uxrl_lock) { - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), 0, uxrl->GetRight(), uxr->GetRight()); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 0, ux->GetLeft(), uxrl->GetLeft()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxrl->GetKey(), uxrl->GetValue(), ux->GetWeight(), nxl, nxr); @@ -289,9 +277,7 @@ embb_errors_t RB2_R( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -309,19 +295,19 @@ embb_errors_t W1_L( HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxrl, UniqueLock& uxrl_lock) { - NodePtr nxll = node_pool_.Allocate( + Node* nxll = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), uxl->GetWeight() - 1, uxl->GetLeft(), uxl->GetRight()); - NodePtr nxlr = node_pool_.Allocate( + Node* nxlr = node_pool_.Allocate( uxrl->GetKey(), uxrl->GetValue(), uxrl->GetWeight() - 1, uxrl->GetLeft(), uxrl->GetRight()); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, nxll, nxlr); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), ux->GetWeight(), nxl, uxr->GetRight()); @@ -337,9 +323,7 @@ embb_errors_t W1_L( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -358,19 +342,19 @@ embb_errors_t W1_R( HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxlr, UniqueLock& uxlr_lock) { - NodePtr nxrr = node_pool_.Allocate( + Node* nxrr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), uxr->GetWeight() - 1, uxr->GetLeft(), uxr->GetRight()); - NodePtr nxrl = node_pool_.Allocate( + Node* nxrl = node_pool_.Allocate( uxlr->GetKey(), uxlr->GetValue(), uxlr->GetWeight() - 1, uxlr->GetLeft(), uxlr->GetRight()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, nxrl, nxrr); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), ux->GetWeight(), uxl->GetLeft(), nxr); @@ -386,9 +370,7 @@ embb_errors_t W1_R( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -407,19 +389,19 @@ embb_errors_t W2_L( HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxrl, UniqueLock& uxrl_lock) { - NodePtr nxll = node_pool_.Allocate( + Node* nxll = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), uxl->GetWeight() - 1, uxl->GetLeft(), uxl->GetRight()); - NodePtr nxlr = node_pool_.Allocate( + Node* nxlr = node_pool_.Allocate( uxrl->GetKey(), uxrl->GetValue(), 0, uxrl->GetLeft(), uxrl->GetRight()); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, nxll, nxlr); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), ux->GetWeight(), nxl, uxr->GetRight()); @@ -435,9 +417,7 @@ embb_errors_t W2_L( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -456,19 +436,19 @@ embb_errors_t W2_R( HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxlr, UniqueLock& uxlr_lock) { - NodePtr nxrr = node_pool_.Allocate( + Node* nxrr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), uxr->GetWeight() - 1, uxr->GetLeft(), uxr->GetRight()); - NodePtr nxrl = node_pool_.Allocate( + Node* nxrl = node_pool_.Allocate( uxlr->GetKey(), uxlr->GetValue(), 0, uxlr->GetLeft(), uxlr->GetRight()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, nxrl, nxrr); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), ux->GetWeight(), uxl->GetLeft(), nxr); @@ -484,9 +464,7 @@ embb_errors_t W2_R( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -506,23 +484,23 @@ embb_errors_t W3_L( HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxrl, UniqueLock& uxrl_lock, HazardNodePtr& uxrll, UniqueLock& uxrll_lock) { - NodePtr nxlll = node_pool_.Allocate( + Node* nxlll = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), uxl->GetWeight() - 1, uxl->GetLeft(), uxl->GetRight()); - NodePtr nxll = node_pool_.Allocate( + Node* nxll = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, nxlll, uxrll->GetLeft()); - NodePtr nxlr = node_pool_.Allocate( + Node* nxlr = node_pool_.Allocate( uxrl->GetKey(), uxrl->GetValue(), 1, uxrll->GetRight(), uxrl->GetRight()); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( uxrll->GetKey(), uxrll->GetValue(), 0, nxll, nxlr); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), ux->GetWeight(), nxl, uxr->GetRight()); @@ -540,9 +518,7 @@ embb_errors_t W3_L( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -563,23 +539,23 @@ embb_errors_t W3_R( HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxlr, UniqueLock& uxlr_lock, HazardNodePtr& uxlrr, UniqueLock& uxlrr_lock) { - NodePtr nxrrr = node_pool_.Allocate( + Node* nxrrr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), uxr->GetWeight() - 1, uxr->GetLeft(), uxr->GetRight()); - NodePtr nxrr = node_pool_.Allocate( + Node* nxrr = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, uxlrr->GetRight(), nxrrr); - NodePtr nxrl = node_pool_.Allocate( + Node* nxrl = node_pool_.Allocate( uxlr->GetKey(), uxlr->GetValue(), 1, uxlr->GetLeft(), uxlrr->GetLeft()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( uxlrr->GetKey(), uxlrr->GetValue(), 0, nxrl, nxrr); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), ux->GetWeight(), uxl->GetLeft(), nxr); @@ -597,9 +573,7 @@ embb_errors_t W3_R( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -620,23 +594,23 @@ embb_errors_t W4_L( HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxrl, UniqueLock& uxrl_lock, HazardNodePtr& uxrlr, UniqueLock& uxrlr_lock) { - NodePtr nxll = node_pool_.Allocate( + Node* nxll = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), uxl->GetWeight() - 1, uxl->GetLeft(), uxl->GetRight()); - NodePtr nxrl = node_pool_.Allocate( + Node* nxrl = node_pool_.Allocate( uxrlr->GetKey(), uxrlr->GetValue(), 1, uxrlr->GetLeft(), uxrlr->GetRight()); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, nxll, uxrl->GetLeft()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), 0, nxrl, uxr->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxrl->GetKey(), uxrl->GetValue(), ux->GetWeight(), nxl, nxr); @@ -654,9 +628,7 @@ embb_errors_t W4_L( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -677,23 +649,23 @@ embb_errors_t W4_R( HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxlr, UniqueLock& uxlr_lock, HazardNodePtr& uxlrl, UniqueLock& uxlrl_lock) { - NodePtr nxrr = node_pool_.Allocate( + Node* nxrr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), uxr->GetWeight() - 1, uxr->GetLeft(), uxr->GetRight()); - NodePtr nxlr = node_pool_.Allocate( + Node* nxlr = node_pool_.Allocate( uxlrl->GetKey(), uxlrl->GetValue(), 1, uxlrl->GetLeft(), uxlrl->GetRight()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, uxlr->GetRight(), nxrr); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), 0, uxl->GetLeft(), nxlr); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxlr->GetKey(), uxlr->GetValue(), ux->GetWeight(), nxl, nxr); @@ -711,9 +683,7 @@ embb_errors_t W4_R( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -733,19 +703,19 @@ embb_errors_t W5_L( HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxrr, UniqueLock& uxrr_lock) { - NodePtr nxll = node_pool_.Allocate( + Node* nxll = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), uxl->GetWeight() - 1, uxl->GetLeft(), uxl->GetRight()); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, nxll, uxr->GetLeft()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( uxrr->GetKey(), uxrr->GetValue(), 1, uxrr->GetLeft(), uxrr->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), ux->GetWeight(), nxl, nxr); @@ -761,9 +731,7 @@ embb_errors_t W5_L( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -782,19 +750,19 @@ embb_errors_t W5_R( HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxll, UniqueLock& uxll_lock) { - NodePtr nxrr = node_pool_.Allocate( + Node* nxrr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), uxr->GetWeight() - 1, uxr->GetLeft(), uxr->GetRight()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, uxl->GetRight(), nxrr); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( uxll->GetKey(), uxll->GetValue(), 1, uxll->GetLeft(), uxll->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), ux->GetWeight(), nxl, nxr); @@ -810,9 +778,7 @@ embb_errors_t W5_R( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -831,19 +797,19 @@ embb_errors_t W6_L( HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxrl, UniqueLock& uxrl_lock) { - NodePtr nxll = node_pool_.Allocate( + Node* nxll = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), uxl->GetWeight() - 1, uxl->GetLeft(), uxl->GetRight()); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, nxll, uxrl->GetLeft()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), 1, uxrl->GetRight(), uxr->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxrl->GetKey(), uxrl->GetValue(), ux->GetWeight(), nxl, nxr); @@ -859,9 +825,7 @@ embb_errors_t W6_L( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -880,19 +844,19 @@ embb_errors_t W6_R( HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock, HazardNodePtr& uxlr, UniqueLock& uxlr_lock) { - NodePtr nxrr = node_pool_.Allocate( + Node* nxrr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), uxr->GetWeight() - 1, uxr->GetLeft(), uxr->GetRight()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), 1, uxlr->GetRight(), nxrr); - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), 1, uxl->GetLeft(), uxlr->GetLeft()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( uxlr->GetKey(), uxlr->GetValue(), ux->GetWeight(), nxl, nxr); @@ -908,9 +872,7 @@ embb_errors_t W6_R( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; @@ -928,15 +890,15 @@ embb_errors_t W7( HazardNodePtr& ux, UniqueLock& ux_lock, HazardNodePtr& uxl, UniqueLock& uxl_lock, HazardNodePtr& uxr, UniqueLock& uxr_lock) { - NodePtr nxl = node_pool_.Allocate( + Node* nxl = node_pool_.Allocate( uxl->GetKey(), uxl->GetValue(), uxl->GetWeight() - 1, uxl->GetLeft(), uxl->GetRight()); - NodePtr nxr = node_pool_.Allocate( + Node* nxr = node_pool_.Allocate( uxr->GetKey(), uxr->GetValue(), uxr->GetWeight() - 1, uxr->GetLeft(), uxr->GetRight()); - NodePtr nx = node_pool_.Allocate( + Node* nx = node_pool_.Allocate( ux->GetKey(), ux->GetValue(), IsSentinel(u) ? 1 : ux->GetWeight() + 1, nxl, nxr); @@ -950,9 +912,7 @@ embb_errors_t W7( return EMBB_NOMEM; } - NodePtr expected = ux; - bool rotation_succeeded = GetPointerToChild(u, ux) - .CompareAndSwap(expected, nx); + bool rotation_succeeded = u->ReplaceChild(ux, nx); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail if (!rotation_succeeded) return EMBB_BUSY; diff --git a/containers_cpp/include/embb/containers/lock_free_chromatic_tree.h b/containers_cpp/include/embb/containers/lock_free_chromatic_tree.h index 1b7fd2f..0ce86ff 100644 --- a/containers_cpp/include/embb/containers/lock_free_chromatic_tree.h +++ b/containers_cpp/include/embb/containers/lock_free_chromatic_tree.h @@ -50,8 +50,8 @@ namespace internal { template class ChromaticTreeNode { public: - typedef ChromaticTreeNode* ChildPointer; - typedef embb::base::Atomic AtomicChildPointer; + typedef ChromaticTreeNode Node; + typedef embb::base::Atomic AtomicNodePtr; /** * Creates a node with given parameters. @@ -62,8 +62,8 @@ class ChromaticTreeNode { * \param[IN] left Pointer to the left child node * \param[IN] right Pointer to the right child node */ - ChromaticTreeNode(const Key& key, const Value& value, const int weight, - const ChildPointer& left, const ChildPointer& right); + ChromaticTreeNode(const Key& key, const Value& value, int weight, + Node* left, Node* right); /** * Creates a node given only a key-value pair. Node will have no child nodes @@ -73,7 +73,7 @@ class ChromaticTreeNode { * \param[IN] value Value of the new node * \param[IN] weight Weight of the new node */ - ChromaticTreeNode(const Key& key, const Value& value, const int weight = 1); + ChromaticTreeNode(const Key& key, const Value& value, int weight = 1); /** * Accessor for the stored key. @@ -101,14 +101,30 @@ class ChromaticTreeNode { * * \return Reference to the left child pointer */ - AtomicChildPointer& GetLeft(); + AtomicNodePtr& GetLeft(); + Node* GetLeft() const; /** * Accessor for the right child pointer. * * \return Reference to the right child pointer */ - AtomicChildPointer& GetRight(); + AtomicNodePtr& GetRight(); + Node* GetRight() const; + + /** + * Tries to replace one of the child pointers that compares equal to + * \c old_child with the \c new_child using an atomic compare-and-swap + * operation. If neither left nor right child pointer is pointing to + * \c old_child, returns \c false. + * + * \param old_child[IN] Pointer to an old child node to compare against + * \param new_child[IN] Pointer to the new child node + * + * \return \c true if one of the child pointers is now pointing to + * \c new_child, \c false otherwise + */ + bool ReplaceChild(Node* old_child, Node* new_child); /** * Marks node for deletion from the tree @@ -136,183 +152,16 @@ class ChromaticTreeNode { ChromaticTreeNode(const ChromaticTreeNode&); ChromaticTreeNode& operator=(const ChromaticTreeNode&); - const Key key_; /**< Stored key */ - const Value value_; /**< Stored value */ - const int weight_; /**< Weight of the node */ - AtomicChildPointer left_; /**< Pointer to left child node */ - AtomicChildPointer right_; /**< Pointer to right child node */ + const Key key_; /**< Stored key */ + const Value value_; /**< Stored value */ + const int weight_; /**< Weight of the node */ + AtomicNodePtr left_; /**< Pointer to left child node */ + AtomicNodePtr right_; /**< Pointer to right child node */ embb::base::Atomic retired_; /**< Retired (marked for deletion) flag */ embb::base::Mutex mutex_; /**< Fine-grained locking tree: per node mutex */ }; -/** - * Ownership wrapper for a hazard pointer - * - * Uses an entry of the hazard table to provide protection for a single - * hazardous pointer. While providing standard pointer dereference and member - * access operators, it requires special care for pointer assignment (realized - * via 'ProtectHazard' method). - * On destruction, it clears the wrapped hazard table entry, releasing the - * protected hazardous pointer (if any). - * - * \tparam GuardedType Type of the object to be protected by the hazard pointer - */ -template -class UniqueHazardPointer { - public: - /** - * Typedef for a pointer to the guarded object. - */ - typedef GuardedType* GuardedPtr; - /** - * Typedef for a atomic pointer to the guarded object. - */ - typedef embb::base::Atomic AtomicGuard; - - /** - * Creates an uninitialized, empty wrapper. - * - * An uninitialized wrapper may only be swapped with another wrapper (using - * \c Swap() method) or checked for being active (using 'IsActive()' method, - * which should always return /c false for an uninitialized wrapper). - */ - UniqueHazardPointer(); - - /** - * Creates a wrapper that uses the given hazard table entry (referred to as - * "guard") to protect hazardous pointers. - * - * \param[IN] hazard_guard Reference to a hazard table entry - * \param[IN] undefined_guard Dummy value used to clear the hazard table entry - */ - explicit - UniqueHazardPointer(AtomicGuard& hazard_guard, - GuardedPtr undefined_guard = NULL); - - /** - * If initialized and active, clears the hazard table entry. - */ - ~UniqueHazardPointer(); - - /** - * Tries to protect the given hazard using the wrapped hazard pointer (guard). - * If it succeeds, the hazard may be safely dereferenced as long as the guard - * is not destroyed or reset to protect another hazard. - * - * \param hazard The hazard to be protected - * \return \c true if the specified hazard is now protected by the guard, - * \c false if the hazard was modified by a concurrent thread - */ - bool ProtectHazard(const AtomicGuard& hazard); - - /** - * Type cast operator. - * - * \return The hazardous pointer protected by this wrapper - */ - operator GuardedPtr () const; - - /** - * Pointer member access operator. - * - * \return The hazardous pointer protected by this wrapper - */ - GuardedPtr operator->() const; - - /** - * Pointer dereference operator. - * - * \return Reference to the object pointed to by the protected pointer - */ - GuardedType& operator*() const; - - /** - * Protects the hazard that is currently protected by another wrapper (so it - * becomes protected by two guards simultaneously). The other wrapper remains - * unmodified. - * - * \param other Another wrapper those protected pointer is to be protected by - * the calling wrapper - */ - void AdoptGuard(const UniqueHazardPointer& other); - - /** - * Swaps the guard ownership with another wrapper. Swaps not just the - * protected hazards, but the hazard guards themselves. - * - * \param other Another wrapper to swap guards with - */ - void Swap(UniqueHazardPointer& other); - - /** - * Clears the hazard guard and returns the hazard previously protected by that - * guard. - * - * \return The hazardous pointer previously protected by this wrapper - */ - GuardedPtr ReleaseHazard(); - - /** - * Check whether the wrapper is active. - * - * \return \c true if the wrapper is initialized and currently protecting some - * hazard, \c false otherwise - */ - bool IsActive() const; - - private: - /** - * Sets the 'active' flag of this wrapper. - * - * \param active The new value for the flag - */ - void SetActive(bool active); - - /** - * Reset the wrapped hazard guard to a state when it is not protecting any - * hazards. - */ - void ClearHazard(); - - /** - * Retrieves the hazardous pointer currently protected by the wrapped guard. - * - * \return The hazardous pointer protected by this wrapper - */ - GuardedPtr LoadGuardedPointer() const; - - /** - * Updates the wrapped guard to protect the specified hazardous pointer. - * - * \param ptr Hazardous pointer to be protected - */ - void StoreGuardedPointer(GuardedPtr ptr); - - /** - * Check whether the wrapper is initialized (i.e. it wraps some hazard guard) - * - * \return \c true if this wrapper is initialized, \c false otherwise - */ - bool OwnsHazardGuard() const; - - /** - * Disable copy construction and assignment. - */ - UniqueHazardPointer(const UniqueHazardPointer&); - UniqueHazardPointer& operator=(const UniqueHazardPointer&); - - /** - * Pointer to a hazard table entry (the guard) that is used to store the - * hazardous pointers - */ - AtomicGuard* hazard_guard_; - /** Dummy value used to clear the hazard guard from any hazards */ - GuardedPtr undefined_guard_; - /** Flag set to true when the guard is protecting some hazardous pointer */ - bool active_; -}; - } // namespace internal namespace test { @@ -330,20 +179,19 @@ class TreeTest; * Implements a balanced BST with support for \c Get, \c Insert and \c Delete * operations. * - * \tparam Key Key type - * \tparam Value Value type - * \tparam Compare Custom comparator type for the keys. An object of the - * type \c Compare must must be a functor taking two - * arguments \c rhs and \c lhs of type \c Key and - * returning \c true if and only if (rhs < lhs) holds - * \tparam NodePool The object pool type used for allocation/deallocation - * of tree nodes. + * \tparam Key Key type + * \tparam Value Value type + * \tparam Compare Custom comparator type for the keys. An object of the + * type \c Compare must must be a functor taking two + * arguments \c rhs and \c lhs of type \c Key and + * returning \c true if and only if (rhs < lhs) holds + * \tparam ValuePool Type of the value pool to be used inside object pools for + * tree nodes and operation objects. */ template, - typename NodePool = ObjectPool, - LockFreeTreeValuePool > + typename ValuePool = LockFreeTreeValuePool > class ChromaticTree { public: @@ -465,7 +313,7 @@ class ChromaticTree { * * \return Object of type \c Value that is used by the tree as a dummy value */ - const Value& GetUndefinedValue(); + const Value& GetUndefinedValue() const; /** * Checks whether the tree is currently empty. @@ -475,26 +323,16 @@ class ChromaticTree { bool IsEmpty() const; private: - /** - * Typedef for a node of the tree. - */ + /** Typedef for a node of the tree. */ typedef internal::ChromaticTreeNode Node; - /** - * Typedef for a pointer to a node of the tree. - */ - typedef internal::ChromaticTreeNode* NodePtr; - /** - * Typedef for an atomic pointer to a node of the tree. - */ - typedef embb::base::Atomic AtomicNodePtr; - /** - * Typedef for an pointer to a node protected by a Hazard Pointer. - */ + /** Typedef for an atomic pointer to a node of the tree. */ + typedef embb::base::Atomic AtomicNodePtr; + /** Typedef for an pointer to a node protected by a Hazard Pointer. */ typedef internal::UniqueHazardPointer HazardNodePtr; - /** - * Typedef for the UniqueLock class. - */ + /** Typedef for the UniqueLock class. */ typedef embb::base::UniqueLock UniqueLock; + /** Typedef for an object pool for tree nodes. */ + typedef ObjectPool NodePool; /** @@ -528,7 +366,7 @@ class ChromaticTree { * * \return \c true if the given node is a leaf, \c false otherwise */ - bool IsLeaf(const NodePtr& node) const; + bool IsLeaf(const Node* node) const; /** * Checks whether the given node is a sentinel node. @@ -537,7 +375,7 @@ class ChromaticTree { * * \return \c true if the given node is a sentinel node, \c false otherwise */ - bool IsSentinel(const NodePtr& node) const; + bool IsSentinel(const Node* node) const; /** * Checks whether the given node has a specified child node. @@ -548,22 +386,8 @@ class ChromaticTree { * \return \c true if \c child is a child node of \c parent, \c false * otherwise */ - bool HasChild(const NodePtr& parent, const NodePtr& child) const; - - /** - * Accessor for the child pointer of a given parent to the specified child. - * - * \pre The \c child has to be an actual child of the \c parent. - * - * \param[IN] parent Parent node - * \param[IN] child Child node of the \c parent - * - * \return Reference to a member pointer of the \c parent that points to - * the \c child - */ - AtomicNodePtr& GetPointerToChild(const NodePtr& parent, - const NodePtr& child) const; - + bool HasChild(const Node* parent, const Node* child) const; + /** * Destroys all the nodes of a subtree rooted at the given node, including the * node itself. @@ -572,7 +396,7 @@ class ChromaticTree { * * \param node Root of the subtree to be destroyed */ - void Destruct(const NodePtr& node); + void Destruct(Node* node); /** * Computes the hight of the subtree rooted at the given node. @@ -584,7 +408,7 @@ class ChromaticTree { * \return The height of a subtree rooted at node \c node. (The height of a * leaf node is defined to be zero). */ - int GetHeight(const NodePtr& node) const; + int GetHeight(const Node* node) const; /** * Check whether the tree is currently in a balanced state (if it is a valid @@ -601,7 +425,7 @@ class ChromaticTree { * * \return \c true if the tree is balanced, \c false otherwise */ - bool IsBalanced(const NodePtr& node) const; + bool IsBalanced(const Node* node) const; /** * Free a tree node using the Hazard Pointers memory reclamation routines. @@ -616,7 +440,7 @@ class ChromaticTree { * * \param[IN] node A node to be freed. */ - void FreeNode(NodePtr node); + void FreeNode(Node* node); /** * Follows the path from the root to some leaf (directed by the given key) and @@ -654,23 +478,21 @@ class ChromaticTree { // directly inside the class definition. # include - /** Callback functor for the hazard pointer that frees retired nodes */ - embb::base::Function free_node_callback_; /** Hazard pointer instance for protection of node pointers */ - embb::containers::internal::HazardPointer node_hazard_manager_; + internal::HazardPointer node_hazard_manager_; const Key undefined_key_; /**< A dummy key used by the tree */ const Value undefined_value_; /**< A dummy value used by the tree */ const Compare compare_; /**< Comparator object for the keys */ size_t capacity_; /**< User-requested capacity of the tree */ NodePool node_pool_; /**< Comparator object for the keys */ - const AtomicNodePtr entry_; /**< Pointer to the sentinel node used as + Node* const entry_; /**< Pointer to the sentinel node used as * the entry point into the tree */ /** * Friending the test class for white-box testing */ - friend class test::TreeTest >; + friend class test::TreeTest; }; } // namespace containers