projects
/
libcds.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Hazard Pointer:
[libcds.git]
/
cds
/
gc
/
details
/
dhp.h
diff --git
a/cds/gc/details/dhp.h
b/cds/gc/details/dhp.h
index 8e117c7a0c3ef5ce16acbc987599318225713ea8..ee689bee79c289dc7bc2601c1968abaeb3730abb 100644
(file)
--- a/
cds/gc/details/dhp.h
+++ b/
cds/gc/details/dhp.h
@@
-15,6
+15,7
@@
# pragma warning(disable:4251) // C4251: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
#endif
# 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
namespace cds { namespace gc {
/// Dynamic Hazard Pointer reclamation schema
@@
-62,17
+63,14
@@
namespace cds { namespace gc {
/// Internal guard representation
struct guard_data {
/// Internal guard representation
struct guard_data {
- typedef retired_ptr_node * handoff_ptr ; ///< trapped value type
- typedef void * guarded_ptr ; ///< type of value guarded
+ typedef void * guarded_ptr; ///< type of value guarded
- atomics::atomic<guarded_ptr> pPost ; ///< pointer guarded
+ atomics::atomic<guarded_ptr> pPost; ///< pointer guarded
+ atomics::atomic<guard_data *> pGlobalNext; ///< next item of global list of allocated guards
+ atomics::atomic<guard_data *> pNextFree; ///< pointer to the next item in global or thread-local free-list
- atomics::atomic<guard_data *> pGlobalNext ; ///< next item of global list of allocated guards
- atomics::atomic<guard_data *> pNextFree ; ///< pointer to the next item in global or thread-local free-list
+ guard_data * pThreadNext; ///< next item of thread's local list of guards
- guard_data * pThreadNext ; ///< next item of thread's local list of guards
-
- //@cond
guard_data() CDS_NOEXCEPT
: pPost( nullptr )
, pGlobalNext( nullptr )
guard_data() CDS_NOEXCEPT
: pPost( nullptr )
, pGlobalNext( nullptr )
@@
-84,7
+82,6
@@
namespace cds { namespace gc {
{
pPost.store( nullptr, atomics::memory_order_relaxed );
}
{
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
/// Checks if the guard is free, that is, it does not contain any pointer guarded
bool isFree() const CDS_NOEXCEPT
@@
-118,7
+115,7
@@
namespace cds { namespace gc {
details::guard_data * pGuard = m_GuardAllocator.New();
// Link guard to the list
details::guard_data * pGuard = m_GuardAllocator.New();
// Link guard to the list
- // m_GuardList is a
ccumulated
list and it cannot support concurrent deletion,
+ // m_GuardList is a
n accumulating
list and it cannot support concurrent deletion,
// so, ABA problem is impossible for it
details::guard_data * pHead = m_GuardList.load( atomics::memory_order_acquire );
do {
// so, ABA problem is impossible for it
details::guard_data * pHead = m_GuardList.load( atomics::memory_order_acquire );
do {
@@
-250,8
+247,7
@@
namespace cds { namespace gc {
atomics::atomic<size_t> m_nItemCount; ///< buffer's item count
public:
atomics::atomic<size_t> m_nItemCount; ///< buffer's item count
public:
- //@cond
- CDS_CONSTEXPR retired_ptr_buffer() CDS_NOEXCEPT
+ retired_ptr_buffer() CDS_NOEXCEPT
: m_pHead( nullptr )
, m_nItemCount(0)
{}
: m_pHead( nullptr )
, m_nItemCount(0)
{}
@@
-260,7
+256,6
@@
namespace cds { namespace gc {
{
assert( m_pHead.load( atomics::memory_order_relaxed ) == nullptr );
}
{
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
/// Pushes new node into the buffer. Returns current buffer size
size_t push( retired_ptr_node& node ) CDS_NOEXCEPT
@@
-331,7
+326,6
@@
namespace cds { namespace gc {
cds::details::Allocator< block, Alloc > m_BlockAllocator ; ///< block allocator
private:
cds::details::Allocator< block, Alloc > m_BlockAllocator ; ///< block allocator
private:
- //@cond
void allocNewBlock()
{
// allocate new block
void allocNewBlock()
{
// allocate new block
@@
-372,10
+366,8
@@
namespace cds { namespace gc {
{
return (m_nCurEpoch.load(atomics::memory_order_acquire) - 1) & (c_nEpochCount - 1);
}
{
return (m_nCurEpoch.load(atomics::memory_order_acquire) - 1) & (c_nEpochCount - 1);
}
- //@endcond
public:
public:
- //@cond
retired_ptr_pool()
: m_pBlockListHead( nullptr )
, m_nCurEpoch(0)
retired_ptr_pool()
: m_pBlockListHead( nullptr )
, m_nCurEpoch(0)
@@
-402,8
+394,6
@@
namespace cds { namespace gc {
m_nCurEpoch.fetch_add( 1, atomics::memory_order_acq_rel );
}
m_nCurEpoch.fetch_add( 1, atomics::memory_order_acq_rel );
}
- //@endcond
-
/// Allocates new retired pointer
retired_ptr_node& alloc()
{
/// Allocates new retired pointer
retired_ptr_node& alloc()
{
@@
-463,36
+453,45
@@
namespace cds { namespace gc {
/// Uninitialized guard
class guard
{
/// Uninitialized guard
class guard
{
- friend class ThreadGC;
+ friend class
dhp::
ThreadGC;
protected:
details::guard_data * m_pGuard ; ///< Pointer to guard data
protected:
details::guard_data * m_pGuard ; ///< Pointer to guard data
+
public:
/// Initialize empty guard.
CDS_CONSTEXPR guard() CDS_NOEXCEPT
: m_pGuard( nullptr )
{}
public:
/// Initialize empty guard.
CDS_CONSTEXPR guard() CDS_NOEXCEPT
: m_pGuard( nullptr )
{}
- ///
The object is not copy-constructible
+ ///
Ñopy-ctor is disabled
guard( guard const& ) = delete;
guard( guard const& ) = delete;
+ /// Move-ctor is disabled
+ guard( guard&& ) = delete;
+
/// Object destructor, does nothing
~guard() CDS_NOEXCEPT
{}
/// Object destructor, does nothing
~guard() CDS_NOEXCEPT
{}
+ /// Get current guarded pointer
+ void * get( atomics::memory_order order = atomics::memory_order_acquire ) const CDS_NOEXCEPT
+ {
+ assert( m_pGuard != nullptr );
+ return m_pGuard->pPost.load( order );
+ }
+
/// Guards pointer \p p
/// Guards pointer \p p
- void set( void * p ) CDS_NOEXCEPT
+ void set( void * p
, atomics::memory_order order = atomics::memory_order_release
) CDS_NOEXCEPT
{
assert( m_pGuard != nullptr );
{
assert( m_pGuard != nullptr );
- m_pGuard->pPost.store( p, atomics::memory_order_release );
- //CDS_COMPILER_RW_BARRIER;
+ m_pGuard->pPost.store( p, order );
}
/// Clears the guard
}
/// Clears the guard
- void clear() CDS_NOEXCEPT
+ void clear(
atomics::memory_order order = atomics::memory_order_relaxed
) CDS_NOEXCEPT
{
assert( m_pGuard != nullptr );
{
assert( m_pGuard != nullptr );
- m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
- CDS_STRICT_DO( CDS_COMPILER_RW_BARRIER );
+ m_pGuard->pPost.store( nullptr, order );
}
/// Guards pointer \p p
}
/// Guards pointer \p p
@@
-503,20
+502,17
@@
namespace cds { namespace gc {
return p;
}
return p;
}
- //@cond
std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
{
clear();
return nullptr;
}
std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
{
clear();
return nullptr;
}
- //@endcond
public: // for ThreadGC.
/*
GCC cannot compile code for template versions of ThreasGC::allocGuard/freeGuard,
the compiler produces error:
\91
cds::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.
public: // for ThreadGC.
/*
GCC cannot compile code for template versions of ThreasGC::allocGuard/freeGuard,
the compiler produces error:
\91
cds::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
*/
/// Set guard data
Therefore, we have to add set_guard/get_guard public functions
*/
/// Set guard data
@@
-536,6
+532,18
@@
namespace cds { namespace gc {
{
return m_pGuard;
}
{
return m_pGuard;
}
+
+ details::guard_data * release_guard() CDS_NOEXCEPT
+ {
+ details::guard_data * p = m_pGuard;
+ m_pGuard = nullptr;
+ return p;
+ }
+
+ bool is_initialized() const
+ {
+ return m_pGuard != nullptr;
+ }
};
} // namespace details
};
} // namespace details
@@
-547,18
+555,16
@@
namespace cds { namespace gc {
*/
class Guard: public details::guard
{
*/
class Guard: public details::guard
{
- //@cond
typedef details::guard base_class;
friend class ThreadGC;
typedef details::guard base_class;
friend class ThreadGC;
- //@endcond
ThreadGC& m_gc ; ///< ThreadGC object of current thread
public:
/// Allocates a guard from \p gc GC. \p gc must be ThreadGC object of current thread
ThreadGC& m_gc ; ///< ThreadGC object of current thread
public:
/// Allocates a guard from \p gc GC. \p gc must be ThreadGC object of current thread
- Guard( ThreadGC& gc )
CDS_NOEXCEPT
;
+ Guard( ThreadGC& gc );
/// Returns guard allocated back to pool of free guards
/// Returns guard allocated back to pool of free guards
- ~Guard()
CDS_NOEXCEPT
; // inline after GarbageCollector
+ ~Guard(); // inline after GarbageCollector
/// Returns DHP GC object
ThreadGC& getGC() CDS_NOEXCEPT
/// Returns DHP GC object
ThreadGC& getGC() CDS_NOEXCEPT
@@
-573,12
+579,10
@@
namespace cds { namespace gc {
return base_class::operator =<T>( p );
}
return base_class::operator =<T>( p );
}
- //@cond
std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
{
return base_class::operator =(nullptr);
}
std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
{
return base_class::operator =(nullptr);
}
- //@endcond
};
/// Array of guards
};
/// Array of guards
@@
-602,7
+606,7
@@
namespace cds { namespace gc {
public:
/// Allocates array of guards from \p gc which must be the ThreadGC object of current thread
public:
/// Allocates array of guards from \p gc which must be the ThreadGC object of current thread
- GuardArray( ThreadGC& gc )
CDS_NOEXCEPT
; // inline below
+ GuardArray( ThreadGC& gc ); // inline below
/// The object is not default-constructible
GuardArray() = delete;
/// The object is not default-constructible
GuardArray() = delete;
@@
-611,7
+615,7
@@
namespace cds { namespace gc {
GuardArray( GuardArray const& ) = delete;
/// Returns guards allocated back to pool
GuardArray( GuardArray const& ) = delete;
/// Returns guards allocated back to pool
- ~GuardArray()
CDS_NOEXCEPT
; // inline below
+ ~GuardArray(); // inline below
/// Returns the capacity of array
CDS_CONSTEXPR size_t capacity() const CDS_NOEXCEPT
/// Returns the capacity of array
CDS_CONSTEXPR size_t capacity() const CDS_NOEXCEPT
@@
-666,7
+670,6
@@
namespace cds { namespace gc {
class CDS_EXPORT_API GarbageCollector
{
private:
class CDS_EXPORT_API GarbageCollector
{
private:
- //@cond
friend class ThreadGC;
/// Internal GC statistics
friend class ThreadGC;
/// Internal GC statistics
@@
-680,7
+683,6
@@
namespace cds { namespace gc {
, m_nFreeGuardCount(0)
{}
};
, m_nFreeGuardCount(0)
{}
};
- //@endcond
public:
/// Exception "No GarbageCollector object is created"
public:
/// Exception "No GarbageCollector object is created"
@@
-692,7
+694,6
@@
namespace cds { namespace gc {
size_t m_nGuardCount ; ///< Total guard count
size_t m_nFreeGuardCount ; ///< Count of free guard
size_t m_nGuardCount ; ///< Total guard count
size_t m_nFreeGuardCount ; ///< Count of free guard
- //@cond
InternalState()
: m_nGuardCount(0)
, m_nFreeGuardCount(0)
InternalState()
: m_nGuardCount(0)
, m_nFreeGuardCount(0)
@@
-705,7
+706,6
@@
namespace cds { namespace gc {
return *this;
}
return *this;
}
- //@endcond
};
private:
};
private:
@@
-844,10
+844,8
@@
namespace cds { namespace gc {
}
private:
}
private:
- //@cond none
GarbageCollector( size_t nLiberateThreshold, size_t nInitialThreadGuardCount );
~GarbageCollector();
GarbageCollector( size_t nLiberateThreshold, size_t nInitialThreadGuardCount );
~GarbageCollector();
- //@endcond
};
/// Thread GC
};
/// Thread GC
@@
-906,27
+904,32
@@
namespace cds { namespace gc {
public:
/// Initializes guard \p g
public:
/// Initializes guard \p g
- void allocGuard(
G
uard& g )
+ void allocGuard(
dhp::details::g
uard& g )
{
assert( m_pList != nullptr );
{
assert( m_pList != nullptr );
- if ( m_pFree ) {
- g.m_pGuard = m_pFree;
- m_pFree = m_pFree->pNextFree.load(atomics::memory_order_relaxed);
- }
- else {
- g.m_pGuard = m_gc.allocGuard();
- g.m_pGuard->pThreadNext = m_pList;
- m_pList = g.m_pGuard;
+ if ( !g.m_pGuard ) {
+ if ( m_pFree ) {
+ g.m_pGuard = m_pFree;
+ m_pFree = m_pFree->pNextFree.load( atomics::memory_order_relaxed );
+ }
+ else {
+ g.m_pGuard = m_gc.allocGuard();
+ g.m_pGuard->pThreadNext = m_pList;
+ m_pList = g.m_pGuard;
+ }
}
}
/// Frees guard \p g
}
}
/// Frees guard \p g
- void freeGuard(
G
uard& g )
+ void freeGuard(
dhp::details::g
uard& g )
{
assert( m_pList != nullptr );
{
assert( m_pList != nullptr );
- g.m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
- g.m_pGuard->pNextFree.store( m_pFree, atomics::memory_order_relaxed );
- m_pFree = g.m_pGuard;
+ if ( g.m_pGuard ) {
+ g.m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
+ g.m_pGuard->pNextFree.store( m_pFree, atomics::memory_order_relaxed );
+ m_pFree = g.m_pGuard;
+ g.m_pGuard = nullptr;
+ }
}
/// Initializes guard array \p arr
}
/// Initializes guard array \p arr
@@
-975,13
+978,10
@@
namespace cds { namespace gc {
m_gc.retirePtr( p, pFunc );
}
m_gc.retirePtr( p, pFunc );
}
- //@cond
void scan()
{
m_gc.scan();
}
void scan()
{
m_gc.scan();
}
- //@endcond
-
};
//////////////////////////////////////////////////////////
};
//////////////////////////////////////////////////////////
@@
-1011,6
+1011,7
@@
namespace cds { namespace gc {
} // namespace dhp
}} // namespace cds::gc
} // namespace dhp
}} // namespace cds::gc
+//@endcond
#if CDS_COMPILER == CDS_COMPILER_MSVC
# pragma warning(pop)
#if CDS_COMPILER == CDS_COMPILER_MSVC
# pragma warning(pop)