for Dynamic-Sized Data Structures. ACM Transactions on Computer Systems, Vol.23, No.2, May 2005
- The cds::gc::ptb namespace and its members are internal representation of the Pass-the-Buck GC and should not be used directly.
+ The cds::gc::dhp namespace and its members are internal representation of the Pass-the-Buck GC and should not be used directly.
Use cds::gc::PTB class in your code.
Pass-the-Buck (PTB) garbage collector is a singleton. The main user-level part of PTB schema is
See cds::gc::PTB class for explanation.
\par Implementation issues
- The global list of free guards (cds::gc::ptb::details::guard_allocator) is protected by spin-lock (i.e. serialized).
+ The global list of free guards (cds::gc::dhp::details::guard_allocator) is protected by spin-lock (i.e. serialized).
It seems that solution should not introduce significant performance bottleneck, because each thread has own set
of guards allocated from global list of free guards and access to global list is occurred only when
all thread's guard is busy. In this case the thread allocates next block of guards from global list.
Guards allocated for the thread is push back to the global list only when the thread terminates.
*/
- namespace ptb {
+ namespace dhp {
// Forward declarations
class Guard;
/**
The list returned is linked by guard's \p pThreadNext and \p pNextFree fields.
- cds::gc::ptb::ThreadGC supporting method
+ cds::gc::dhp::ThreadGC supporting method
*/
guard_data * allocList( size_t nCount )
{
/**
The list \p pList is linked by guard's \p pThreadNext field.
- cds::gc::ptb::ThreadGC supporting method
+ cds::gc::dhp::ThreadGC supporting method
*/
void freeList( guard_data * pList )
{
public: // for ThreadGC.
/*
GCC cannot compile code for template versions of ThreasGC::allocGuard/freeGuard,
- the compiler produces error: \91cds::gc::ptb::details::guard_data* cds::gc::ptb::details::guard::m_pGuard\92 is protected
+ the compiler produces error: \91cds::gc::dhp::details::guard_data* cds::gc::dhp::details::guard::m_pGuard\92 is protected
despite the fact that ThreadGC is declared as friend for guard class.
We should not like to declare m_pGuard member as public one.
Therefore, we have to add set_guard/get_guard public functions
/**
This member function creates and initializes PTB global object.
The function should be called before using CDS data structure based on cds::gc::PTB GC. Usually,
- this member function is called in the \p main() function. See cds::gc::ptb for example.
+ this member function is called in the \p main() function. See cds::gc::dhp for example.
After calling of this function you may use CDS data structures based on cds::gc::PTB.
\par Parameters
/**
The member function destroys PTB global object. After calling of this function you may \b NOT
use CDS data structures based on cds::gc::PTB. Usually, the \p Destruct function is called
- at the end of your \p main(). See cds::gc::ptb for example.
+ at the end of your \p main(). See cds::gc::dhp for example.
*/
static void CDS_STDCALL Destruct();
getGC().freeGuard( *this );
}
- } // namespace ptb
+ } // namespace dhp
}} // namespace cds::gc
#if CDS_COMPILER == CDS_COMPILER_MSVC
template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
/// Thread GC implementation for internal usage
- typedef ptb::ThreadGC thread_gc_impl;
+ typedef dhp::ThreadGC thread_gc_impl;
- /// Wrapper for ptb::ThreadGC class
+ /// Wrapper for dhp::ThreadGC class
/**
@headerfile cds/gc/dhp.h
This class performs automatically attaching/detaching Pass-the-Buck GC
/// Pass-the-Buck guard
/**
@headerfile cds/gc/dhp.h
- This class is a wrapper for ptb::Guard.
+ This class is a wrapper for dhp::Guard.
*/
- class Guard: public ptb::Guard
+ class Guard: public dhp::Guard
{
//@cond
- typedef ptb::Guard base_class;
+ typedef dhp::Guard base_class;
//@endcond
public:
/// Array of Pass-the-Buck guards
/**
@headerfile cds/gc/dhp.h
- This class is a wrapper for ptb::GuardArray template.
+ This class is a wrapper for dhp::GuardArray template.
Template parameter \p Count defines the size of PTB array.
*/
template <size_t Count>
- class GuardArray: public ptb::GuardArray<Count>
+ class GuardArray: public dhp::GuardArray<Count>
{
//@cond
- typedef ptb::GuardArray<Count> base_class;
+ typedef dhp::GuardArray<Count> base_class;
//@endcond
public:
/// Rebind array for other size \p COUNT2
};
public:
- /// Initializes ptb::GarbageCollector singleton
+ /// Initializes dhp::GarbageCollector singleton
/**
The constructor calls GarbageCollector::Construct with passed parameters.
- See ptb::GarbageCollector::Construct for explanation of parameters meaning.
+ See dhp::GarbageCollector::Construct for explanation of parameters meaning.
*/
PTB(
size_t nLiberateThreshold = 1024
, size_t nInitialThreadGuardCount = 8
)
{
- ptb::GarbageCollector::Construct(
+ dhp::GarbageCollector::Construct(
nLiberateThreshold,
nInitialThreadGuardCount
);
}
- /// Terminates ptb::GarbageCollector singleton
+ /// Terminates dhp::GarbageCollector singleton
/**
- The destructor calls \code ptb::GarbageCollector::Destruct() \endcode
+ The destructor calls \code dhp::GarbageCollector::Destruct() \endcode
*/
~PTB()
{
- ptb::GarbageCollector::Destruct();
+ dhp::GarbageCollector::Destruct();
}
/// Checks if count of hazard pointer is no less than \p nCountNeeded
template <typename T>
static void retire( T * p, void (* pFunc)(T *) )
{
- ptb::GarbageCollector::instance().retirePtr( p, pFunc );
+ dhp::GarbageCollector::instance().retirePtr( p, pFunc );
}
/// Retire pointer \p p with functor of type \p Disposer
/// Checks if Pass-the-Buck GC is constructed and may be used
static bool isUsed()
{
- return ptb::GarbageCollector::isUsed();
+ return dhp::GarbageCollector::isUsed();
}
/// Forced GC cycle call for current thread
#include <cds/gc/dhp/dhp.h>
#include <cds/algo/int_algo.h>
-namespace cds { namespace gc { namespace ptb {
+namespace cds { namespace gc { namespace dhp {
namespace details {
GarbageCollector::~GarbageCollector()
{
liberate();
-
-#if 0
- details::retired_ptr_node * pHead = nullptr;
- details::retired_ptr_node * pTail = nullptr;
-
- for ( details::guard_data * pGuard = m_GuardPool.begin(); pGuard; pGuard = pGuard->pGlobalNext.load(atomics::memory_order_relaxed)) {
- details::guard_data::handoff_ptr h = pGuard->pHandOff;
- pGuard->pHandOff = nullptr;
- while ( h ) {
- details::guard_data::handoff_ptr pNext = h->m_pNextFree;
- if ( h->m_ptr.m_p )
- h->m_ptr.free();
- if ( !pHead )
- pTail = pHead = h;
- else
- pTail = pTail->m_pNextFree = h;
- h = pNext;
- }
- }
- if ( pHead )
- m_RetiredAllocator.free_range( pHead, pTail );
-#endif
}
void GarbageCollector::liberate()
}
}
}
-
-#if 0
- void GarbageCollector::liberate( details::liberate_set& set )
- {
- details::guard_data::handoff_ptr const nullHandOff = nullptr;
-
- for ( details::guard_data * pGuard = m_GuardPool.begin(); pGuard; pGuard = pGuard->pGlobalNext.load(atomics::memory_order_acquire) )
- {
- // get guarded pointer
- details::guard_data::guarded_ptr valGuarded = pGuard->pPost.load(atomics::memory_order_acquire);
- details::guard_data::handoff_ptr h;
-
- if ( valGuarded ) {
- details::retired_ptr_node * pRetired = set.erase( valGuarded );
- if ( pRetired ) {
- // Retired pointer is being guarded
-
- // pRetired is the head of retired pointers list for which the m_ptr.m_p field is equal
- // List is linked on m_pNextFree field
-
- // Now, try to set retired node pRetired as a hand-off node for the guard
- cds::lock::Auto<details::guard_data::handoff_spin> al( pGuard->spinHandOff );
- if ( valGuarded == pGuard->pPost.load(atomics::memory_order_acquire) ) {
- if ( pGuard->pHandOff && pGuard->pHandOff->m_ptr.m_p == pRetired->m_ptr.m_p ) {
- h = nullHandOff ; //nullptr;
- details::retired_ptr_node * pTail = pGuard->pHandOff;
- while ( pTail->m_pNextFree )
- pTail = pTail->m_pNextFree;
- pTail->m_pNextFree = pRetired;
- }
- else {
- // swap h and pGuard->pHandOff
- h = pGuard->pHandOff;
- pGuard->pHandOff = pRetired;
- }
- }
- else
- h = pRetired;
- }
- else {
- cds::lock::Auto<details::guard_data::handoff_spin> al( pGuard->spinHandOff );
- h = pGuard->pHandOff;
- if ( h ) {
- if ( h->m_ptr.m_p != valGuarded )
- pGuard->pHandOff = nullHandOff;
- else
- h = nullHandOff;
- }
- }
- }
- else {
- cds::lock::Auto<details::guard_data::handoff_spin> al( pGuard->spinHandOff );
- h = pGuard->pHandOff;
- pGuard->pHandOff = nullHandOff;
- }
-
- // h is the head of a list linked on m_pNextFree field
- if ( h ) {
- set.insert( *h );
- }
- }
- }
-#endif
-}}} // namespace cds::gc::ptb
+}}} // namespace cds::gc::dhp