# pragma warning(disable:4251) // C4251: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
#endif
+//@cond
namespace cds { namespace gc {
/// Dynamic Hazard Pointer reclamation schema
guard_data * pThreadNext ; ///< next item of thread's local list of guards
- //@cond
guard_data() CDS_NOEXCEPT
: pPost( nullptr )
, pGlobalNext( nullptr )
{
pPost.store( nullptr, atomics::memory_order_relaxed );
}
- //@endcond
/// Checks if the guard is free, that is, it does not contain any pointer guarded
bool isFree() const CDS_NOEXCEPT
atomics::atomic<size_t> m_nItemCount; ///< buffer's item count
public:
- //@cond
CDS_CONSTEXPR retired_ptr_buffer() CDS_NOEXCEPT
: m_pHead( nullptr )
, m_nItemCount(0)
{
assert( m_pHead.load( atomics::memory_order_relaxed ) == nullptr );
}
- //@endcond
/// Pushes new node into the buffer. Returns current buffer size
size_t push( retired_ptr_node& node ) CDS_NOEXCEPT
cds::details::Allocator< block, Alloc > m_BlockAllocator ; ///< block allocator
private:
- //@cond
void allocNewBlock()
{
// allocate new block
{
return (m_nCurEpoch.load(atomics::memory_order_acquire) - 1) & (c_nEpochCount - 1);
}
- //@endcond
public:
- //@cond
retired_ptr_pool()
: m_pBlockListHead( nullptr )
, m_nCurEpoch(0)
m_nCurEpoch.fetch_add( 1, atomics::memory_order_acq_rel );
}
- //@endcond
-
/// Allocates new retired pointer
retired_ptr_node& alloc()
{
return p;
}
- //@cond
std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
{
clear();
return nullptr;
}
- //@endcond
public: // for ThreadGC.
/*
*/
class Guard: public details::guard
{
- //@cond
typedef details::guard base_class;
friend class ThreadGC;
- //@endcond
ThreadGC& m_gc ; ///< ThreadGC object of current thread
public:
return base_class::operator =<T>( p );
}
- //@cond
std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
{
return base_class::operator =(nullptr);
}
- //@endcond
};
/// Array of guards
class CDS_EXPORT_API GarbageCollector
{
private:
- //@cond
friend class ThreadGC;
/// Internal GC statistics
, m_nFreeGuardCount(0)
{}
};
- //@endcond
public:
/// Exception "No GarbageCollector object is created"
size_t m_nGuardCount ; ///< Total guard count
size_t m_nFreeGuardCount ; ///< Count of free guard
- //@cond
InternalState()
: m_nGuardCount(0)
, m_nFreeGuardCount(0)
return *this;
}
- //@endcond
};
private:
}
private:
- //@cond none
GarbageCollector( size_t nLiberateThreshold, size_t nInitialThreadGuardCount );
~GarbageCollector();
- //@endcond
};
/// Thread GC
m_gc.retirePtr( p, pFunc );
}
- //@cond
void scan()
{
m_gc.scan();
}
- //@endcond
-
};
//////////////////////////////////////////////////////////
} // namespace dhp
}} // namespace cds::gc
+//@endcond
#if CDS_COMPILER == CDS_COMPILER_MSVC
# pragma warning(pop)
2010.01.27 khizmax Introducing memory order constraint
*/
+//@cond
namespace cds {
/**
@page cds_garbage_collectors_comparison GC comparison
atomics::atomic<OS::ThreadId> m_idOwner ; ///< Owner thread id; 0 - the record is free (not owned)
atomics::atomic<bool> m_bFree ; ///< true if record if free (not owned)
- //@cond
hplist_node( const GarbageCollector& HzpMgr )
: hp_record( HzpMgr ),
m_pNextNode( nullptr ),
assert( m_idOwner.load( atomics::memory_order_relaxed ) == OS::c_NullThreadId );
assert( m_bFree.load(atomics::memory_order_relaxed) );
}
- //@endcond
};
atomics::atomic<hplist_node *> m_pListHead ; ///< Head of GC list
*/
void DeletePtr( details::retired_ptr& p );
- //@cond
void detachAllThread();
- //@endcond
public:
/// Creates GarbageCollector singleton
}
}
- //@cond
void scan()
{
m_HzpManager.Scan( m_pHzpRec );
m_HzpManager.HelpScan( m_pHzpRec );
}
- //@endcond
};
/// Auto hp_guard.
*/
class guard
{
- //@cond
details::hp_guard& m_hp ; ///< Hazard pointer guarded
ThreadGC& m_gc ; ///< Thread GC
- //@endcond
public:
typedef details::hp_guard::hazard_ptr hazard_ptr ; ///< Hazard pointer type
+
public:
/// Allocates HP guard from \p gc
guard( ThreadGC& gc )
return m_hp = p;
}
- //@cond
std::nullptr_t operator =(std::nullptr_t)
{
return m_hp = nullptr;
{
return m_hp;
}
- //@endcond
};
/// Auto-managed array of hazard pointers
} // namespace hp
}} // namespace cds::gc
+//@endcond
// Inlines
#include <cds/gc/details/hp_inline.h>
public:
typedef hazard_pointer hazard_ptr; ///< Hazard pointer type
private:
- //@cond
typedef atomics::atomic<hazard_ptr> base_class;
- //@endcond
protected:
- //@cond
template <class Allocator> friend class hp_allocator;
- //@endcond
public:
hp_guard() CDS_NOEXCEPT
return p;
}
- //@cond
std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
{
clear();
return nullptr;
}
- //@endcond
/// Returns current value of hazard pointer
/**
static CDS_CONSTEXPR const size_t c_nCapacity = Count ; ///< Capacity of the array
private:
- //@cond
atomic_hazard_ptr * m_arr ; ///< Hazard pointer array of size = \p Count
template <class Allocator> friend class hp_allocator;
- //@endcond
public:
/// Constructs uninitialized array.
typedef Allocator allocator_type; ///< allocator type
private:
- //@cond
typedef cds::details::Allocator< atomic_hazard_ptr, allocator_type > allocator_impl;
atomic_hazard_ptr * m_arrHazardPtr ; ///< Array of hazard pointers
size_t m_nTop ; ///< The top of stack
const size_t m_nCapacity ; ///< Array capacity
- //@endcond
-
public:
/// Default ctor
explicit hp_allocator(
}
private:
- //@cond
void make_free() CDS_NOEXCEPT
{
for ( size_t i = 0; i < capacity(); ++i )
{
return allocator_impl().NewArray( nCapacity );
}
- //@endcond
};
}}} // namespace gc::hp::details
#ifndef __CDS_GC_DETAILS_HP_INLINE_H
#define __CDS_GC_DETAILS_HP_INLINE_H
+//@cond
namespace cds {
namespace gc{ namespace hp { namespace details {
m_arrRetired( HzpMgr )
{}
- } } } // namespace gc::hp::details
+ }}} // namespace gc::hp::details
} // namespace cds
-
+//@endcond
#endif // #ifndef __CDS_GC_DETAILS_HP_INLINE_H
#include <cds/gc/details/retired_ptr.h> // free_retired_ptr_func
+//@cond
namespace cds {
namespace gc {
namespace hp {
}
}
}
+//@endcond
#endif // #ifndef __CDS_GC_DETAILS_HP_TYPE_H
//$$CDS-header$$
-#ifndef __CDS_GC_DHP_DHP_DECL_H
-#define __CDS_GC_DHP_DHP_DECL_H
+#ifndef __CDS_GC_IMPL_DHP_DECL_H
+#define __CDS_GC_IMPL_DHP_DECL_H
#include <cds/gc/details/dhp.h>
#include <cds/details/marked_ptr.h>
}} // namespace cds::gc
-#endif // #ifndef __CDS_GC_DHP_DHP_DECL_H
+#endif // #ifndef __CDS_GC_IMPL_DHP_DECL_H
//$$CDS-header$$
-#ifndef __CDS_GC_DHP_DHP_IMPL_H
-#define __CDS_GC_DHP_DHP_IMPL_H
+#ifndef __CDS_GC_IMPL_DHP_IMPL_H
+#define __CDS_GC_IMPL_DHP_IMPL_H
#include <cds/threading/model.h>
}} // namespace cds::gc
//@endcond
-#endif // #ifndef __CDS_GC_DHP_DHP_IMPL_H
+#endif // #ifndef __CDS_GC_IMPL_DHP_IMPL_H
//$$CDS-header$$
-#ifndef __CDS_GC_HP_HP_DECL_H
-#define __CDS_GC_HP_HP_DECL_H
+#ifndef __CDS_GC_IMPL_HP_DECL_H
+#define __CDS_GC_IMPL_HP_DECL_H
#include <stdexcept> // overflow_error
#include <cds/gc/details/hp.h>
};
public:
+ /// \p scan() type
+ enum class scan_type {
+ classic = hp::classic, ///< classic scan as described in Michael's papers
+ inplace = hp::inplace ///< inplace scan without allocation
+ };
/// Initializes hp::GarbageCollector singleton
/**
The constructor initializes GC singleton with passed parameters.
size_t nHazardPtrCount = 0, ///< Hazard pointer count per thread
size_t nMaxThreadCount = 0, ///< Max count of simultaneous working thread in your application
size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
- hp::scan_type nScanType = hp::inplace ///< Scan type (see \ref hp::scan_type enum)
+ scan_type nScanType = scan_type::inplace ///< Scan type (see \p scan_type enum)
)
{
hp::GarbageCollector::Construct(
nHazardPtrCount,
nMaxThreadCount,
nMaxRetiredPtrCount,
- nScanType
+ static_cast<hp::scan_type>(nScanType)
);
}
static void retire( T * p ) ; // inline in hp_impl.h
/// Get current scan strategy
- hp::scan_type getScanType() const
+ scan_type getScanType() const
{
- return hp::GarbageCollector::instance().getScanType();
+ return static_cast<scan_type>( hp::GarbageCollector::instance().getScanType());
}
/// Set current scan strategy
void setScanType(
- hp::scan_type nScanType ///< new scan strategy
+ scan_type nScanType ///< new scan strategy
)
{
- hp::GarbageCollector::instance().setScanType( nScanType );
+ hp::GarbageCollector::instance().setScanType( static_cast<hp::scan_type>(nScanType) );
}
/// Checks if Hazard Pointer GC is constructed and may be used
return hp::GarbageCollector::isUsed();
}
-
/// Forced GC cycle call for current thread
/**
Usually, this function should not be called directly.
};
}} // namespace cds::gc
-#endif // #ifndef __CDS_GC_HP_HP_DECL_H
+#endif // #ifndef __CDS_GC_IMPL_HP_DECL_H
//$$CDS-header$$
-#ifndef __CDS_GC_HP_HP_IMPL_H
-#define __CDS_GC_HP_HP_IMPL_H
+#ifndef __CDS_GC_IMPL_HP_IMPL_H
+#define __CDS_GC_IMPL_HP_IMPL_H
#include <cds/threading/model.h>
#include <cds/details/static_functor.h>
}} // namespace cds::gc
//@endcond
-#endif // #ifndef __CDS_GC_HP_HP_IMPL_H
+#endif // #ifndef __CDS_GC_IMPL_HP_IMPL_H