Commit e518a31d by Danila Klimenko

Code refactoring (const-correctness, internal interfaces)

parent abd38fe8
...@@ -478,7 +478,7 @@ class Atomic<BaseType*> : public embb::base::internal::atomic:: ...@@ -478,7 +478,7 @@ class Atomic<BaseType*> : public embb::base::internal::atomic::
public: public:
Atomic() : embb::base::internal::atomic:: Atomic() : embb::base::internal::atomic::
AtomicPointer<BaseType, ptrdiff_t, sizeof(BaseType*)>() {} AtomicPointer<BaseType, ptrdiff_t, sizeof(BaseType*)>() {}
Atomic(BaseType* p) : embb::base::internal::atomic:: explicit Atomic(BaseType* p) : embb::base::internal::atomic::
AtomicPointer<BaseType, ptrdiff_t, sizeof(BaseType*)>(p) {} AtomicPointer<BaseType, ptrdiff_t, sizeof(BaseType*)>(p) {}
BaseType* operator=(BaseType* p) { BaseType* operator=(BaseType* p) {
......
...@@ -177,8 +177,7 @@ CompareAndSwap(BaseType& expected, BaseType desired) { ...@@ -177,8 +177,7 @@ CompareAndSwap(BaseType& expected, BaseType desired) {
compare_and_swap(&AtomicValue, &native_expected, native_desired)) !=0 compare_and_swap(&AtomicValue, &native_expected, native_desired)) !=0
? true : false; ? true : false;
if (!return_val) memcpy(&expected, &native_expected, sizeof(expected));
expected = Load();
return return_val; return return_val;
} }
......
...@@ -418,6 +418,118 @@ void HazardPointer< GuardType >::EnqueuePointerForDeletion( ...@@ -418,6 +418,118 @@ void HazardPointer< GuardType >::EnqueuePointerForDeletion(
template<typename GuardType> template<typename GuardType>
const double embb::containers::internal::HazardPointer<GuardType>:: const double embb::containers::internal::HazardPointer<GuardType>::
RETIRE_THRESHOLD = 1.25f; RETIRE_THRESHOLD = 1.25f;
template<typename Type>
UniqueHazardPointer<Type>::
UniqueHazardPointer()
: hazard_guard_(NULL), undefined_guard_(NULL), active_(false) {}
template<typename Type>
UniqueHazardPointer<Type>::
UniqueHazardPointer(AtomicTypePtr& hazard_guard, Type* undefined_guard)
: hazard_guard_(&hazard_guard),
undefined_guard_(undefined_guard),
active_(LoadGuardedPointer() == undefined_guard_) {}
template<typename Type>
UniqueHazardPointer<Type>::~UniqueHazardPointer() {
if (IsActive()) ClearHazard();
}
template<typename Type>
bool UniqueHazardPointer<Type>::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<typename Type>
void UniqueHazardPointer<Type>::ProtectSafe(Type* safe_ptr) {
assert(OwnsHazardGuard());
StoreGuardedPointer(safe_ptr);
SetActive(true);
}
template<typename Type>
UniqueHazardPointer<Type>::operator Type* () const {
assert(IsActive());
return LoadGuardedPointer();
}
template<typename Type>
Type* UniqueHazardPointer<Type>::operator->() const {
assert(IsActive());
return LoadGuardedPointer();
}
template<typename Type>
Type& UniqueHazardPointer<Type>::operator*() const {
assert(IsActive());
return *(LoadGuardedPointer());
}
template<typename Type>
void UniqueHazardPointer<Type>::AdoptGuard(const UniqueHazardPointer& other) {
assert(OwnsHazardGuard());
StoreGuardedPointer(other.LoadGuardedPointer());
SetActive(other.active_);
}
template<typename Type>
void UniqueHazardPointer<Type>::Swap(UniqueHazardPointer& other) {
std::swap(hazard_guard_, other.hazard_guard_);
std::swap(undefined_guard_, other.undefined_guard_);
std::swap(active_, other.active_);
}
template<typename Type>
Type* UniqueHazardPointer<Type>::ReleaseHazard() {
assert(IsActive());
Type* released_hazard = LoadGuardedPointer();
ClearHazard();
SetActive(false);
return released_hazard;
}
template<typename Type>
bool UniqueHazardPointer<Type>::IsActive() const {
return active_;
}
template<typename Type>
void UniqueHazardPointer<Type>::SetActive(bool active) {
active_ = active;
}
template<typename Type>
void UniqueHazardPointer<Type>::ClearHazard() {
StoreGuardedPointer(undefined_guard_);
}
template<typename Type>
Type* UniqueHazardPointer<Type>::LoadGuardedPointer() const {
return hazard_guard_->Load();
}
template<typename Type>
void UniqueHazardPointer<Type>::StoreGuardedPointer(Type* ptr) {
hazard_guard_->Store(ptr);
}
template<typename Type>
bool UniqueHazardPointer<Type>::OwnsHazardGuard() const {
return hazard_guard_ != NULL;
}
} // namespace internal } // namespace internal
} // namespace containers } // namespace containers
} // namespace embb } // namespace embb
......
...@@ -529,6 +529,175 @@ class HazardPointer { ...@@ -529,6 +529,175 @@ class HazardPointer {
*/ */
void EnqueuePointerForDeletion(GuardType guardedElement); 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<typename Type>
class UniqueHazardPointer {
public:
/** Typedef for a atomic pointer to the guarded object. */
typedef embb::base::Atomic<Type*> 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 internal
} // namespace containers } // namespace containers
} // namespace embb } // namespace embb
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment